acttrader-charts 1.0.11 → 1.0.13
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 +8 -2
- package/dist/{MACD-DoO45b_C.d.cts → MACD-CEmdbwGz.d.cts} +19 -1
- package/dist/{MACD-DoO45b_C.d.ts → MACD-CEmdbwGz.d.ts} +19 -1
- package/dist/index.cjs +210 -86
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +16 -5
- package/dist/index.d.ts +16 -5
- package/dist/index.js +210 -87
- package/dist/index.js.map +1 -1
- package/dist/indicators/index.d.cts +2 -2
- package/dist/indicators/index.d.ts +2 -2
- package/dist/webview/chart.html +7 -7
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -428,6 +428,9 @@ var DEFAULT_TOP_BAR_CONFIG = {
|
|
|
428
428
|
dropBtnFontFamily: INTER_FONT,
|
|
429
429
|
drawBtnSize: "26px",
|
|
430
430
|
drawBtnIconFontSize: "14px",
|
|
431
|
+
iconBtnSize: "26px",
|
|
432
|
+
mobileIconBtnSize: "28px",
|
|
433
|
+
mobileDrawBtnIconSize: "16px",
|
|
431
434
|
flyoutRowFontSize: "12px",
|
|
432
435
|
flyoutRowFontFamily: INTER_FONT,
|
|
433
436
|
flyoutCategoryFontSize: "10px",
|
|
@@ -465,6 +468,12 @@ var DEFAULT_INDICATOR_OVERLAY_CONFIG = {
|
|
|
465
468
|
dropdownRowFontFamily: INTER_FONT,
|
|
466
469
|
dropdownIconFontSize: "10px"
|
|
467
470
|
};
|
|
471
|
+
var DEFAULT_TRADE_BUTTON_CONFIG = {
|
|
472
|
+
size: 22,
|
|
473
|
+
mobileSize: 24,
|
|
474
|
+
iconSize: 14,
|
|
475
|
+
mobileIconSize: 16
|
|
476
|
+
};
|
|
468
477
|
var DEFAULT_UI_CONFIG = {
|
|
469
478
|
drawingToolbar: DEFAULT_DRAWING_TOOLBAR_CONFIG,
|
|
470
479
|
topBar: DEFAULT_TOP_BAR_CONFIG,
|
|
@@ -472,7 +481,8 @@ var DEFAULT_UI_CONFIG = {
|
|
|
472
481
|
priceAxis: DEFAULT_PRICE_AXIS_CONFIG,
|
|
473
482
|
timeAxis: DEFAULT_TIME_AXIS_CONFIG,
|
|
474
483
|
crosshair: DEFAULT_CROSSHAIR_CONFIG,
|
|
475
|
-
indicatorOverlay: DEFAULT_INDICATOR_OVERLAY_CONFIG
|
|
484
|
+
indicatorOverlay: DEFAULT_INDICATOR_OVERLAY_CONFIG,
|
|
485
|
+
tradeButton: DEFAULT_TRADE_BUTTON_CONFIG
|
|
476
486
|
};
|
|
477
487
|
function resolveUiConfig(override) {
|
|
478
488
|
if (!override) return DEFAULT_UI_CONFIG;
|
|
@@ -483,7 +493,8 @@ function resolveUiConfig(override) {
|
|
|
483
493
|
priceAxis: { ...DEFAULT_PRICE_AXIS_CONFIG, ...override.priceAxis },
|
|
484
494
|
timeAxis: { ...DEFAULT_TIME_AXIS_CONFIG, ...override.timeAxis },
|
|
485
495
|
crosshair: { ...DEFAULT_CROSSHAIR_CONFIG, ...override.crosshair },
|
|
486
|
-
indicatorOverlay: { ...DEFAULT_INDICATOR_OVERLAY_CONFIG, ...override.indicatorOverlay }
|
|
496
|
+
indicatorOverlay: { ...DEFAULT_INDICATOR_OVERLAY_CONFIG, ...override.indicatorOverlay },
|
|
497
|
+
tradeButton: { ...DEFAULT_TRADE_BUTTON_CONFIG, ...override.tradeButton }
|
|
487
498
|
};
|
|
488
499
|
}
|
|
489
500
|
|
|
@@ -2100,7 +2111,7 @@ function drawLevel(ctx, level, layout, chartW, colors, theme, precision, hovered
|
|
|
2100
2111
|
ctx.restore();
|
|
2101
2112
|
if (draggable) {
|
|
2102
2113
|
drawGripHandle(ctx, gripX, boxY, boxH, colors, hovered);
|
|
2103
|
-
const BTN_ZONE_W = EDIT_R * 2 + EDIT_GAP + CLOSE_R * 2 + BOX_PAD_X / 2;
|
|
2114
|
+
const BTN_ZONE_W = hideConfirmCancel ? 0 : EDIT_R * 2 + EDIT_GAP + CLOSE_R * 2 + BOX_PAD_X / 2;
|
|
2104
2115
|
dragAreas.push({
|
|
2105
2116
|
label: level.label,
|
|
2106
2117
|
type: level.type,
|
|
@@ -2110,7 +2121,8 @@ function drawLevel(ctx, level, layout, chartW, colors, theme, precision, hovered
|
|
|
2110
2121
|
y: boxY,
|
|
2111
2122
|
w: GRIP_W + 2 + boxW - BTN_ZONE_W,
|
|
2112
2123
|
h: boxH,
|
|
2113
|
-
isBracket: false
|
|
2124
|
+
isBracket: false,
|
|
2125
|
+
isBox: true
|
|
2114
2126
|
});
|
|
2115
2127
|
dragAreas.push({
|
|
2116
2128
|
label: level.label,
|
|
@@ -2123,6 +2135,19 @@ function drawLevel(ctx, level, layout, chartW, colors, theme, precision, hovered
|
|
|
2123
2135
|
h: 8,
|
|
2124
2136
|
isBracket: false
|
|
2125
2137
|
});
|
|
2138
|
+
} else if (hideConfirmCancel && boxW > 0) {
|
|
2139
|
+
dragAreas.push({
|
|
2140
|
+
label: level.label,
|
|
2141
|
+
type: level.type,
|
|
2142
|
+
data: level.data,
|
|
2143
|
+
price: level.price,
|
|
2144
|
+
x: boxX,
|
|
2145
|
+
y: boxY,
|
|
2146
|
+
w: boxW,
|
|
2147
|
+
h: boxH,
|
|
2148
|
+
isBracket: false,
|
|
2149
|
+
isBox: true
|
|
2150
|
+
});
|
|
2126
2151
|
}
|
|
2127
2152
|
hoverAreas.push({
|
|
2128
2153
|
label: level.label,
|
|
@@ -3223,6 +3248,9 @@ var TopBar = class {
|
|
|
3223
3248
|
this.fullscreenBtn.innerHTML = active ? ICON_FULLSCREEN_EXIT : ICON_FULLSCREEN_ENTER;
|
|
3224
3249
|
this.fullscreenBtn.title = active ? this.labels.exitFullscreenTitle : this.labels.toggleFullscreenTitle;
|
|
3225
3250
|
this.applyIconBtnStyles(this.fullscreenBtn, this.theme, active);
|
|
3251
|
+
if (this.isMobileLayout) {
|
|
3252
|
+
this.resizeSvg(this.fullscreenBtn, this.getSvgSize(this.fullscreenBtn) + 2);
|
|
3253
|
+
}
|
|
3226
3254
|
}
|
|
3227
3255
|
setDrawingsBtnActive(active) {
|
|
3228
3256
|
if (!this.drawingBtn) return;
|
|
@@ -3275,6 +3303,21 @@ var TopBar = class {
|
|
|
3275
3303
|
}
|
|
3276
3304
|
this.durationSep.style.display = btnDisplay;
|
|
3277
3305
|
this.durationDropBtn.style.display = isMobile ? "" : "none";
|
|
3306
|
+
const containerSize = isMobile ? this.cfg.mobileIconBtnSize : this.cfg.iconBtnSize;
|
|
3307
|
+
for (const btn of [this.fullscreenBtn, this.settingsBtn, this.drawingBtn]) {
|
|
3308
|
+
if (!btn) continue;
|
|
3309
|
+
btn.style.width = containerSize;
|
|
3310
|
+
btn.style.height = containerSize;
|
|
3311
|
+
}
|
|
3312
|
+
const delta = isMobile ? 2 : -2;
|
|
3313
|
+
this.resizeSvg(this.fullscreenBtn, this.getSvgSize(this.fullscreenBtn) + delta);
|
|
3314
|
+
if (this.settingsBtn) {
|
|
3315
|
+
this.resizeSvg(this.settingsBtn, this.getSvgSize(this.settingsBtn) + delta);
|
|
3316
|
+
}
|
|
3317
|
+
if (this.drawingBtn) {
|
|
3318
|
+
const drawIconSize = isMobile ? parseInt(this.cfg.mobileDrawBtnIconSize, 10) : parseInt(this.cfg.drawBtnIconFontSize, 10);
|
|
3319
|
+
this.resizeSvg(this.drawingBtn, drawIconSize);
|
|
3320
|
+
}
|
|
3278
3321
|
}
|
|
3279
3322
|
setIndicatorOptions(options) {
|
|
3280
3323
|
this.indicatorOptions = options;
|
|
@@ -3681,13 +3724,14 @@ var TopBar = class {
|
|
|
3681
3724
|
}
|
|
3682
3725
|
applyIconBtnStyles(btn, theme, active) {
|
|
3683
3726
|
btn.dataset.active = String(active);
|
|
3727
|
+
const size = this.isMobileLayout ? this.cfg.mobileIconBtnSize : this.cfg.iconBtnSize;
|
|
3684
3728
|
Object.assign(btn.style, {
|
|
3685
3729
|
background: active ? theme.ui.accentBg : "transparent",
|
|
3686
3730
|
color: active ? theme.ui.accentText : theme.topBar.btnColor,
|
|
3687
3731
|
border: `1px solid ${active ? theme.ui.accent : theme.axisBorder}`,
|
|
3688
3732
|
borderRadius: "5px",
|
|
3689
|
-
width:
|
|
3690
|
-
height:
|
|
3733
|
+
width: size,
|
|
3734
|
+
height: size,
|
|
3691
3735
|
cursor: "pointer",
|
|
3692
3736
|
outline: "none",
|
|
3693
3737
|
display: "flex",
|
|
@@ -3698,6 +3742,20 @@ var TopBar = class {
|
|
|
3698
3742
|
transition: "border-color 0.12s, background 0.12s"
|
|
3699
3743
|
});
|
|
3700
3744
|
}
|
|
3745
|
+
resizeSvg(btn, size) {
|
|
3746
|
+
if (!btn) return;
|
|
3747
|
+
const svg = btn.querySelector("svg");
|
|
3748
|
+
if (svg) {
|
|
3749
|
+
svg.setAttribute("width", String(size));
|
|
3750
|
+
svg.setAttribute("height", String(size));
|
|
3751
|
+
}
|
|
3752
|
+
}
|
|
3753
|
+
getSvgSize(btn) {
|
|
3754
|
+
if (!btn) return 0;
|
|
3755
|
+
const svg = btn.querySelector("svg");
|
|
3756
|
+
if (!svg) return 0;
|
|
3757
|
+
return parseInt(svg.getAttribute("width") ?? "0", 10);
|
|
3758
|
+
}
|
|
3701
3759
|
};
|
|
3702
3760
|
|
|
3703
3761
|
// src/ui/BottomBar.ts
|
|
@@ -12214,9 +12272,11 @@ var ChartSettingsDialog = class {
|
|
|
12214
12272
|
|
|
12215
12273
|
// src/ui/TradeButton.ts
|
|
12216
12274
|
var TradeButton = class {
|
|
12217
|
-
constructor(theme, priceAxisWidth, onClick, labels = DEFAULT_LABELS.trade) {
|
|
12275
|
+
constructor(theme, priceAxisWidth, onClick, labels = DEFAULT_LABELS.trade, cfg = DEFAULT_TRADE_BUTTON_CONFIG) {
|
|
12218
12276
|
this._visible = false;
|
|
12277
|
+
this._isMobile = false;
|
|
12219
12278
|
this.theme = theme;
|
|
12279
|
+
this.cfg = cfg;
|
|
12220
12280
|
this.el = document.createElement("button");
|
|
12221
12281
|
this.el.innerHTML = ICON_PLUS_CIRCLE;
|
|
12222
12282
|
this.el.title = labels.placeOrderTitle;
|
|
@@ -12224,8 +12284,8 @@ var TradeButton = class {
|
|
|
12224
12284
|
position: "absolute",
|
|
12225
12285
|
right: `${priceAxisWidth + 26}px`,
|
|
12226
12286
|
top: "0",
|
|
12227
|
-
width:
|
|
12228
|
-
height:
|
|
12287
|
+
width: `${cfg.size}px`,
|
|
12288
|
+
height: `${cfg.size}px`,
|
|
12229
12289
|
borderRadius: "50%",
|
|
12230
12290
|
border: `1px solid ${theme.axisBorder}`,
|
|
12231
12291
|
background: theme.tooltip.background,
|
|
@@ -12244,6 +12304,7 @@ var TradeButton = class {
|
|
|
12244
12304
|
pointerEvents: "auto",
|
|
12245
12305
|
userSelect: "none"
|
|
12246
12306
|
});
|
|
12307
|
+
this.applyIconSize(cfg.iconSize);
|
|
12247
12308
|
this.el.addEventListener("click", (e) => {
|
|
12248
12309
|
e.stopPropagation();
|
|
12249
12310
|
onClick();
|
|
@@ -12291,6 +12352,27 @@ var TradeButton = class {
|
|
|
12291
12352
|
right: `${priceAxisWidth + 26}px`
|
|
12292
12353
|
});
|
|
12293
12354
|
}
|
|
12355
|
+
/**
|
|
12356
|
+
* Toggle mobile sizing. When `isMobile` is true, the button diameter and
|
|
12357
|
+
* inner SVG icon are swapped for the configured mobile values; when false,
|
|
12358
|
+
* they revert to desktop values.
|
|
12359
|
+
*/
|
|
12360
|
+
setMobileMode(isMobile) {
|
|
12361
|
+
if (this._isMobile === isMobile) return;
|
|
12362
|
+
this._isMobile = isMobile;
|
|
12363
|
+
const size = isMobile ? this.cfg.mobileSize : this.cfg.size;
|
|
12364
|
+
const iconSize = isMobile ? this.cfg.mobileIconSize : this.cfg.iconSize;
|
|
12365
|
+
this.el.style.width = `${size}px`;
|
|
12366
|
+
this.el.style.height = `${size}px`;
|
|
12367
|
+
this.applyIconSize(iconSize);
|
|
12368
|
+
}
|
|
12369
|
+
applyIconSize(size) {
|
|
12370
|
+
const svg = this.el.querySelector("svg");
|
|
12371
|
+
if (svg) {
|
|
12372
|
+
svg.setAttribute("width", String(size));
|
|
12373
|
+
svg.setAttribute("height", String(size));
|
|
12374
|
+
}
|
|
12375
|
+
}
|
|
12294
12376
|
};
|
|
12295
12377
|
|
|
12296
12378
|
// src/ui/TradePopover.ts
|
|
@@ -16472,7 +16554,7 @@ var _ChartEngine = class _ChartEngine {
|
|
|
16472
16554
|
Math.min(Math.ceil(this.viewport.endIndex), Math.round(rawBarIndex))
|
|
16473
16555
|
);
|
|
16474
16556
|
const bar = this.dataStore.all[clamped] ?? null;
|
|
16475
|
-
this.crosshair = isInChartArea && !this.tradePopover?.isVisible ? { x, y, barIndex: clamped, price, bar } : null;
|
|
16557
|
+
this.crosshair = isInChartArea && !this.tradePopover?.isVisible && this.selectedTradeLabel === null ? { x, y, barIndex: clamped, price, bar } : null;
|
|
16476
16558
|
if (this.crosshair) this.emitter.emit("crosshair", this.crosshair);
|
|
16477
16559
|
const hoveringDotLevel = this.positionRenderStyle === "dot" && this.hoveredTradeLabel !== null;
|
|
16478
16560
|
if (this.tradeButton) {
|
|
@@ -16811,8 +16893,9 @@ var _ChartEngine = class _ChartEngine {
|
|
|
16811
16893
|
e.preventDefault();
|
|
16812
16894
|
const level = this.levels.find((l) => l.label === dragHit.label);
|
|
16813
16895
|
if (level) {
|
|
16814
|
-
const
|
|
16815
|
-
|
|
16896
|
+
const isAlreadySelected = this.selectedTradeLabel === level.label;
|
|
16897
|
+
const isMobileDraggable = dragHit.isBracket || level.type === "pending" && level.orderType !== "market" && (isAlreadySelected || !dragHit.isBox);
|
|
16898
|
+
if (this.hideLevelConfirmCancel && !isMobileDraggable) {
|
|
16816
16899
|
const hasPending = this.pendingLevelDrags.has(level.label);
|
|
16817
16900
|
if (this.selectedTradeLabel === level.label && !hasPending) {
|
|
16818
16901
|
this.selectedTradeLabel = null;
|
|
@@ -16990,7 +17073,7 @@ var _ChartEngine = class _ChartEngine {
|
|
|
16990
17073
|
Math.min(Math.ceil(this.viewport.endIndex), Math.round(rawBarIndex))
|
|
16991
17074
|
);
|
|
16992
17075
|
const bar = this.dataStore.all[clamped] ?? null;
|
|
16993
|
-
this.crosshair = { x, y, barIndex: clamped, price, bar };
|
|
17076
|
+
this.crosshair = this.selectedTradeLabel === null ? { x, y, barIndex: clamped, price, bar } : null;
|
|
16994
17077
|
if (this.tradeButton) {
|
|
16995
17078
|
this.tradeButton.setY(y);
|
|
16996
17079
|
if (this._isTradingActive) {
|
|
@@ -17600,30 +17683,32 @@ var _ChartEngine = class _ChartEngine {
|
|
|
17600
17683
|
padding: "0 2px"
|
|
17601
17684
|
});
|
|
17602
17685
|
this.canvasWrap.appendChild(this.textInputEl);
|
|
17603
|
-
|
|
17604
|
-
|
|
17605
|
-
|
|
17606
|
-
|
|
17607
|
-
|
|
17608
|
-
|
|
17609
|
-
|
|
17610
|
-
|
|
17611
|
-
|
|
17612
|
-
|
|
17613
|
-
|
|
17614
|
-
|
|
17615
|
-
|
|
17616
|
-
|
|
17617
|
-
|
|
17618
|
-
|
|
17619
|
-
|
|
17620
|
-
|
|
17621
|
-
|
|
17622
|
-
|
|
17623
|
-
|
|
17624
|
-
|
|
17625
|
-
|
|
17626
|
-
|
|
17686
|
+
if (showUI) {
|
|
17687
|
+
this.loadingOverlayEl = document.createElement("div");
|
|
17688
|
+
Object.assign(this.loadingOverlayEl.style, {
|
|
17689
|
+
display: "none",
|
|
17690
|
+
position: "absolute",
|
|
17691
|
+
top: "0",
|
|
17692
|
+
left: "0",
|
|
17693
|
+
width: "100%",
|
|
17694
|
+
height: "100%",
|
|
17695
|
+
alignItems: "center",
|
|
17696
|
+
justifyContent: "center",
|
|
17697
|
+
pointerEvents: "none",
|
|
17698
|
+
zIndex: "20"
|
|
17699
|
+
});
|
|
17700
|
+
const loadingLabel = document.createElement("span");
|
|
17701
|
+
loadingLabel.textContent = this.labels.chart.loading;
|
|
17702
|
+
Object.assign(loadingLabel.style, {
|
|
17703
|
+
color: "rgba(200,200,200,0.9)",
|
|
17704
|
+
fontSize: "13px",
|
|
17705
|
+
background: "rgba(0,0,0,0.45)",
|
|
17706
|
+
padding: "4px 12px",
|
|
17707
|
+
borderRadius: "4px"
|
|
17708
|
+
});
|
|
17709
|
+
this.loadingOverlayEl.appendChild(loadingLabel);
|
|
17710
|
+
this.canvasWrap.appendChild(this.loadingOverlayEl);
|
|
17711
|
+
}
|
|
17627
17712
|
if (showUI) {
|
|
17628
17713
|
this.siEl = document.createElement("div");
|
|
17629
17714
|
Object.assign(this.siEl.style, {
|
|
@@ -17755,7 +17840,8 @@ var _ChartEngine = class _ChartEngine {
|
|
|
17755
17840
|
);
|
|
17756
17841
|
}
|
|
17757
17842
|
},
|
|
17758
|
-
this.labels.trade
|
|
17843
|
+
this.labels.trade,
|
|
17844
|
+
this.uiConfig.tradeButton
|
|
17759
17845
|
);
|
|
17760
17846
|
this.canvasWrap.appendChild(this.tradeButton.el);
|
|
17761
17847
|
this.tradeButton.el.addEventListener("mouseenter", () => {
|
|
@@ -18355,6 +18441,30 @@ var _ChartEngine = class _ChartEngine {
|
|
|
18355
18441
|
this.emitStateChange();
|
|
18356
18442
|
return this;
|
|
18357
18443
|
}
|
|
18444
|
+
/** Programmatically change the active timeframe and reload data. */
|
|
18445
|
+
setTimeframe(tf) {
|
|
18446
|
+
this.timeframe = tf;
|
|
18447
|
+
this.topBar?.setTimeframe(tf);
|
|
18448
|
+
this.emitter.emit("timeframeChange", { timeframe: tf });
|
|
18449
|
+
this.emitStateChange();
|
|
18450
|
+
this.updateCountdownState();
|
|
18451
|
+
this.triggerLoad("timeframe");
|
|
18452
|
+
return this;
|
|
18453
|
+
}
|
|
18454
|
+
/** Update per-theme deep-partial color overrides and rebuild the active theme. */
|
|
18455
|
+
setThemeOverrides(overrides) {
|
|
18456
|
+
this.themeOverrides = overrides;
|
|
18457
|
+
this.theme = this.buildTheme(this.themeName);
|
|
18458
|
+
this.topBar?.setTheme(this.theme);
|
|
18459
|
+
this.bottomBar?.setTheme(this.theme);
|
|
18460
|
+
this.leftBar?.setTheme(this.theme);
|
|
18461
|
+
this.tradeButton?.setTheme(this.theme, this.priceAxisWidth);
|
|
18462
|
+
this.tradePopover?.setTheme(this.theme);
|
|
18463
|
+
this.indicatorSettingsDialog?.setTheme(this.theme);
|
|
18464
|
+
this.chartSettingsDialog?.setTheme(this.theme);
|
|
18465
|
+
this.scheduleRender();
|
|
18466
|
+
return this;
|
|
18467
|
+
}
|
|
18358
18468
|
setSeries(series) {
|
|
18359
18469
|
this.series = series;
|
|
18360
18470
|
this.topBar?.setSeries(series);
|
|
@@ -18883,8 +18993,10 @@ var _ChartEngine = class _ChartEngine {
|
|
|
18883
18993
|
addLevelBracket(label, type) {
|
|
18884
18994
|
const level = this.levels.find((l) => l.label === label);
|
|
18885
18995
|
if (!level) return this;
|
|
18886
|
-
const
|
|
18887
|
-
|
|
18996
|
+
const dragField = type === "sl" ? "stopLoss" : "takeProfit";
|
|
18997
|
+
const alreadyHasInLevel = type === "sl" ? level.stopLossPrice !== void 0 : level.takeProfitPrice !== void 0;
|
|
18998
|
+
const alreadyHasPending = this.pendingLevelDrags.get(label)?.some((c) => c.field === dragField && !c.isRemoval) ?? false;
|
|
18999
|
+
if (alreadyHasInLevel || alreadyHasPending) return this;
|
|
18888
19000
|
const { priceH } = this.getChartLayout();
|
|
18889
19001
|
const priceRange = this._displayedPriceRange ?? this.getScaledPriceRange(this.viewport);
|
|
18890
19002
|
const entryY = this.scaleManager.yToPixel(level.price, priceRange, priceH);
|
|
@@ -18893,6 +19005,10 @@ var _ChartEngine = class _ChartEngine {
|
|
|
18893
19005
|
const bracketY = entryY + (isBelowEntry ? 30 : -30);
|
|
18894
19006
|
const defaultPrice = this.scaleManager.pixelToPrice(bracketY, priceRange, priceH);
|
|
18895
19007
|
this.updateLevelBracket(label, type, defaultPrice);
|
|
19008
|
+
const existingDrags = this.pendingLevelDrags.get(label) ?? [];
|
|
19009
|
+
const filteredDrags = existingDrags.filter((c) => c.field !== dragField);
|
|
19010
|
+
filteredDrags.push({ field: dragField, newPrice: defaultPrice, oldPrice: defaultPrice, isNew: true });
|
|
19011
|
+
this.pendingLevelDrags.set(label, filteredDrags);
|
|
18896
19012
|
this.emitter.emit("tradeLevelBracketActivated", {
|
|
18897
19013
|
label,
|
|
18898
19014
|
bracketType: type,
|
|
@@ -18955,7 +19071,20 @@ var _ChartEngine = class _ChartEngine {
|
|
|
18955
19071
|
* No-op if the target doesn't exist or doesn't have the bracket type.
|
|
18956
19072
|
*/
|
|
18957
19073
|
removeBracket(type, label) {
|
|
18958
|
-
if (label)
|
|
19074
|
+
if (label) {
|
|
19075
|
+
const field = type === "sl" ? "stopLoss" : "takeProfit";
|
|
19076
|
+
const level = this.levels.find((l) => l.label === label);
|
|
19077
|
+
if (!level) return this;
|
|
19078
|
+
const existingChange = this.pendingLevelDrags.get(label)?.find((c) => c.field === field);
|
|
19079
|
+
const effectivePrice = existingChange && !existingChange.isRemoval ? existingChange.newPrice : type === "sl" ? level.stopLossPrice : level.takeProfitPrice;
|
|
19080
|
+
if (effectivePrice === void 0) return this;
|
|
19081
|
+
const existingDrags = this.pendingLevelDrags.get(label) ?? [];
|
|
19082
|
+
const filteredDrags = existingDrags.filter((c) => c.field !== field);
|
|
19083
|
+
filteredDrags.push({ field, newPrice: effectivePrice, oldPrice: effectivePrice, isRemoval: true });
|
|
19084
|
+
this.pendingLevelDrags.set(label, filteredDrags);
|
|
19085
|
+
this.renderTradeLayer();
|
|
19086
|
+
return this;
|
|
19087
|
+
}
|
|
18959
19088
|
if (type === "sl") {
|
|
18960
19089
|
this.draftBracketPnl = { ...this.draftBracketPnl, sl: void 0 };
|
|
18961
19090
|
} else {
|
|
@@ -18977,12 +19106,13 @@ var _ChartEngine = class _ChartEngine {
|
|
|
18977
19106
|
return this;
|
|
18978
19107
|
}
|
|
18979
19108
|
/**
|
|
18980
|
-
* Set or clear the estimated PNL text shown on
|
|
18981
|
-
*
|
|
19109
|
+
* Set or clear the estimated PNL text shown on the SL or TP bracket line.
|
|
19110
|
+
* Applies to the currently active bracket host — a draft order while drafting,
|
|
19111
|
+
* or the selected/hovered level while editing an existing pending order or position.
|
|
19112
|
+
* Pass `null` to clear the text.
|
|
18982
19113
|
* Use this to display the consumer-calculated estimated profit/loss next to the bracket.
|
|
18983
19114
|
*/
|
|
18984
19115
|
setDraftBracketPnl(type, pnlText) {
|
|
18985
|
-
if (!this.draftOrderLabel) return this;
|
|
18986
19116
|
if (type === "sl") {
|
|
18987
19117
|
this.draftBracketPnl = { ...this.draftBracketPnl, sl: pnlText ?? void 0 };
|
|
18988
19118
|
} else {
|
|
@@ -19060,6 +19190,7 @@ var _ChartEngine = class _ChartEngine {
|
|
|
19060
19190
|
*/
|
|
19061
19191
|
selectLevel(label) {
|
|
19062
19192
|
this.selectedTradeLabel = label;
|
|
19193
|
+
if (label !== null) this.crosshair = null;
|
|
19063
19194
|
this.renderTradeLayer();
|
|
19064
19195
|
return this;
|
|
19065
19196
|
}
|
|
@@ -19367,25 +19498,31 @@ var _ChartEngine = class _ChartEngine {
|
|
|
19367
19498
|
);
|
|
19368
19499
|
const processedLevels = this.levels.filter((l) => !(l.type === "pending" && l.ToClose != null)).map((l) => {
|
|
19369
19500
|
const draftChanges = this.pendingLevelDrags.get(l.label) ?? [];
|
|
19370
|
-
const
|
|
19371
|
-
const
|
|
19501
|
+
const slChange = draftChanges.find((c) => c.field === "stopLoss");
|
|
19502
|
+
const tpChange = draftChanges.find((c) => c.field === "takeProfit");
|
|
19503
|
+
const slDraft = slChange && !slChange.isRemoval ? slChange.newPrice : void 0;
|
|
19504
|
+
const tpDraft = tpChange && !tpChange.isRemoval ? tpChange.newPrice : void 0;
|
|
19505
|
+
const slIsRemoval = slChange?.isRemoval ?? false;
|
|
19506
|
+
const tpIsRemoval = tpChange?.isRemoval ?? false;
|
|
19372
19507
|
const mainDraft = draftChanges.find((c) => c.field === "main")?.newPrice;
|
|
19373
19508
|
const linked = bracketOrders.filter((b) => b.ToClose === l.label);
|
|
19374
|
-
if (linked.length === 0 && slDraft === void 0 && tpDraft === void 0 && mainDraft === void 0)
|
|
19509
|
+
if (linked.length === 0 && slDraft === void 0 && tpDraft === void 0 && mainDraft === void 0 && !slIsRemoval && !tpIsRemoval)
|
|
19375
19510
|
return l;
|
|
19376
19511
|
const clone = { ...l };
|
|
19377
19512
|
if (mainDraft !== void 0) clone.price = mainDraft;
|
|
19378
19513
|
if (slDraft !== void 0) clone.stopLossPrice = slDraft;
|
|
19514
|
+
else if (slIsRemoval) clone.stopLossPrice = void 0;
|
|
19379
19515
|
if (tpDraft !== void 0) clone.takeProfitPrice = tpDraft;
|
|
19516
|
+
else if (tpIsRemoval) clone.takeProfitPrice = void 0;
|
|
19380
19517
|
if (linked.length > 0) {
|
|
19381
19518
|
const parentSide = l.side ?? "buy";
|
|
19382
19519
|
for (const b of linked) {
|
|
19383
19520
|
const isSL = parentSide === "buy" ? b.price < l.price : b.price > l.price;
|
|
19384
19521
|
if (isSL) {
|
|
19385
|
-
clone.stopLossPrice = slDraft ?? clone.stopLossPrice ?? b.price;
|
|
19522
|
+
clone.stopLossPrice = slIsRemoval ? void 0 : slDraft ?? clone.stopLossPrice ?? b.price;
|
|
19386
19523
|
clone._slOrderLabel = b.label;
|
|
19387
19524
|
} else {
|
|
19388
|
-
clone.takeProfitPrice = tpDraft ?? clone.takeProfitPrice ?? b.price;
|
|
19525
|
+
clone.takeProfitPrice = tpIsRemoval ? void 0 : tpDraft ?? clone.takeProfitPrice ?? b.price;
|
|
19389
19526
|
clone._tpOrderLabel = b.label;
|
|
19390
19527
|
}
|
|
19391
19528
|
}
|
|
@@ -19447,8 +19584,9 @@ var _ChartEngine = class _ChartEngine {
|
|
|
19447
19584
|
const parentPrice = this._effectiveEntryPrice(result.label, level?.price ?? oldPrice);
|
|
19448
19585
|
const isEntryOrder = level?.entryPriceEditable === true;
|
|
19449
19586
|
const isDraft = level?.data?._isDraft === true;
|
|
19587
|
+
const isMobilePendingOrder = this.hideLevelConfirmCancel && result.type === "pending" && !isDraft;
|
|
19450
19588
|
const all = this.dataStore.all;
|
|
19451
|
-
const marketPrice = isEntryOrder || isDraft ? 0 : all[all.length - 1]?.close ?? 0;
|
|
19589
|
+
const marketPrice = isEntryOrder || isDraft || isMobilePendingOrder ? 0 : all[all.length - 1]?.close ?? 0;
|
|
19452
19590
|
if (!TradeDragHandler.isBracketPriceValid(
|
|
19453
19591
|
result.newPrice,
|
|
19454
19592
|
result.bracketType,
|
|
@@ -19578,16 +19716,14 @@ var _ChartEngine = class _ChartEngine {
|
|
|
19578
19716
|
if (!level) return;
|
|
19579
19717
|
if (label === this.draftOrderLabel) {
|
|
19580
19718
|
const mainEntry = changes.find((c) => c.field === "main");
|
|
19581
|
-
const slEntry = changes.find((c) => c.field === "stopLoss" && c.isNew);
|
|
19582
|
-
const tpEntry = changes.find((c) => c.field === "takeProfit" && c.isNew);
|
|
19583
19719
|
const draft = level;
|
|
19584
19720
|
this._onOrderSubmit?.({
|
|
19585
19721
|
price: mainEntry?.newPrice ?? draft.price,
|
|
19586
19722
|
lots: this._minLots,
|
|
19587
19723
|
side: draft.side,
|
|
19588
19724
|
orderType: draft.orderType,
|
|
19589
|
-
...
|
|
19590
|
-
...
|
|
19725
|
+
...draft.stopLossPrice !== void 0 ? { stopLoss: draft.stopLossPrice } : {},
|
|
19726
|
+
...draft.takeProfitPrice !== void 0 ? { takeProfit: draft.takeProfitPrice } : {}
|
|
19591
19727
|
});
|
|
19592
19728
|
this.emitter.emit("tradeLevelConfirmed", {
|
|
19593
19729
|
label,
|
|
@@ -20157,6 +20293,7 @@ var _ChartEngine = class _ChartEngine {
|
|
|
20157
20293
|
this._mobileLayout = isMobile;
|
|
20158
20294
|
this.leftBar?.setMobileMode(isMobile);
|
|
20159
20295
|
this.topBar?.setMobileLayout(isMobile);
|
|
20296
|
+
this.tradeButton?.setMobileMode(isMobile);
|
|
20160
20297
|
if (this.siEl) {
|
|
20161
20298
|
this.siEl.style.flexDirection = isMobile ? "column" : "row";
|
|
20162
20299
|
this.siEl.style.alignItems = isMobile ? "flex-start" : "center";
|
|
@@ -20259,24 +20396,20 @@ var _ChartEngine = class _ChartEngine {
|
|
|
20259
20396
|
const isDraftBracket = parentLevel?.data?._isDraft === true;
|
|
20260
20397
|
if (isDraftBracket && parentLevel) {
|
|
20261
20398
|
const bracketKey = closedLevel.bracketType === "stopLoss" ? "sl" : "tp";
|
|
20262
|
-
|
|
20263
|
-
|
|
20264
|
-
const entryY = this.scaleManager.yToPixel(
|
|
20265
|
-
parentLevel.price,
|
|
20266
|
-
priceRange,
|
|
20267
|
-
priceH
|
|
20268
|
-
);
|
|
20269
|
-
const side = parentLevel.side ?? "buy";
|
|
20270
|
-
const isBelowEntry = side === "buy" && bracketKey === "sl" || side === "sell" && bracketKey === "tp";
|
|
20271
|
-
const bracketY = entryY + (isBelowEntry ? 30 : -30);
|
|
20272
|
-
const defaultPrice = this.scaleManager.pixelToPrice(bracketY, priceRange, priceH);
|
|
20273
|
-
this.updateDraftOrderBracket(bracketKey, defaultPrice);
|
|
20274
|
-
this.emitter.emit("tradeLevelDrag", {
|
|
20399
|
+
this.updateDraftOrderBracket(bracketKey, null);
|
|
20400
|
+
this.emitter.emit("tradeLevelEdit", {
|
|
20275
20401
|
label: closedLevel.label,
|
|
20276
|
-
|
|
20277
|
-
data: parentLevel
|
|
20278
|
-
|
|
20279
|
-
|
|
20402
|
+
type: "pending",
|
|
20403
|
+
data: parentLevel.data,
|
|
20404
|
+
isFullscreen: this.isFullscreen,
|
|
20405
|
+
changes: [
|
|
20406
|
+
{
|
|
20407
|
+
field: closedLevel.bracketType === "stopLoss" ? "REMOVE_SL" : "REMOVE_TP",
|
|
20408
|
+
newPrice: 0,
|
|
20409
|
+
data: parentLevel.data,
|
|
20410
|
+
bracketOrderLabel: void 0
|
|
20411
|
+
}
|
|
20412
|
+
]
|
|
20280
20413
|
});
|
|
20281
20414
|
return;
|
|
20282
20415
|
}
|
|
@@ -20325,7 +20458,7 @@ var _ChartEngine = class _ChartEngine {
|
|
|
20325
20458
|
Math.min(Math.ceil(this.viewport.endIndex), Math.round(rawBarIndex))
|
|
20326
20459
|
);
|
|
20327
20460
|
const bar = this.dataStore.all[clamped] ?? null;
|
|
20328
|
-
this.crosshair = { x, y, barIndex: clamped, price, bar };
|
|
20461
|
+
this.crosshair = this.selectedTradeLabel === null ? { x, y, barIndex: clamped, price, bar } : null;
|
|
20329
20462
|
if (this.tradeButton) {
|
|
20330
20463
|
this.tradeButton.setY(y);
|
|
20331
20464
|
if (this._isTradingActive) {
|
|
@@ -20349,8 +20482,9 @@ var _ChartEngine = class _ChartEngine {
|
|
|
20349
20482
|
this._isBracketNew = false;
|
|
20350
20483
|
const isEntryOrder = level.entryPriceEditable === true;
|
|
20351
20484
|
const isDraft = level.data?._isDraft === true;
|
|
20485
|
+
const isMobilePendingOrder = this.hideLevelConfirmCancel && level.type === "pending" && !isDraft;
|
|
20352
20486
|
const all = this.dataStore.all;
|
|
20353
|
-
const marketPrice = isEntryOrder || isDraft ? 0 : all[all.length - 1]?.close ?? 0;
|
|
20487
|
+
const marketPrice = isEntryOrder || isDraft || isMobilePendingOrder ? 0 : all[all.length - 1]?.close ?? 0;
|
|
20354
20488
|
this.tradeDragHandler.startBracketDrag(
|
|
20355
20489
|
level,
|
|
20356
20490
|
dragHit.bracketType,
|
|
@@ -20408,20 +20542,9 @@ var _ChartEngine = class _ChartEngine {
|
|
|
20408
20542
|
const initialPrice = this.scaleManager.pixelToPrice(btnCenterY, priceRange, priceH);
|
|
20409
20543
|
const isEntryOrder = level.entryPriceEditable === true;
|
|
20410
20544
|
const isDraft = level.data?._isDraft === true;
|
|
20545
|
+
const isMobilePendingOrder = this.hideLevelConfirmCancel && level.type === "pending" && !isDraft;
|
|
20411
20546
|
const all = this.dataStore.all;
|
|
20412
|
-
const marketPrice = isEntryOrder || isDraft ? 0 : all[all.length - 1]?.close ?? 0;
|
|
20413
|
-
if (!isDraft) {
|
|
20414
|
-
this.emitter.emit("tradeLevelEditOpen", {
|
|
20415
|
-
label: level.label,
|
|
20416
|
-
type: level.type,
|
|
20417
|
-
data: level.data,
|
|
20418
|
-
price: level.price,
|
|
20419
|
-
side: level.side,
|
|
20420
|
-
stopLossPrice: level.stopLossPrice,
|
|
20421
|
-
takeProfitPrice: level.takeProfitPrice,
|
|
20422
|
-
isFullscreen: this.isFullscreen
|
|
20423
|
-
});
|
|
20424
|
-
}
|
|
20547
|
+
const marketPrice = isEntryOrder || isDraft || isMobilePendingOrder ? 0 : all[all.length - 1]?.close ?? 0;
|
|
20425
20548
|
this._pendingBracketOrderLabel = null;
|
|
20426
20549
|
this._isBracketNew = true;
|
|
20427
20550
|
this.tradeDragHandler.startBracketDrag(
|
|
@@ -20811,6 +20934,7 @@ exports.DEFAULT_LABELS = DEFAULT_LABELS;
|
|
|
20811
20934
|
exports.DEFAULT_PRICE_AXIS_CONFIG = DEFAULT_PRICE_AXIS_CONFIG;
|
|
20812
20935
|
exports.DEFAULT_TIME_AXIS_CONFIG = DEFAULT_TIME_AXIS_CONFIG;
|
|
20813
20936
|
exports.DEFAULT_TOP_BAR_CONFIG = DEFAULT_TOP_BAR_CONFIG;
|
|
20937
|
+
exports.DEFAULT_TRADE_BUTTON_CONFIG = DEFAULT_TRADE_BUTTON_CONFIG;
|
|
20814
20938
|
exports.DEFAULT_UI_CONFIG = DEFAULT_UI_CONFIG;
|
|
20815
20939
|
exports.DatePriceRange = DatePriceRange;
|
|
20816
20940
|
exports.DateRange = DateRange;
|