acttrader-charts 1.0.8 → 1.0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -194,6 +194,18 @@ chart.on('tradeLevelDrag', ({ label, newPrice, bracketType, isFullscreen }) => {
194
194
  | `buy` | must stay ≤ order price | must stay ≥ order price |
195
195
  | `sell` | must stay ≥ order price | must stay ≤ order price |
196
196
 
197
+ **Mobile mode — `hideLevelConfirmCancel: true`:**
198
+
199
+ When the on-canvas ✓/✗ buttons are hidden (mobile native UI), the chart adapts its interaction model:
200
+
201
+ - **Tap a trade level line** → `tradeLevelEditOpen` fires immediately (the whole line acts as the edit button; no pencil icon required).
202
+ - **Tap empty canvas area while a level is selected** → edit is dismissed and any pending drag changes are reverted (equivalent to pressing ✗).
203
+ - **Drag a SL/TP bracket and release** → `tradeLevelEdit` fires automatically without needing a ✓ button tap.
204
+
205
+ **Market orders — BID/ASK spread zone:**
206
+
207
+ When `enableTrading` is on and live BID/ASK data is streaming, hovering / activating the trade crosshair button while the cursor price is inside the spread shows **"Buy Market"** and **"Sell Market"** rows instead of the standard Limit/Stop rows. Tapping either row calls `showMarketDraft()` internally and emits `draftInitiated` with `orderType: 'market'`.
208
+
197
209
  ---
198
210
 
199
211
  ## Default Configuration
@@ -484,6 +496,8 @@ chart.setDrawingTool(tool: DrawingToolType | null): this
484
496
  chart.setLevels(levels, labelField, priceField, type): this
485
497
  chart.removeLevelByLabel(label: string): this
486
498
  chart.cancelCurrentEdit(): this // cancel the active draft order or in-progress level edit; no-op when nothing is active
499
+ chart.addLevelBracket(label: string, bracketType: 'sl' | 'tp'): this // auto-place a SL or TP bracket at a default offset; emits tradeLevelBracketActivated with the computed price
500
+ chart.setDraftBracketPnl(bracketType: 'sl' | 'tp', pnlText: string | null): this // set estimated P&L text on a draft order bracket line; pass null to clear
487
501
  ```
488
502
 
489
503
  ### Trade Button
@@ -662,6 +676,12 @@ chart.on('draftInitiated', ({ side, price, orderType, isFullscreen }) => {})
662
676
  chart.on('draftCancelled', ({ label, isFullscreen }) => {}); // draft order dismissed without confirming
663
677
  chart.on('tradeLevelDragEnd', ({ label, type, newPrice, data }) => {}); // deprecated — use tradeLevelEdit
664
678
  chart.on('tradeLevelBracketDrag', ({ label, bracketType, newPrice, data }) => {}); // deprecated
679
+
680
+ // Fires after addLevelBracket() auto-places a bracket, delivering the computed price back to the caller
681
+ chart.on('tradeLevelBracketActivated', ({ label, bracketType, price, isFullscreen }) => {
682
+ // Use price to pre-populate the SL/TP input field in your native form
683
+ updateBracketPriceInput(bracketType, price);
684
+ });
665
685
  ```
666
686
 
667
687
  ---
@@ -518,6 +518,8 @@ interface ChartConfig {
518
518
  showUI?: boolean;
519
519
  /** If false, the drawing tools toolbar and pencil button are hidden entirely. Default: true */
520
520
  showDrawingTools?: boolean;
521
+ /** If false, the settings gear button in the top bar is hidden entirely. Default: true */
522
+ showSettings?: boolean;
521
523
  timeframe?: Timeframe;
522
524
  duration?: Duration;
523
525
  symbol?: string;
@@ -986,6 +988,13 @@ type ChartEventMap = {
986
988
  openingBar: OHLCVBar;
987
989
  intervalMs: number;
988
990
  };
991
+ /** Emitted after addLevelBracket() auto-places a SL or TP bracket so consumers can populate their form's price field. */
992
+ tradeLevelBracketActivated: {
993
+ label: string;
994
+ bracketType: 'sl' | 'tp';
995
+ price: number;
996
+ isFullscreen: boolean;
997
+ };
989
998
  /** Emitted when the user confirms all edits to a level — replaces separate tradeLevelDragEnd / tradeLevelBracketDrag events. */
990
999
  tradeLevelEdit: {
991
1000
  label: string;
@@ -518,6 +518,8 @@ interface ChartConfig {
518
518
  showUI?: boolean;
519
519
  /** If false, the drawing tools toolbar and pencil button are hidden entirely. Default: true */
520
520
  showDrawingTools?: boolean;
521
+ /** If false, the settings gear button in the top bar is hidden entirely. Default: true */
522
+ showSettings?: boolean;
521
523
  timeframe?: Timeframe;
522
524
  duration?: Duration;
523
525
  symbol?: string;
@@ -986,6 +988,13 @@ type ChartEventMap = {
986
988
  openingBar: OHLCVBar;
987
989
  intervalMs: number;
988
990
  };
991
+ /** Emitted after addLevelBracket() auto-places a SL or TP bracket so consumers can populate their form's price field. */
992
+ tradeLevelBracketActivated: {
993
+ label: string;
994
+ bracketType: 'sl' | 'tp';
995
+ price: number;
996
+ isFullscreen: boolean;
997
+ };
989
998
  /** Emitted when the user confirms all edits to a level — replaces separate tradeLevelDragEnd / tradeLevelBracketDrag events. */
990
999
  tradeLevelEdit: {
991
1000
  label: string;
package/dist/index.cjs CHANGED
@@ -1607,7 +1607,7 @@ function isDraggable(level) {
1607
1607
  return !!level.entryPriceEditable;
1608
1608
  return false;
1609
1609
  }
1610
- function renderTradeLevels(ctx, levels, scale, priceRange, theme, chartW, priceH, precision, hoveredLabel = null, draggingLabel = null, dragNewPrice = null, selectedLabel = null, pendingLabels = /* @__PURE__ */ new Set(), positionStyle = "line", hideConfirmCancel = false) {
1610
+ function renderTradeLevels(ctx, levels, scale, priceRange, theme, chartW, priceH, precision, hoveredLabel = null, draggingLabel = null, dragNewPrice = null, selectedLabel = null, pendingLabels = /* @__PURE__ */ new Set(), positionStyle = "line", hideConfirmCancel = false, draftOrderLabel = null, draftBracketPnl = {}) {
1611
1611
  if (levels.length === 0)
1612
1612
  return {
1613
1613
  hitAreas: [],
@@ -1704,7 +1704,8 @@ function renderTradeLevels(ctx, levels, scale, priceRange, theme, chartW, priceH
1704
1704
  dragAreas,
1705
1705
  confirmAreas,
1706
1706
  addBracketAreas,
1707
- hideConfirmCancel
1707
+ hideConfirmCancel,
1708
+ level.label === draftOrderLabel ? draftBracketPnl : void 0
1708
1709
  );
1709
1710
  }
1710
1711
  ctx.restore();
@@ -1768,7 +1769,7 @@ function drawDotHoverBox(ctx, level, y, dotX, dotR, theme, precision) {
1768
1769
  });
1769
1770
  ctx.restore();
1770
1771
  }
1771
- function drawLevel(ctx, level, layout, chartW, colors, theme, precision, hovered, selected, scale, priceRange, priceH, draggingLabel, dragNewPrice, bracketLineXMap, hasPendingChanges, positionStyle, hitAreas, editAreas, hoverAreas, dragAreas, confirmAreas, addBracketAreas, hideConfirmCancel = false) {
1772
+ function drawLevel(ctx, level, layout, chartW, colors, theme, precision, hovered, selected, scale, priceRange, priceH, draggingLabel, dragNewPrice, bracketLineXMap, hasPendingChanges, positionStyle, hitAreas, editAreas, hoverAreas, dragAreas, confirmAreas, addBracketAreas, hideConfirmCancel = false, draftBracketPnl) {
1772
1773
  const { y, boxY, boxW, boxH } = layout;
1773
1774
  const color = levelColor(level, colors, theme);
1774
1775
  const active = hovered || selected;
@@ -1830,7 +1831,8 @@ function drawLevel(ctx, level, layout, chartW, colors, theme, precision, hovered
1830
1831
  dragNewPrice,
1831
1832
  hitAreas,
1832
1833
  dragAreas,
1833
- bracketHost._slOrderLabel
1834
+ bracketHost._slOrderLabel,
1835
+ draftBracketPnl?.sl
1834
1836
  );
1835
1837
  } else if (draggingLabel === slDragKey && dragNewPrice !== null) {
1836
1838
  const bLineX = chartW * BRACKET_BASE_RATIO;
@@ -1850,7 +1852,8 @@ function drawLevel(ctx, level, layout, chartW, colors, theme, precision, hovered
1850
1852
  dragNewPrice,
1851
1853
  hitAreas,
1852
1854
  dragAreas,
1853
- void 0
1855
+ void 0,
1856
+ draftBracketPnl?.sl
1854
1857
  );
1855
1858
  }
1856
1859
  if (bracketHost.takeProfitPrice !== void 0) {
@@ -1871,7 +1874,8 @@ function drawLevel(ctx, level, layout, chartW, colors, theme, precision, hovered
1871
1874
  dragNewPrice,
1872
1875
  hitAreas,
1873
1876
  dragAreas,
1874
- bracketHost._tpOrderLabel
1877
+ bracketHost._tpOrderLabel,
1878
+ draftBracketPnl?.tp
1875
1879
  );
1876
1880
  } else if (draggingLabel === tpDragKey && dragNewPrice !== null) {
1877
1881
  const bLineX = chartW * BRACKET_BASE_RATIO;
@@ -1891,7 +1895,8 @@ function drawLevel(ctx, level, layout, chartW, colors, theme, precision, hovered
1891
1895
  dragNewPrice,
1892
1896
  hitAreas,
1893
1897
  dragAreas,
1894
- void 0
1898
+ void 0,
1899
+ draftBracketPnl?.tp
1895
1900
  );
1896
1901
  }
1897
1902
  if (selected && bracketHost.side !== void 0) {
@@ -2162,7 +2167,7 @@ function drawAddBracketButton(ctx, level, bracketType, entryY, bracketLineX, cha
2162
2167
  h: bH
2163
2168
  });
2164
2169
  }
2165
- function drawBracketLine(ctx, level, bracketType, bracketPrice, scale, priceRange, priceH, bracketLineX, chartW, theme, precision, draggingLabel, dragNewPrice, hitAreas, dragAreas, bracketOrderLabel) {
2170
+ function drawBracketLine(ctx, level, bracketType, bracketPrice, scale, priceRange, priceH, bracketLineX, chartW, theme, precision, draggingLabel, dragNewPrice, hitAreas, dragAreas, bracketOrderLabel, pnlText) {
2166
2171
  const isDraggingThis = draggingLabel === `${level.label}:${bracketType}`;
2167
2172
  const price = isDraggingThis && dragNewPrice !== null ? dragNewPrice : bracketPrice;
2168
2173
  const y = scale.yToPixel(price, priceRange, priceH);
@@ -2181,7 +2186,8 @@ function drawBracketLine(ctx, level, bracketType, bracketPrice, scale, priceRang
2181
2186
  const boxLabel = `${typeLabel} ${priceStr}`;
2182
2187
  ctx.font = FONT_BRACKET;
2183
2188
  const textW = ctx.measureText(boxLabel).width;
2184
- const bW = BRACKET_BOX_PAD_X + textW + BRACKET_BOX_PAD_X + CLOSE_R * 2 + BRACKET_BOX_PAD_X / 2;
2189
+ const pnlW = pnlText ? ctx.measureText(pnlText).width + BRACKET_BOX_PAD_X : 0;
2190
+ const bW = BRACKET_BOX_PAD_X + textW + pnlW + BRACKET_BOX_PAD_X + CLOSE_R * 2 + BRACKET_BOX_PAD_X / 2;
2185
2191
  const bH = BRACKET_BOX_H;
2186
2192
  const bX = bracketLineX - bW - 2;
2187
2193
  const bY = y - bH / 2;
@@ -2195,6 +2201,11 @@ function drawBracketLine(ctx, level, bracketType, bracketPrice, scale, priceRang
2195
2201
  ctx.textAlign = "left";
2196
2202
  ctx.textBaseline = "middle";
2197
2203
  ctx.fillText(boxLabel, bX + BRACKET_BOX_PAD_X, y);
2204
+ if (pnlText) {
2205
+ const isLoss = pnlText.trim().startsWith("-");
2206
+ ctx.fillStyle = isLoss ? theme.candle.down : theme.candle.up;
2207
+ ctx.fillText(pnlText, bX + BRACKET_BOX_PAD_X + textW + BRACKET_BOX_PAD_X, y);
2208
+ }
2198
2209
  const btnX = bX + bW - BRACKET_BOX_PAD_X / 2 - CLOSE_R;
2199
2210
  const btnY = y;
2200
2211
  ctx.fillStyle = monoColor(theme);
@@ -3073,7 +3084,7 @@ function injectFlyoutScrollbarStyles() {
3073
3084
  document.head.appendChild(style);
3074
3085
  }
3075
3086
  var TopBar = class {
3076
- constructor(onSeriesChange, onTimeframeChange, onAddIndicator, onDurationChange, onSettingsClick, onFullscreenToggle, onDrawingToolsToggle, showDrawingToolsBtn, initialSeries, initialTf, initialDuration, durationMap, theme, cfg = DEFAULT_TOP_BAR_CONFIG, labels = DEFAULT_LABELS.topBar) {
3087
+ constructor(onSeriesChange, onTimeframeChange, onAddIndicator, onDurationChange, onSettingsClick, onFullscreenToggle, onDrawingToolsToggle, showDrawingToolsBtn, showSettingsBtn, initialSeries, initialTf, initialDuration, durationMap, theme, cfg = DEFAULT_TOP_BAR_CONFIG, labels = DEFAULT_LABELS.topBar) {
3077
3088
  this.onSeriesChange = onSeriesChange;
3078
3089
  this.onTimeframeChange = onTimeframeChange;
3079
3090
  this.onAddIndicator = onAddIndicator;
@@ -3081,6 +3092,7 @@ var TopBar = class {
3081
3092
  this.onSettingsClick = onSettingsClick;
3082
3093
  this.onFullscreenToggle = onFullscreenToggle;
3083
3094
  this.onDrawingToolsToggle = onDrawingToolsToggle;
3095
+ this.settingsBtn = null;
3084
3096
  this.isFullscreen = false;
3085
3097
  this.durationBtns = /* @__PURE__ */ new Map();
3086
3098
  this.isMobileLayout = false;
@@ -3156,16 +3168,18 @@ var TopBar = class {
3156
3168
  });
3157
3169
  this.addBtnHover(this.fullscreenBtn);
3158
3170
  this.rightGroup.appendChild(this.fullscreenBtn);
3159
- this.settingsBtn = document.createElement("button");
3160
- this.settingsBtn.title = this.labels.settingsTitle;
3161
- this.settingsBtn.innerHTML = ICON_SETTINGS;
3162
- this.applyIconBtnStyles(this.settingsBtn, theme, false);
3163
- this.settingsBtn.addEventListener("click", (e) => {
3164
- e.stopPropagation();
3165
- this.onSettingsClick();
3166
- });
3167
- this.addBtnHover(this.settingsBtn);
3168
- this.rightGroup.appendChild(this.settingsBtn);
3171
+ if (showSettingsBtn) {
3172
+ this.settingsBtn = document.createElement("button");
3173
+ this.settingsBtn.title = this.labels.settingsTitle;
3174
+ this.settingsBtn.innerHTML = ICON_SETTINGS;
3175
+ this.applyIconBtnStyles(this.settingsBtn, theme, false);
3176
+ this.settingsBtn.addEventListener("click", (e) => {
3177
+ e.stopPropagation();
3178
+ this.onSettingsClick();
3179
+ });
3180
+ this.addBtnHover(this.settingsBtn);
3181
+ this.rightGroup.appendChild(this.settingsBtn);
3182
+ }
3169
3183
  this.el.append(this.leftGroup, this.rightGroup);
3170
3184
  this.docClickHandler = (e) => {
3171
3185
  if (!this.el.contains(e.target) && !this.flyout.contains(e.target)) {
@@ -3199,7 +3213,7 @@ var TopBar = class {
3199
3213
  this.applyFlyoutStyles();
3200
3214
  if (this.drawingBtn) this.applyIconBtnStyles(this.drawingBtn, theme, false);
3201
3215
  this.applyIconBtnStyles(this.fullscreenBtn, theme, this.isFullscreen);
3202
- this.applyIconBtnStyles(this.settingsBtn, theme, false);
3216
+ if (this.settingsBtn) this.applyIconBtnStyles(this.settingsBtn, theme, false);
3203
3217
  this.applySeriesBtnStyles(this.seriesBtn, theme, false);
3204
3218
  this.applyDropBtnStyles(this.tfBtn, theme, false);
3205
3219
  this.applyDropBtnStyles(this.indBtn, theme, false);
@@ -11519,7 +11533,7 @@ var TAB_LABELS = {
11519
11533
  trading: "Trading"
11520
11534
  };
11521
11535
  var ChartSettingsDialog = class {
11522
- constructor(theme, initial, labels = DEFAULT_LABELS.dialogs) {
11536
+ constructor(theme, initial, labels = DEFAULT_LABELS.dialogs, showTradingTab = true) {
11523
11537
  this.activeTab = "appearance";
11524
11538
  this.onChange = null;
11525
11539
  this.onReset = null;
@@ -11527,6 +11541,8 @@ var ChartSettingsDialog = class {
11527
11541
  this.theme = theme;
11528
11542
  this.labels = labels;
11529
11543
  this.current = { ...initial };
11544
+ this.showTradingTab = showTradingTab;
11545
+ if (!showTradingTab && this.activeTab === "trading") this.activeTab = "appearance";
11530
11546
  this.el = document.createElement("div");
11531
11547
  Object.assign(this.el.style, {
11532
11548
  position: "fixed",
@@ -11718,7 +11734,7 @@ var ChartSettingsDialog = class {
11718
11734
  return sidebar;
11719
11735
  }
11720
11736
  buildSidebarTabs(container) {
11721
- const tabs = ["appearance", "trading"];
11737
+ const tabs = this.showTradingTab ? ["appearance", "trading"] : ["appearance"];
11722
11738
  for (const tab of tabs) {
11723
11739
  const btn = document.createElement("button");
11724
11740
  Object.assign(btn.style, {
@@ -12259,6 +12275,7 @@ var TradePopover = class {
12259
12275
  this._pricePrecision = 2;
12260
12276
  this._buyOrderType = "limit";
12261
12277
  this._sellOrderType = "limit";
12278
+ this._isMarket = false;
12262
12279
  this.onDocMouseDown = (e) => {
12263
12280
  if (this.isVisible && !this.el.contains(e.target)) {
12264
12281
  this.hide();
@@ -12288,11 +12305,12 @@ var TradePopover = class {
12288
12305
  document.addEventListener("mousedown", this.onDocMouseDown);
12289
12306
  }
12290
12307
  // ── Public ────────────────────────────────────────────────────────────────
12291
- show(price, buttonY, buttonRight, pricePrecision = 2, buyOrderType = "limit", sellOrderType = "limit") {
12308
+ show(price, buttonY, buttonRight, pricePrecision = 2, buyOrderType = "limit", sellOrderType = "limit", isMarket = false) {
12292
12309
  this._price = price;
12293
12310
  this._pricePrecision = pricePrecision;
12294
12311
  this._buyOrderType = buyOrderType;
12295
12312
  this._sellOrderType = sellOrderType;
12313
+ this._isMarket = isMarket;
12296
12314
  this.rebuild();
12297
12315
  this.el.style.display = "flex";
12298
12316
  const popW = 145;
@@ -12322,16 +12340,22 @@ var TradePopover = class {
12322
12340
  // ── Private ───────────────────────────────────────────────────────────────
12323
12341
  rebuild() {
12324
12342
  this.el.innerHTML = "";
12325
- this.el.append(
12326
- this.makeRow(this.labels.buy, "#26a69a", "buy", this._buyOrderType),
12327
- this.makeRow(this.labels.sell, "#ef5350", "sell", this._sellOrderType)
12328
- );
12343
+ if (this._isMarket) {
12344
+ this.el.append(
12345
+ this.makeRow(`${this.labels.buy} Market`, "#26a69a", "buy", "market"),
12346
+ this.makeRow(`${this.labels.sell} Market`, "#ef5350", "sell", "market")
12347
+ );
12348
+ } else {
12349
+ this.el.append(
12350
+ this.makeRow(this.labels.buy, "#26a69a", "buy", this._buyOrderType),
12351
+ this.makeRow(this.labels.sell, "#ef5350", "sell", this._sellOrderType)
12352
+ );
12353
+ }
12329
12354
  }
12330
12355
  makeRow(label, color, side, orderType) {
12331
12356
  const btn = document.createElement("button");
12332
12357
  const priceStr = this._price.toFixed(this._pricePrecision);
12333
- const typeLabel = orderType === "limit" ? this.labels.limit : this.labels.stop;
12334
- btn.textContent = `${label} ${typeLabel} ${priceStr}`;
12358
+ btn.textContent = orderType === "market" ? `${label} ${priceStr}` : `${label} ${orderType === "limit" ? this.labels.limit : this.labels.stop} ${priceStr}`;
12335
12359
  Object.assign(btn.style, {
12336
12360
  display: "block",
12337
12361
  width: "100%",
@@ -16377,6 +16401,7 @@ var _ChartEngine = class _ChartEngine {
16377
16401
  this.leftBar = null;
16378
16402
  this.leftBarVisible = true;
16379
16403
  this.drawingToolsEnabled = true;
16404
+ this.settingsEnabled = true;
16380
16405
  this._mobileLayout = false;
16381
16406
  this.indicatorOverlay = null;
16382
16407
  this.subPaneOverlays = /* @__PURE__ */ new Map();
@@ -16400,6 +16425,7 @@ var _ChartEngine = class _ChartEngine {
16400
16425
  this.draftOrderQtyInput = null;
16401
16426
  this._hoverBuyType = "limit";
16402
16427
  this._hoverSellType = "limit";
16428
+ this._hoverInSpread = false;
16403
16429
  this._onOrderSubmit = void 0;
16404
16430
  this._minLots = 1;
16405
16431
  this.scrollToEndBtn = null;
@@ -16496,6 +16522,8 @@ var _ChartEngine = class _ChartEngine {
16496
16522
  this.tradeAddBracketAreas = [];
16497
16523
  this.hoveredTradeLabel = null;
16498
16524
  this.selectedTradeLabel = null;
16525
+ /** Estimated PNL text for draft order SL/TP bracket lines, set by setDraftBracketPnl(). */
16526
+ this.draftBracketPnl = {};
16499
16527
  // TFC components
16500
16528
  this.tradeDragHandler = null;
16501
16529
  this.tradeDragNewPrice = null;
@@ -16560,6 +16588,7 @@ var _ChartEngine = class _ChartEngine {
16560
16588
  const lastClose = allBars.length > 0 ? allBars[allBars.length - 1].close : price;
16561
16589
  this._hoverBuyType = price < lastClose ? "limit" : "stop";
16562
16590
  this._hoverSellType = price > lastClose ? "limit" : "stop";
16591
+ this._hoverInSpread = !!(this.liveBidAsk && price >= this.liveBidAsk.bid && price <= this.liveBidAsk.ask);
16563
16592
  } else if (!this.tradePopover?.isVisible) {
16564
16593
  this.tradeButton.hide();
16565
16594
  }
@@ -17172,9 +17201,28 @@ var _ChartEngine = class _ChartEngine {
17172
17201
  this.selectedTradeLabel = hoverHit.label;
17173
17202
  }
17174
17203
  this.renderTradeLayer();
17204
+ if (this.hideLevelConfirmCancel) {
17205
+ const level = this.levels.find((l) => l.label === hoverHit.label);
17206
+ if (level) {
17207
+ this.emitter.emit("tradeLevelEditOpen", {
17208
+ label: level.label,
17209
+ type: level.type,
17210
+ data: level.data,
17211
+ price: level.price,
17212
+ side: level.side,
17213
+ stopLossPrice: level.stopLossPrice,
17214
+ takeProfitPrice: level.takeProfitPrice,
17215
+ isFullscreen: this.isFullscreen
17216
+ });
17217
+ }
17218
+ }
17175
17219
  return;
17176
17220
  } else if (this.selectedTradeLabel !== null) {
17177
- if (!this.pendingLevelDrags.has(this.selectedTradeLabel)) {
17221
+ if (this.hideLevelConfirmCancel) {
17222
+ this.revertPendingChanges(this.selectedTradeLabel);
17223
+ this.selectedTradeLabel = null;
17224
+ this.renderTradeLayer();
17225
+ } else if (!this.pendingLevelDrags.has(this.selectedTradeLabel)) {
17178
17226
  this.selectedTradeLabel = null;
17179
17227
  this.renderTradeLayer();
17180
17228
  }
@@ -17384,6 +17432,7 @@ var _ChartEngine = class _ChartEngine {
17384
17432
  } = config;
17385
17433
  this.dataLoader = dataLoader ?? null;
17386
17434
  this.drawingToolsEnabled = config.showDrawingTools !== false;
17435
+ this.settingsEnabled = config.showSettings !== false;
17387
17436
  this.uiConfig = resolveUiConfig(uiConfig);
17388
17437
  this.labels = resolveLabels(labels);
17389
17438
  this.tickActivityMs = tickActivityMs;
@@ -17476,6 +17525,7 @@ var _ChartEngine = class _ChartEngine {
17476
17525
  },
17477
17526
  this.drawingToolsEnabled ? () => this.toggleDrawingTools() : null,
17478
17527
  this.drawingToolsEnabled,
17528
+ this.settingsEnabled,
17479
17529
  this.series,
17480
17530
  this.timeframe,
17481
17531
  null,
@@ -17734,7 +17784,10 @@ var _ChartEngine = class _ChartEngine {
17734
17784
  this.tradePopover = new TradePopover(
17735
17785
  this.theme,
17736
17786
  lots,
17737
- (side, price, orderType) => this.createDraftOrder(side, price, orderType),
17787
+ (side, price, orderType) => {
17788
+ if (orderType === "market") this.showMarketDraft(price, side);
17789
+ else this.createDraftOrder(side, price, orderType);
17790
+ },
17738
17791
  this.labels.trade
17739
17792
  );
17740
17793
  this.canvasWrap.appendChild(this.tradePopover.el);
@@ -17756,7 +17809,8 @@ var _ChartEngine = class _ChartEngine {
17756
17809
  btnRight,
17757
17810
  this.dataStore.getPricePrecision(),
17758
17811
  this._hoverBuyType,
17759
- this._hoverSellType
17812
+ this._hoverSellType,
17813
+ this._hoverInSpread
17760
17814
  );
17761
17815
  }
17762
17816
  },
@@ -18808,6 +18862,34 @@ var _ChartEngine = class _ChartEngine {
18808
18862
  this.renderTradeLayer();
18809
18863
  return this;
18810
18864
  }
18865
+ /**
18866
+ * Add a SL or TP bracket to an existing level at an auto-computed default price.
18867
+ * Use this when an external panel enables a bracket without knowing the price.
18868
+ * The chart places the bracket at the same offset used by the canvas +SL/+TP button
18869
+ * and emits `tradeLevelBracketActivated` with the chosen price so the panel can populate its input.
18870
+ * No-op if the level doesn't exist or already has the requested bracket.
18871
+ */
18872
+ addLevelBracket(label, type) {
18873
+ const level = this.levels.find((l) => l.label === label);
18874
+ if (!level) return this;
18875
+ const alreadyHas = type === "sl" ? level.stopLossPrice !== void 0 : level.takeProfitPrice !== void 0;
18876
+ if (alreadyHas) return this;
18877
+ const { priceH } = this.getChartLayout();
18878
+ const priceRange = this._displayedPriceRange ?? this.getScaledPriceRange(this.viewport);
18879
+ const entryY = this.scaleManager.yToPixel(level.price, priceRange, priceH);
18880
+ const side = level.side ?? "buy";
18881
+ const isBelowEntry = side === "buy" && type === "sl" || side === "sell" && type === "tp";
18882
+ const bracketY = entryY + (isBelowEntry ? 30 : -30);
18883
+ const defaultPrice = this.scaleManager.pixelToPrice(bracketY, priceRange, priceH);
18884
+ this.updateLevelBracket(label, type, defaultPrice);
18885
+ this.emitter.emit("tradeLevelBracketActivated", {
18886
+ label,
18887
+ bracketType: type,
18888
+ price: defaultPrice,
18889
+ isFullscreen: this.isFullscreen
18890
+ });
18891
+ return this;
18892
+ }
18811
18893
  /**
18812
18894
  * Move an existing level's entry price line to a new price and re-render.
18813
18895
  * Used when an external panel updates the entry price for an open position or pending order.
@@ -18821,6 +18903,21 @@ var _ChartEngine = class _ChartEngine {
18821
18903
  }
18822
18904
  return this;
18823
18905
  }
18906
+ /**
18907
+ * Set or clear the estimated PNL text shown on a draft order's SL or TP bracket line.
18908
+ * Pass `null` to clear the text. No-op if no draft order is active.
18909
+ * Use this to display the consumer-calculated estimated profit/loss next to the bracket.
18910
+ */
18911
+ setDraftBracketPnl(type, pnlText) {
18912
+ if (!this.draftOrderLabel) return this;
18913
+ if (type === "sl") {
18914
+ this.draftBracketPnl = { ...this.draftBracketPnl, sl: pnlText ?? void 0 };
18915
+ } else {
18916
+ this.draftBracketPnl = { ...this.draftBracketPnl, tp: pnlText ?? void 0 };
18917
+ }
18918
+ this.renderTradeLayer();
18919
+ return this;
18920
+ }
18824
18921
  /**
18825
18922
  * Update the stop-loss or take-profit price on the current draft order.
18826
18923
  * Pass `null` to remove the bracket. No-op if no draft order is active.
@@ -19079,7 +19176,8 @@ var _ChartEngine = class _ChartEngine {
19079
19176
  positionRenderStyle: this.positionRenderStyle,
19080
19177
  theme: this.themeName
19081
19178
  },
19082
- this.labels.dialogs
19179
+ this.labels.dialogs,
19180
+ !!this._onOrderSubmit
19083
19181
  );
19084
19182
  this.getFloatingRoot().appendChild(this.chartSettingsDialog.el);
19085
19183
  }
@@ -19269,7 +19367,9 @@ var _ChartEngine = class _ChartEngine {
19269
19367
  this.selectedTradeLabel,
19270
19368
  new Set(this.pendingLevelDrags.keys()),
19271
19369
  this.positionRenderStyle,
19272
- this.hideLevelConfirmCancel
19370
+ this.hideLevelConfirmCancel,
19371
+ this.draftOrderLabel,
19372
+ this.draftBracketPnl
19273
19373
  );
19274
19374
  ctx.restore();
19275
19375
  ctx.restore();
@@ -19348,6 +19448,10 @@ var _ChartEngine = class _ChartEngine {
19348
19448
  filtered.push({ field, newPrice: result.newPrice, oldPrice, isNew, bracketOrderLabel });
19349
19449
  this.pendingLevelDrags.set(result.label, filtered);
19350
19450
  this.tradeDragNewPrice = null;
19451
+ if (this.hideLevelConfirmCancel) {
19452
+ this.applyPendingChanges(result.label);
19453
+ return;
19454
+ }
19351
19455
  this.renderTradeLayer();
19352
19456
  }
19353
19457
  createDraftOrder(side, price, orderType) {
@@ -19383,6 +19487,7 @@ var _ChartEngine = class _ChartEngine {
19383
19487
  this.pendingLevelDrags.delete(label);
19384
19488
  this.selectedTradeLabel = null;
19385
19489
  this.draftOrderLabel = null;
19490
+ this.draftBracketPnl = {};
19386
19491
  this.draftOrderQtyInput?.hide();
19387
19492
  this.renderTradeLayer();
19388
19493
  this.emitter.emit("draftCancelled", { label, isFullscreen: this.isFullscreen });