@tradecanvas/chart 0.14.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
1
  import { DARK_THEME as e, DEFAULT_PANEL_HEIGHT as t, LIGHT_THEME as n, LayerType as r, MIN_PANEL_HEIGHT as i, PRICE_AXIS_WIDTH as a, TIME_AXIS_HEIGHT as o, computePriceLimits as s, mergeBar as c, setLocale as l, timeframeToMs as u } from "@tradecanvas/commons";
2
- import { AlertDragHandler as d, AlertManager as f, Animator as p, AreaRenderer as m, AxisDragHandler as ee, BarCountdown as te, BarRenderer as h, BaselineRenderer as ne, CandlestickRenderer as g, ChartLegend as re, ChartStateManager as _, CompareRenderer as ie, CrosshairHandler as ae, CrosshairTooltip as oe, CurrentPriceLine as se, DataExporter as v, DepthHeatmapRenderer as ce, DrawingManager as le, DrawingRenderer as ue, EquivolumeRenderer as de, EventBus as fe, GridRenderer as pe, HLCAreaRenderer as me, HollowCandleRenderer as he, IndicatorEngine as y, InteractionManager as ge, KagiRenderer as _e, KeyboardHandler as ve, LineRenderer as ye, LineWithMarkersRenderer as be, MarketProfileRenderer as xe, MeasureOverlay as Se, PanHandler as Ce, PeriodLevelsRenderer as we, PinnedTooltip as Te, PivotMarkersRenderer as b, PointAndFigureRenderer as x, PriceAxis as S, RenderEngine as C, RenkoRenderer as w, ReplayManager as T, Screenshot as E, SessionBreaks as D, SessionShading as O, SignalMarkerManager as Ee, StepLineRenderer as De, StreamManager as Oe, TimeAxis as ke, TradeZoneManager as Ae, TradingManager as je, TradingRenderer as Me, UndoRedoManager as Ne, Viewport as Pe, VolumeCandleRenderer as Fe, VolumeProfileRenderer as Ie, VolumeRenderer as Le, Watermark as Re, ZoomHandler as ze, findDominantSwing as Be, registerBuiltInDrawingTools as Ve, registerBuiltInIndicators as k, toHeikinAshi as A, toKagi as He, toLineBreak as Ue, toPointAndFigure as We, toRangeBars as Ge, toRenko as Ke, xToBarIndex as qe } from "@tradecanvas/core";
2
+ import { AlertDragHandler as d, AlertManager as f, Animator as p, AreaRenderer as m, AxisDragHandler as ee, BarCountdown as te, BarRenderer as h, BaselineRenderer as ne, CandlestickRenderer as g, ChartLegend as re, ChartStateManager as _, CompareRenderer as ie, CrosshairHandler as ae, CrosshairTooltip as oe, CurrentPriceLine as se, DataExporter as v, DepthHeatmapRenderer as ce, DrawingManager as le, DrawingRenderer as ue, EquivolumeRenderer as de, EventBus as fe, GridRenderer as pe, HLCAreaRenderer as me, HollowCandleRenderer as he, IndicatorEngine as y, InteractionManager as ge, KagiRenderer as _e, KeyboardHandler as ve, LineRenderer as ye, LineWithMarkersRenderer as be, MarketProfileRenderer as xe, MeasureOverlay as Se, PanHandler as Ce, PaneResizeHandler as we, PeriodLevelsRenderer as Te, PinnedTooltip as Ee, PivotMarkersRenderer as De, PointAndFigureRenderer as Oe, PriceAxis as ke, RenderEngine as Ae, RenkoRenderer as b, ReplayManager as x, Screenshot as S, SessionBreaks as C, SessionShading as je, SignalMarkerManager as Me, StepLineRenderer as Ne, StreamManager as Pe, TimeAxis as Fe, TradeZoneManager as Ie, TradingManager as Le, TradingRenderer as Re, UndoRedoManager as ze, Viewport as Be, VolumeCandleRenderer as Ve, VolumeProfileRenderer as He, VolumeRenderer as Ue, Watermark as We, ZoomHandler as Ge, findDominantSwing as Ke, registerBuiltInDrawingTools as qe, registerBuiltInIndicators as w, toHeikinAshi as Je, toKagi as Ye, toLineBreak as Xe, toPointAndFigure as Ze, toRangeBars as Qe, toRenko as T, xToBarIndex as $e } from "@tradecanvas/core";
3
3
  //#region src/charts/ChartTypeStrategy.ts
4
- function Je(e) {
4
+ function et(e) {
5
5
  switch (e) {
6
6
  case "candlestick":
7
7
  case "heikinAshi":
@@ -12,46 +12,55 @@ function Je(e) {
12
12
  case "bar": return new h();
13
13
  case "hollowCandle": return new he();
14
14
  case "baseline": return new ne();
15
- case "renko": return new w();
15
+ case "renko": return new b();
16
16
  case "kagi": return new _e();
17
- case "pointAndFigure": return new x();
18
- case "volumeCandles": return new Fe();
17
+ case "pointAndFigure": return new Oe();
18
+ case "volumeCandles": return new Ve();
19
19
  case "equivolume": return new de();
20
20
  case "hlcArea": return new me();
21
- case "stepLine": return new De();
21
+ case "stepLine": return new Ne();
22
22
  case "lineWithMarkers": return new be();
23
23
  default: return new g();
24
24
  }
25
25
  }
26
- function Ye(e, t) {
26
+ function tt(e, t) {
27
27
  if (t.length === 0) return t;
28
28
  switch (e) {
29
- case "heikinAshi": return A(t);
30
- case "renko": return Ke(t, {
29
+ case "heikinAshi": return Je(t);
30
+ case "renko": return T(t, {
31
31
  brickSize: 0,
32
32
  useATR: !0,
33
33
  atrPeriod: 14
34
34
  });
35
- case "lineBreak": return Ue(t, 3);
36
- case "kagi": return He(t, 4);
37
- case "pointAndFigure": return We(t, j(t) * .01, 3);
38
- case "rangeBars": return Ge(t, { rangeSize: j(t) * .005 });
35
+ case "lineBreak": return Xe(t, 3);
36
+ case "kagi": return Ye(t, 4);
37
+ case "pointAndFigure": return Ze(t, E(t) * .01, 3);
38
+ case "rangeBars": return Qe(t, { rangeSize: E(t) * .005 });
39
39
  default: return t;
40
40
  }
41
41
  }
42
- function j(e) {
42
+ function E(e) {
43
43
  let t = 0;
44
44
  for (let n of e) t += n.close;
45
45
  return t / e.length;
46
46
  }
47
+ function nt(e, t) {
48
+ let n = t?.(e);
49
+ return n ? n.createRenderer() : et(e);
50
+ }
51
+ function rt(e, t, n) {
52
+ if (t.length === 0) return t;
53
+ let r = n?.(e);
54
+ return r?.transform ? r.transform(t) : tt(e, t);
55
+ }
47
56
  //#endregion
48
57
  //#region src/charts/IndicatorPriceRange.ts
49
- var M = {
58
+ var D = {
50
59
  min: 0,
51
60
  max: 100
52
- }, N = .1;
53
- function Xe(e, t, n) {
54
- if (!e) return { ...M };
61
+ }, O = .1;
62
+ function it(e, t, n) {
63
+ if (!e) return { ...D };
55
64
  let r = Infinity, i = -Infinity, a = 0;
56
65
  for (let [, o] of e.values) {
57
66
  if (a >= t && a <= n) for (let e in o) {
@@ -60,16 +69,16 @@ function Xe(e, t, n) {
60
69
  }
61
70
  a++;
62
71
  }
63
- if (r === Infinity) return { ...M };
72
+ if (r === Infinity) return { ...D };
64
73
  let o = i - r || 1;
65
74
  return {
66
- min: r - o * N,
67
- max: i + o * N
75
+ min: r - o * O,
76
+ max: i + o * O
68
77
  };
69
78
  }
70
79
  //#endregion
71
80
  //#region src/state/AutoSaveScheduler.ts
72
- var Ze = class {
81
+ var at = class {
73
82
  timer = null;
74
83
  delayMs = 0;
75
84
  key = null;
@@ -99,12 +108,12 @@ var Ze = class {
99
108
  };
100
109
  //#endregion
101
110
  //#region src/DataManager.ts
102
- function P(e) {
111
+ function k(e) {
103
112
  if (!e || typeof e.time != "number") return !1;
104
113
  let { open: t, high: n, low: r, close: i } = e;
105
114
  return !(!isFinite(t) || !isFinite(n) || !isFinite(r) || !isFinite(i) || t < 0 || n < 0 || r < 0 || i < 0 || n < r || e.volume !== void 0 && (!isFinite(e.volume) || e.volume < 0));
106
115
  }
107
- function F(e) {
116
+ function A(e) {
108
117
  return {
109
118
  ...e,
110
119
  high: Math.max(e.open, e.high, e.low, e.close),
@@ -112,20 +121,20 @@ function F(e) {
112
121
  volume: e.volume === void 0 ? 0 : Math.max(0, e.volume)
113
122
  };
114
123
  }
115
- var I = class {
124
+ var j = class {
116
125
  data = [];
117
126
  getData() {
118
127
  return this.data;
119
128
  }
120
129
  setData(e) {
121
- this.data = e.filter(P).map(F);
130
+ this.data = e.filter(k).map(A);
122
131
  }
123
132
  appendBar(e) {
124
- P(e) && this.data.push(F(e));
133
+ k(e) && this.data.push(A(e));
125
134
  }
126
135
  updateLastBar(e) {
127
- if (!P(e)) return;
128
- let t = F(e);
136
+ if (!k(e)) return;
137
+ let t = A(e);
129
138
  if (this.data.length === 0) {
130
139
  this.data.push(t);
131
140
  return;
@@ -141,7 +150,7 @@ var I = class {
141
150
  clear() {
142
151
  this.data = [];
143
152
  }
144
- }, L = class {
153
+ }, M = class {
145
154
  theme;
146
155
  constructor(t) {
147
156
  !t || t === "dark" ? this.theme = { ...e } : t === "light" ? this.theme = { ...n } : this.theme = { ...t };
@@ -152,7 +161,7 @@ var I = class {
152
161
  setTheme(t) {
153
162
  t === "dark" ? this.theme = { ...e } : t === "light" ? this.theme = { ...n } : this.theme = { ...t };
154
163
  }
155
- }, R = 200, z = 80, B = class {
164
+ }, N = 200, P = 80, F = class {
156
165
  panels = [];
157
166
  containerWidth = 0;
158
167
  containerHeight = 0;
@@ -164,8 +173,8 @@ var I = class {
164
173
  this.panels.push({
165
174
  id: e,
166
175
  position: n,
167
- size: r ?? (a ? R : t),
168
- minSize: a ? z : i,
176
+ size: r ?? (a ? N : t),
177
+ minSize: a ? P : i,
169
178
  content: {
170
179
  type: "indicator",
171
180
  indicatorInstanceId: e
@@ -179,7 +188,7 @@ var I = class {
179
188
  let r = this.panels.find((t) => t.id === e);
180
189
  if (r) {
181
190
  let e = r.position === "left" || r.position === "right", a = n === "left" || n === "right";
182
- r.position = n, e !== a && (r.size = a ? R : t, r.minSize = a ? z : i);
191
+ r.position = n, e !== a && (r.size = a ? N : t, r.minSize = a ? P : i);
183
192
  }
184
193
  }
185
194
  setPanelSize(e, t) {
@@ -280,15 +289,95 @@ var I = class {
280
289
  getMainChartRect() {
281
290
  return this.resolve().mainChartRect;
282
291
  }
283
- }, V = class {
284
- constructor(e) {
285
- this.indicatorEngine = e;
292
+ }, ot = 1;
293
+ function I(e, t) {
294
+ return e.filter((e) => (e.descriptor.layer ?? "overlay") === t);
295
+ }
296
+ function L(e) {
297
+ switch (e.kind) {
298
+ case "indicator": return `indicator:${e.plugin.descriptor.id}`;
299
+ case "drawing": return `drawing:${e.plugin.descriptor.type}`;
300
+ case "chartType": return `chartType:${e.plugin.descriptor.type}`;
301
+ case "overlay": return `overlay:${e.plugin.descriptor.id}`;
302
+ }
303
+ }
304
+ //#endregion
305
+ //#region src/plugins/registry.ts
306
+ var R = /* @__PURE__ */ new Map();
307
+ function st(e) {
308
+ R.set(L(e), e);
309
+ }
310
+ function ct(e) {
311
+ return R.delete(e);
312
+ }
313
+ function z() {
314
+ return [...R.values()];
315
+ }
316
+ function lt() {
317
+ R.clear();
318
+ }
319
+ //#endregion
320
+ //#region src/plugins/PluginManager.ts
321
+ var B = class {
322
+ plugins = /* @__PURE__ */ new Map();
323
+ constructor(e, t = {}) {
324
+ if (this.indicatorEngine = e, t.inheritGlobal !== !1) for (let e of z()) this.add(e);
325
+ for (let e of t.plugins ?? []) this.add(e);
326
+ }
327
+ register(e) {
328
+ this.add(e);
329
+ }
330
+ unregister(e) {
331
+ return this.plugins.delete(e);
332
+ }
333
+ list() {
334
+ return [...this.plugins.values()];
286
335
  }
287
336
  registerIndicator(e) {
288
- this.indicatorEngine.register(e);
337
+ this.add({
338
+ kind: "indicator",
339
+ plugin: e
340
+ });
341
+ }
342
+ getChartType(e) {
343
+ let t = this.plugins.get(`chartType:${e}`);
344
+ return t?.kind === "chartType" ? t.plugin : void 0;
345
+ }
346
+ getOverlays() {
347
+ let e = [];
348
+ for (let t of this.plugins.values()) t.kind === "overlay" && e.push(t.plugin);
349
+ return e;
350
+ }
351
+ add(e) {
352
+ this.plugins.set(L(e), e), e.kind === "indicator" && this.indicatorEngine.register(e.plugin);
353
+ }
354
+ }, V = {
355
+ orderPlace: (e, t) => e.placeOrder(t),
356
+ orderModify: (e, t) => e.modifyOrder(t),
357
+ orderCancel: (e, t) => e.cancelOrder(t),
358
+ positionModify: (e, t) => e.modifyPosition(t),
359
+ positionClose: (e, t) => e.closePosition(t)
360
+ };
361
+ function ut(e, t) {
362
+ let n = [], r = (e) => t.setOrders(e.data ?? []), i = (e) => t.setPositions(e.data ?? []), a = (e) => t.onError(e.data ?? { message: "Execution error" });
363
+ e.on("orders", r), e.on("positions", i), e.on("error", a), n.push(() => e.off("orders", r), () => e.off("positions", i), () => e.off("error", a));
364
+ for (let r of Object.keys(V)) {
365
+ let i = V[r], a = t.onIntent(r, (n) => {
366
+ Promise.resolve(i(e, n)).catch((e) => t.onError({
367
+ message: `Execution command failed: ${r}`,
368
+ cause: e
369
+ }));
370
+ });
371
+ n.push(a);
289
372
  }
290
- }, Qe = class {
291
- static version = "0.7.0";
373
+ return () => {
374
+ for (let e of n) e();
375
+ };
376
+ }
377
+ //#endregion
378
+ //#region src/Chart.ts
379
+ var dt = class {
380
+ static version = "1.0.1";
292
381
  engine;
293
382
  viewport;
294
383
  dataManager;
@@ -302,6 +391,8 @@ var I = class {
302
391
  tradingRenderer;
303
392
  eventBus;
304
393
  streamManager = null;
394
+ executionAdapter = null;
395
+ execTeardown = null;
305
396
  autoScrollOnNewBar = !0;
306
397
  displayDataCache = null;
307
398
  resolvedLayoutCache = null;
@@ -309,6 +400,9 @@ var I = class {
309
400
  renderScheduled = !1;
310
401
  containerSizeCache = null;
311
402
  containerSizeCacheTime = 0;
403
+ lastEmittedRange = null;
404
+ lastEmittedPriceRange = null;
405
+ lastEmittedBarWidth = null;
312
406
  chartLegend;
313
407
  watermark;
314
408
  barCountdown;
@@ -328,7 +422,7 @@ var I = class {
328
422
  measureOverlay;
329
423
  replayManager;
330
424
  undoRedoManager;
331
- autoSaveScheduler = new Ze((e) => this.saveState(e));
425
+ autoSaveScheduler = new at((e) => this.saveState(e));
332
426
  animator;
333
427
  crosshairTooltip;
334
428
  pinnedTooltip;
@@ -380,22 +474,22 @@ var I = class {
380
474
  logScale: n.logScale ?? !0,
381
475
  timeframes: n.timeframes ?? [],
382
476
  defaultTimeframeFavorites: n.defaultTimeframeFavorites ?? []
383
- }, e.style.position = "relative", e.style.overflow = "hidden", e.tabIndex = 0, e.style.outline = "none", this.dataManager = new I(), this.themeManager = new L(t.theme), this.layoutManager = new B(), this.indicatorEngine = new y(), this.pluginManager = new V(this.indicatorEngine), this.eventBus = new fe(), k(this.indicatorEngine), this.drawingManager = new le(), Ve(this.drawingManager), this.drawingRenderer = new ue(this.drawingManager), this.drawingManager.setRequestRender(() => {
477
+ }, e.style.position = "relative", e.style.overflow = "hidden", e.tabIndex = 0, e.style.outline = "none", this.dataManager = new j(), this.themeManager = new M(t.theme), this.layoutManager = new F(), this.indicatorEngine = new y(), this.pluginManager = new B(this.indicatorEngine, { plugins: t.plugins }), this.eventBus = new fe(), w(this.indicatorEngine), this.drawingManager = new le(), qe(this.drawingManager), this.drawingRenderer = new ue(this.drawingManager), this.drawingManager.setRequestRender(() => {
384
478
  this.syncRenderContext(), this.engine.requestRender(r.Overlay), this.scheduleAutoSave();
385
479
  }), this.drawingManager.setEventCallback((e, t) => {
386
480
  this.eventBus.emit(e, t);
387
- }), this.undoRedoManager = new Ne(), this.drawingManager.setUndoRedoManager(this.undoRedoManager), this.drawingManager.setDataGetter(() => this.dataManager.getData()), this.drawingManager.setDisplayDataGetter(() => this.getDisplayData()), t.crosshair?.mode === "magnet" && this.drawingManager.setMagnetMode("magnet"), this.tradingManager = new je({
481
+ }), this.undoRedoManager = new ze(), this.drawingManager.setUndoRedoManager(this.undoRedoManager), this.drawingManager.setDataGetter(() => this.dataManager.getData()), this.drawingManager.setDisplayDataGetter(() => this.getDisplayData()), t.crosshair?.mode === "magnet" && this.drawingManager.setMagnetMode("magnet"), this.tradingManager = new Le({
388
482
  enabled: this.features.trading,
389
483
  contextMenu: { enabled: this.features.tradingContextMenu }
390
- }), this.tradingRenderer = new Me(this.tradingManager), this.tradingManager.setContainer(e), this.tradingManager.setRequestRender(() => this.engine.requestRender(r.Overlay)), this.tradingManager.setEventCallback((e, t) => {
484
+ }), this.tradingRenderer = new Re(this.tradingManager), this.tradingManager.setContainer(e), this.tradingManager.setRequestRender(() => this.engine.requestRender(r.Overlay)), this.tradingManager.setEventCallback((e, t) => {
391
485
  this.eventBus.emit(e, t);
392
- }), this.engine = new C(e);
486
+ }), this.engine = new Ae(e);
393
487
  let i = this.engine.dprManager.getContainerSize();
394
- if (this.viewport = new Pe(i.width, i.height, t.minBarSpacing ?? 2, t.maxBarSpacing ?? 30, t.rightMargin ?? 5), this.layoutManager.resize(i.width, i.height), this.engine.onContainerResize = (e) => {
488
+ if (this.viewport = new Be(i.width, i.height, t.minBarSpacing ?? 2, t.maxBarSpacing ?? 30, t.rightMargin ?? 5), this.layoutManager.resize(i.width, i.height), this.engine.onContainerResize = (e) => {
395
489
  if (e.width <= 0 || e.height <= 0) return;
396
490
  let t = this.viewport.isAtEnd();
397
491
  this.viewport.resize(e.width, e.height), this.layoutManager.resize(e.width, e.height), this.updateViewportAndRender(t);
398
- }, this.chartRenderer = this.createChartRenderer(t.chartType), this.gridRenderer = new pe(), t.grid?.visible === !1 && this.gridRenderer.setVisible(!1), this.priceAxis = new S(), this.priceAxis.setLocale(this.numberLocale), this.timeAxis = new ke(), this.crosshairHandler = new ae(), this.crosshairHandler.setLocale(this.numberLocale), t.crosshair?.mode && this.crosshairHandler.setMode(t.crosshair.mode), this.crosshairHandler.setCallback((e, t) => {
492
+ }, this.chartRenderer = this.createChartRenderer(t.chartType), this.gridRenderer = new pe(), t.grid?.visible === !1 && this.gridRenderer.setVisible(!1), this.priceAxis = new ke(), this.priceAxis.setLocale(this.numberLocale), this.timeAxis = new Fe(), this.crosshairHandler = new ae(), this.crosshairHandler.setLocale(this.numberLocale), t.crosshair?.mode && this.crosshairHandler.setMode(t.crosshair.mode), this.crosshairHandler.setCallback((e, t) => {
399
493
  if (e !== null && t) {
400
494
  let n = this.dataManager.getData(), r = e < n.length ? n[e] : void 0;
401
495
  this.chartLegend.setHoverBar(r ?? null), r && this.crosshairTooltip.show(t, r, this.themeManager.getTheme(), this.cachedContainerSize()), this.pinnedTooltip.isPinned() && this.pinnedTooltip.reposition(this.viewport.getState(), r ?? null, e, this.themeManager.getTheme()), this.eventBus.emit("crosshairMove", {
@@ -404,12 +498,12 @@ var I = class {
404
498
  barIndex: e
405
499
  });
406
500
  } else this.crosshairTooltip.hide(), this.chartLegend.setHoverBar(null);
407
- }), this.chartLegend = new re(), this.chartLegend.setChartType(t.chartType), this.watermark = new Re(), t.watermark && this.watermark.setConfig(t.watermark), this.volumeRenderer = new Le(), this.volumeProfile = new Ie(), this.marketProfile = new xe(), this.depthHeatmap = new ce(), this.periodLevels = new we(), this.pivotMarkers = new b(), this.barCountdown = new te(), this.sessionBreaks = new D(), this.sessionShading = new O(), this.compareRenderer = new ie(), t.sessionBreaks ? this.sessionBreaks.setConfig({
501
+ }), this.chartLegend = new re(), this.chartLegend.setChartType(t.chartType), this.watermark = new We(), t.watermark && this.watermark.setConfig(t.watermark), this.volumeRenderer = new Ue(), this.volumeProfile = new He(), this.marketProfile = new xe(), this.depthHeatmap = new ce(), this.periodLevels = new Te(), this.pivotMarkers = new De(), this.barCountdown = new te(), this.sessionBreaks = new C(), this.sessionShading = new je(), this.compareRenderer = new ie(), t.sessionBreaks ? this.sessionBreaks.setConfig({
408
502
  visible: t.sessionBreaks.visible ?? !0,
409
503
  color: t.sessionBreaks.color,
410
504
  lineStyle: t.sessionBreaks.lineStyle,
411
505
  lineWidth: t.sessionBreaks.lineWidth
412
- }) : t.features?.sessionBreaks !== !1 && this.sessionBreaks.setVisible(!0), t.logScale && this.viewport.setLogScale(!0), this.animator = new p(), this.crosshairTooltip = new oe(), this.crosshairTooltip.create(e), this.pinnedTooltip = new Te(), this.pinnedTooltip.create(e), this.keyboardHandler = new ve({
506
+ }) : t.features?.sessionBreaks !== !1 && this.sessionBreaks.setVisible(!0), t.logScale && this.viewport.setLogScale(!0), this.animator = new p(), this.crosshairTooltip = new oe(), this.crosshairTooltip.create(e), this.pinnedTooltip = new Ee(), this.pinnedTooltip.create(e), this.keyboardHandler = new ve({
413
507
  scrollBars: (e) => {
414
508
  let t = this.viewport.getState().barWidth + this.viewport.getState().barSpacing;
415
509
  this.viewport.scrollBy(e * t), this.updateViewportAndRender();
@@ -461,7 +555,7 @@ var I = class {
461
555
  message: e.message,
462
556
  triggered: e.triggered
463
557
  });
464
- }), this.signalMarkerManager = new Ee(), this.signalMarkerManager.setRequestRender(() => this.engine.requestRender(r.Overlay)), this.signalMarkerManager.setDataGetter(() => this.dataManager.getData()), this.signalMarkerManager.on("added", (e) => {
558
+ }), this.signalMarkerManager = new Me(), this.signalMarkerManager.setRequestRender(() => this.engine.requestRender(r.Overlay)), this.signalMarkerManager.setDataGetter(() => this.dataManager.getData()), this.signalMarkerManager.on("added", (e) => {
465
559
  this.eventBus.emit("signalMarkerAdd", {
466
560
  id: e.id,
467
561
  source: e.source,
@@ -469,21 +563,21 @@ var I = class {
469
563
  });
470
564
  }), this.signalMarkerManager.on("removed", (e) => {
471
565
  this.eventBus.emit("signalMarkerRemove", { id: e });
472
- }), this.tradeZoneManager = new Ae(), this.tradeZoneManager.setRequestRender(() => this.engine.requestRender(r.Overlay)), this.tradeZoneManager.setDataGetter(() => this.dataManager.getData()), this.tradeZoneManager.on("added", (e) => {
566
+ }), this.tradeZoneManager = new Ie(), this.tradeZoneManager.setRequestRender(() => this.engine.requestRender(r.Overlay)), this.tradeZoneManager.setDataGetter(() => this.dataManager.getData()), this.tradeZoneManager.on("added", (e) => {
473
567
  this.eventBus.emit("tradeZoneAdd", {
474
568
  id: e.id,
475
569
  direction: e.direction
476
570
  });
477
571
  }), this.tradeZoneManager.on("removed", (e) => {
478
572
  this.eventBus.emit("tradeZoneRemove", { id: e });
479
- }), this.replayManager = new T(), this.measureOverlay = new Se(), this.interactionManager = new ge(e), this.features.panning && this.interactionManager.setPanHandler(new Ce((e) => {
573
+ }), this.replayManager = new x(), this.measureOverlay = new Se(), this.interactionManager = new ge(e), this.features.panning && this.interactionManager.setPanHandler(new Ce((e) => {
480
574
  this.viewport.scrollBy(e), this.updateViewportAndRender();
481
575
  })), this.features.zooming) {
482
- this.interactionManager.setZoomHandler(new ze((e, t) => {
576
+ this.interactionManager.setZoomHandler(new Ge((e, t) => {
483
577
  this.viewport.zoom(e, t), this.updateViewportAndRender();
484
578
  }));
485
579
  let e = new ee((e) => {
486
- this.options.autoScale = !1, this.viewport.scalePriceRange(e), this.syncRenderContext(), this.engine.requestRender();
580
+ this.options.autoScale = !1, this.viewport.scalePriceRange(e), this.syncRenderContext(), this.engine.requestRender(), this.emitViewportEvents();
487
581
  }, (e) => {
488
582
  let t = this.viewport.getState().chartRect.width;
489
583
  this.viewport.zoom(1 / e - 1, t / 2), this.updateViewportAndRender();
@@ -502,7 +596,8 @@ var I = class {
502
596
  let e = new d(this.alertManager, () => this.viewport.getState());
503
597
  this.interactionManager.setAlertDragHandler(e);
504
598
  }
505
- this.interactionManager.setAltClickHandler((e) => {
599
+ let a = new we();
600
+ a.configure(() => this.getResolvedLayout(), (e, t) => this.setPanelSize(e, t)), this.interactionManager.setPaneResizeHandler(a), this.interactionManager.setAltClickHandler((e) => {
506
601
  let t = this.getDisplayData();
507
602
  if (t.length === 0) return;
508
603
  let n = this.viewport.getState(), i = n.barWidth + n.barSpacing, a = Math.round((n.offset + e.x) / i);
@@ -513,7 +608,7 @@ var I = class {
513
608
  x: e.x,
514
609
  y: e.y
515
610
  }), t.length === 0) return;
516
- let n = qe(e.x, this.viewport.getState());
611
+ let n = $e(e.x, this.viewport.getState());
517
612
  n < 0 || n >= t.length || this.eventBus.emit("barClick", {
518
613
  bar: t[n],
519
614
  barIndex: n,
@@ -581,15 +676,18 @@ var I = class {
581
676
  registerIndicator(e) {
582
677
  this.pluginManager.registerIndicator(e);
583
678
  }
679
+ get plugins() {
680
+ return this.pluginManager;
681
+ }
584
682
  static indicators() {
585
683
  let e = new y();
586
- return k(e), e.getAvailableIndicators();
684
+ return w(e), e.getAvailableIndicators();
587
685
  }
588
686
  setPanelPosition(e, t) {
589
687
  this.layoutManager.setPanelPosition(e, t), this.engine.requestRender();
590
688
  }
591
689
  setPanelSize(e, t) {
592
- this.layoutManager.setPanelSize(e, t), this.engine.requestRender();
690
+ this.layoutManager.setPanelSize(e, t), this.updateViewportAndRender();
593
691
  }
594
692
  setDrawingTool(e) {
595
693
  this.features.drawings && (e && this.features.drawingTools.length > 0 && !this.features.drawingTools.includes(e) || this.drawingManager.setActiveTool(e));
@@ -622,7 +720,7 @@ var I = class {
622
720
  }
623
721
  autoFib() {
624
722
  if (!this.features.drawings) return null;
625
- let e = this.getDisplayData(), t = this.viewport.getState(), n = Be(e, t.visibleRange.from, t.visibleRange.to);
723
+ let e = this.getDisplayData(), t = this.viewport.getState(), n = Ke(e, t.visibleRange.from, t.visibleRange.to);
626
724
  return n ? this.addDrawing({
627
725
  type: "fibRetracement",
628
726
  anchors: [n[0], n[1]]
@@ -746,6 +844,20 @@ var I = class {
746
844
  isBracketActive() {
747
845
  return this.features.trading && this.tradingManager.isBracketActive();
748
846
  }
847
+ startOrderDraft(e, t) {
848
+ if (!this.features.trading) return !1;
849
+ let n = this.dataManager.getData(), r = t ?? (n.length > 0 ? n[n.length - 1].close : null);
850
+ return r === null ? !1 : (this.tradingManager.startOrderDraft(e, r), !0);
851
+ }
852
+ cancelOrderDraft() {
853
+ this.features.trading && this.tradingManager.cancelOrderDraft();
854
+ }
855
+ confirmOrderDraft() {
856
+ return this.features.trading ? this.tradingManager.confirmOrderDraft() : !1;
857
+ }
858
+ isOrderDraftActive() {
859
+ return this.features.trading && this.tradingManager.isOrderDraftActive();
860
+ }
749
861
  placeOrderIntent(e) {
750
862
  this.features.trading && this.eventBus.emit("orderPlace", e);
751
863
  }
@@ -775,7 +887,7 @@ var I = class {
775
887
  this.features.trading && this.tradingManager.setConfig(e);
776
888
  }
777
889
  async connect(e) {
778
- this.disconnectStream(), this.streamManager = new Oe(), this.streamManager.on("snapshot", (e) => {
890
+ this.disconnectStream(), this.streamManager = new Pe(), this.streamManager.on("snapshot", (e) => {
779
891
  this.setData(e);
780
892
  }), this.streamManager.on("barClose", (e) => {
781
893
  this.dataManager.appendBar(e), this.crosshairHandler.setData(this.dataManager.getData()), this.autoScrollOnNewBar && this.viewport.scrollToEnd(), this.indicatorEngine.recalculateAll(this.dataManager.getData()), this.updateViewportAndRender();
@@ -803,6 +915,27 @@ var I = class {
803
915
  disconnectStream() {
804
916
  this.streamManager &&= (this.streamManager.dispose(), null);
805
917
  }
918
+ connectExecution(e, t = {}) {
919
+ if (!this.features.trading) throw Error("connectExecution requires features.trading to be enabled");
920
+ this.disconnectExecution(), this.executionAdapter = e, this.execTeardown = ut(e, {
921
+ onIntent: (e, t) => {
922
+ let n = (e) => t(e.payload);
923
+ return this.eventBus.on(e, n), () => this.eventBus.off(e, n);
924
+ },
925
+ setOrders: (e) => this.setOrders(e),
926
+ setPositions: (e) => this.setPositions(e),
927
+ onError: (e) => this.eventBus.emit("executionError", e)
928
+ }), Promise.resolve(e.connect(t)).catch((e) => this.eventBus.emit("executionError", {
929
+ message: "Execution connect failed",
930
+ cause: e
931
+ }));
932
+ }
933
+ disconnectExecution() {
934
+ this.execTeardown &&= (this.execTeardown(), null), this.executionAdapter &&= (this.executionAdapter.disconnect(), null);
935
+ }
936
+ getExecutionAdapter() {
937
+ return this.executionAdapter;
938
+ }
806
939
  setBarCountdownVisible(e) {
807
940
  this.barCountdown.setVisible(e), this.engine.requestRender(r.UI);
808
941
  }
@@ -1028,22 +1161,22 @@ var I = class {
1028
1161
  this.chartLegend.setStatusText(e), this.engine.requestRender(r.UI);
1029
1162
  }
1030
1163
  screenshot(e) {
1031
- this.features.screenshot && E.download(this.container, e, this.themeManager.getTheme().background);
1164
+ this.features.screenshot && S.download(this.container, e, this.themeManager.getTheme().background);
1032
1165
  }
1033
1166
  async copyScreenshot() {
1034
1167
  if (!this.features.screenshot) return !1;
1035
1168
  try {
1036
- let e = await E.toBlob(this.container, this.themeManager.getTheme().background), t = globalThis.ClipboardItem;
1169
+ let e = await S.toBlob(this.container, this.themeManager.getTheme().background), t = globalThis.ClipboardItem;
1037
1170
  return !e || !navigator.clipboard?.write || !t ? !1 : (await navigator.clipboard.write([new t({ "image/png": e })]), !0);
1038
1171
  } catch {
1039
1172
  return !1;
1040
1173
  }
1041
1174
  }
1042
1175
  screenshotDataURL() {
1043
- return this.features.screenshot ? E.toDataURL(this.container, this.themeManager.getTheme().background) : null;
1176
+ return this.features.screenshot ? S.toDataURL(this.container, this.themeManager.getTheme().background) : null;
1044
1177
  }
1045
1178
  async screenshotBlob() {
1046
- return this.features.screenshot ? E.toBlob(this.container, this.themeManager.getTheme().background) : null;
1179
+ return this.features.screenshot ? S.toBlob(this.container, this.themeManager.getTheme().background) : null;
1047
1180
  }
1048
1181
  addAlert(e, t = "crossing", n, r = "price", i) {
1049
1182
  if (!this.features.alerts) return null;
@@ -1104,7 +1237,7 @@ var I = class {
1104
1237
  setTradeZoneStyle(e) {
1105
1238
  this.tradeZoneManager.setStyle(e);
1106
1239
  }
1107
- replay(e) {
1240
+ replayStart(e) {
1108
1241
  if (!this.features.replay) return;
1109
1242
  let t = this.dataManager.getData();
1110
1243
  this.replayManager.load(t), this.replayManager.on("bar", ({ bar: e, index: n }) => {
@@ -1218,16 +1351,16 @@ var I = class {
1218
1351
  this.viewport.resize(e.width, e.height), this.layoutManager.resize(e.width, e.height), this.updateViewportAndRender(n), this.eventBus.emit("resize", e);
1219
1352
  }
1220
1353
  destroy() {
1221
- this.countdownInterval && clearInterval(this.countdownInterval), this.disableAutoSave(), this.disconnectStream(), this.onWindowKeyDown &&= (window.removeEventListener("keydown", this.onWindowKeyDown), null), this.keyboardHandler = null, this.interactionManager.detach(), this.tradingManager.destroy(), this.animator.dispose(), this.crosshairTooltip.destroy(), this.pinnedTooltip.destroy(), this.replayManager.dispose(), this.undoRedoManager.clear(), this.engine.destroy(), this.eventBus.destroy(), this.container.innerHTML = "";
1354
+ this.countdownInterval && clearInterval(this.countdownInterval), this.disableAutoSave(), this.disconnectStream(), this.disconnectExecution(), this.onWindowKeyDown &&= (window.removeEventListener("keydown", this.onWindowKeyDown), null), this.keyboardHandler = null, this.interactionManager.detach(), this.tradingManager.destroy(), this.animator.dispose(), this.crosshairTooltip.destroy(), this.pinnedTooltip.destroy(), this.replayManager.dispose(), this.undoRedoManager.clear(), this.engine.destroy(), this.eventBus.destroy(), this.container.innerHTML = "";
1222
1355
  }
1223
1356
  createChartRenderer(e) {
1224
- return Je(e);
1357
+ return nt(e, (e) => this.pluginManager.getChartType(e));
1225
1358
  }
1226
1359
  getDisplayData() {
1227
1360
  if (this.displayDataCache) return this.displayDataCache;
1228
1361
  let e = this.dataManager.getData();
1229
1362
  if (e.length === 0) return e;
1230
- let t = Ye(this.options.chartType, e);
1363
+ let t = rt(this.options.chartType, e, (e) => this.pluginManager.getChartType(e));
1231
1364
  return this.displayDataCache = t, t;
1232
1365
  }
1233
1366
  scheduleRender() {
@@ -1256,7 +1389,25 @@ var I = class {
1256
1389
  }
1257
1390
  }
1258
1391
  }
1259
- e && this.viewport.scrollToEnd(), this.syncRenderContext(), this.engine.requestRender();
1392
+ e && this.viewport.scrollToEnd(), this.syncRenderContext(), this.engine.requestRender(), this.emitViewportEvents();
1393
+ }
1394
+ emitViewportEvents() {
1395
+ let e = this.viewport.getState(), t = Math.max(0, Math.floor(e.visibleRange.from)), n = Math.max(t, Math.ceil(e.visibleRange.to));
1396
+ (!this.lastEmittedRange || this.lastEmittedRange.from !== t || this.lastEmittedRange.to !== n) && (this.lastEmittedRange = {
1397
+ from: t,
1398
+ to: n
1399
+ }, this.eventBus.emit("visibleRangeChange", {
1400
+ from: t,
1401
+ to: n
1402
+ }));
1403
+ let { min: r, max: i } = e.priceRange;
1404
+ (!this.lastEmittedPriceRange || this.lastEmittedPriceRange.min !== r || this.lastEmittedPriceRange.max !== i) && (this.lastEmittedPriceRange = {
1405
+ min: r,
1406
+ max: i
1407
+ }, this.eventBus.emit("priceRangeChange", {
1408
+ min: r,
1409
+ max: i
1410
+ })), this.lastEmittedBarWidth !== e.barWidth && (this.lastEmittedBarWidth = e.barWidth, this.eventBus.emit("zoomChange", { barWidth: e.barWidth }));
1260
1411
  }
1261
1412
  getResolvedLayout() {
1262
1413
  return this.resolvedLayoutCache ||= this.layoutManager.resolve(), this.resolvedLayoutCache;
@@ -1268,7 +1419,7 @@ var I = class {
1268
1419
  buildPanelRenderInfos() {
1269
1420
  if (this.panelInfoCache) return this.panelInfoCache;
1270
1421
  let e = this.getResolvedLayout(), t = this.viewport.getState(), { from: n, to: r } = t.visibleRange, i = e.panels.map((e) => {
1271
- let i = Xe(this.indicatorEngine.getOutput(e.config.id), n, r), a = {
1422
+ let i = it(this.indicatorEngine.getOutput(e.config.id), n, r), a = {
1272
1423
  x: e.rect.x,
1273
1424
  y: e.rect.y + 20,
1274
1425
  width: e.rect.width,
@@ -1324,9 +1475,20 @@ var I = class {
1324
1475
  },
1325
1476
  theme: this.themeManager.getTheme(),
1326
1477
  data: i,
1327
- numberLocale: this.numberLocale
1478
+ numberLocale: this.numberLocale,
1479
+ renderOverlayPlugins: (e, t) => this.drawOverlayPlugins(e, t)
1328
1480
  });
1329
1481
  }
1482
+ drawOverlayPlugins(e, t) {
1483
+ let n = I(this.pluginManager.getOverlays(), t);
1484
+ if (n.length === 0) return;
1485
+ let r = {
1486
+ viewport: this.viewport.getState(),
1487
+ data: this.getDisplayData(),
1488
+ theme: this.themeManager.getTheme()
1489
+ };
1490
+ for (let t of n) t.render(e, r);
1491
+ }
1330
1492
  buildPriceLimits() {
1331
1493
  if (!this.marketConfig?.priceLimits?.enabled || !this.marketConfig.priceLimits.referencePrice) return null;
1332
1494
  let e = s(this.marketConfig.priceLimits.referencePrice, this.marketConfig);
@@ -1352,13 +1514,13 @@ var I = class {
1352
1514
  ];
1353
1515
  function J(e) {
1354
1516
  let t = e.trim();
1355
- return t ? t[0] === "[" || t[0] === "{" ? $e(t) : et(t) : {
1517
+ return t ? t[0] === "[" || t[0] === "{" ? ft(t) : pt(t) : {
1356
1518
  data: [],
1357
1519
  rowCount: 0,
1358
1520
  skipped: 0
1359
1521
  };
1360
1522
  }
1361
- function $e(e) {
1523
+ function ft(e) {
1362
1524
  let t;
1363
1525
  try {
1364
1526
  t = JSON.parse(e);
@@ -1368,19 +1530,19 @@ function $e(e) {
1368
1530
  if (!Array.isArray(t)) throw Error("Expected a JSON array of OHLCV rows");
1369
1531
  let n = [], r = 0;
1370
1532
  for (let e of t) {
1371
- let t = Array.isArray(e) ? it(e) : rt(e);
1533
+ let t = Array.isArray(e) ? _t(e) : gt(e);
1372
1534
  t ? n.push(t) : r++;
1373
1535
  }
1374
1536
  return Q(n, t.length, r);
1375
1537
  }
1376
- function et(e) {
1538
+ function pt(e) {
1377
1539
  let t = e.split(/\r?\n/).filter((e) => e.trim().length > 0);
1378
1540
  if (t.length === 0) return {
1379
1541
  data: [],
1380
1542
  rowCount: 0,
1381
1543
  skipped: 0
1382
1544
  };
1383
- let n = tt(t[0]), r = Y(t[0], n).map((e) => e.trim().toLowerCase()), i = r.some((e) => isNaN(Number(e)) && e.length > 0), a = i ? nt(r) : {
1545
+ let n = mt(t[0]), r = Y(t[0], n).map((e) => e.trim().toLowerCase()), i = r.some((e) => isNaN(Number(e)) && e.length > 0), a = i ? ht(r) : {
1384
1546
  time: 0,
1385
1547
  open: 1,
1386
1548
  high: 2,
@@ -1412,7 +1574,7 @@ function et(e) {
1412
1574
  }
1413
1575
  return Q(o, t.length - +!!i, s);
1414
1576
  }
1415
- function tt(e) {
1577
+ function mt(e) {
1416
1578
  let t = {
1417
1579
  ",": 0,
1418
1580
  ";": 0,
@@ -1432,7 +1594,7 @@ function Y(e, t) {
1432
1594
  }
1433
1595
  return n.push(r), n;
1434
1596
  }
1435
- function nt(e) {
1597
+ function ht(e) {
1436
1598
  let t = (t) => e.findIndex((e) => t.includes(e));
1437
1599
  return {
1438
1600
  time: t(H),
@@ -1443,7 +1605,7 @@ function nt(e) {
1443
1605
  volume: t(q)
1444
1606
  };
1445
1607
  }
1446
- function rt(e) {
1608
+ function gt(e) {
1447
1609
  let t = (t) => {
1448
1610
  for (let n of t) {
1449
1611
  if (e[n] !== void 0) return e[n];
@@ -1465,7 +1627,7 @@ function rt(e) {
1465
1627
  volume: Number.isFinite(s) ? s : 0
1466
1628
  };
1467
1629
  }
1468
- function it(e) {
1630
+ function _t(e) {
1469
1631
  if (e.length < 5) return null;
1470
1632
  let t = Z(String(e[0])), n = Number(e[1]), r = Number(e[2]), i = Number(e[3]), a = Number(e[4]), o = e.length >= 6 ? Number(e[5]) : 0;
1471
1633
  return t === null || ![
@@ -1505,7 +1667,7 @@ function Q(e, t, n) {
1505
1667
  }
1506
1668
  //#endregion
1507
1669
  //#region src/io/DragDropImporter.ts
1508
- var at = class {
1670
+ var vt = class {
1509
1671
  host;
1510
1672
  overlay = null;
1511
1673
  callbacks;
@@ -1573,6 +1735,6 @@ function $(e) {
1573
1735
  return e.dataTransfer?.types?.includes("Files") ?? !1;
1574
1736
  }
1575
1737
  //#endregion
1576
- export { B as a, V as i, J as n, L as o, Qe as r, I as s, at as t };
1738
+ export { lt as a, ct as c, L as d, F as f, B as i, ot as l, j as m, J as n, z as o, M as p, dt as r, st as s, vt as t, I as u };
1577
1739
 
1578
- //# sourceMappingURL=DragDropImporter-Br2ez5Gz.js.map
1740
+ //# sourceMappingURL=DragDropImporter-D_WpWB5H.js.map