acttrader-charts 1.3.0-beta.18 → 1.3.0-beta.19
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 +7 -2
- package/dist/{MACD-OBa3OUGO.d.cts → MACD-DDqzsv_V.d.cts} +6 -0
- package/dist/{MACD-OBa3OUGO.d.ts → MACD-DDqzsv_V.d.ts} +6 -0
- package/dist/index.cjs +50 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +13 -2
- package/dist/index.d.ts +13 -2
- package/dist/index.js +50 -7
- 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 +3 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -395,7 +395,9 @@ Alert | Pending | SL | TP | TSL | ×
|
|
|
395
395
|
row creates the draft order exactly as before and closes both.
|
|
396
396
|
- **SL / TP / TSL** emit `bulkLevelsRequested` with `{ kind, price }` and close the
|
|
397
397
|
bar — the host opens its Bulk Levels dialog pre-focused on that kind. The chart
|
|
398
|
-
never calls a broker.
|
|
398
|
+
never calls a broker. The chips grey out, with a tooltip saying why, when the
|
|
399
|
+
symbol has no open positions or has buys and sells open at once — one stop or
|
|
400
|
+
target price cannot sit on the right side of the market for both directions.
|
|
399
401
|
- **×**, a click elsewhere, Escape, TFC off and `dismissAllUI()` all close it.
|
|
400
402
|
|
|
401
403
|
Chip labels and the × tooltip live under `labels.trade` (`actionAlert`, `actionPending`,
|
|
@@ -424,7 +426,8 @@ the total without opening the positions panel:
|
|
|
424
426
|
- **◎** (the same target glyph as the Bulk Levels dialog header) emits
|
|
425
427
|
`bulkLevelsRequested` with `source: 'pill'` and a `null` price, so your Bulk Levels
|
|
426
428
|
dialog opens pre-scoped to every open position on the symbol. Tooltip:
|
|
427
|
-
"Set SL · TP · TSL on all N {symbol} positions".
|
|
429
|
+
"Set SL · TP · TSL on all N {symbol} positions". Greyed out while buys and sells are
|
|
430
|
+
both open ("Bulk levels need all N {symbol} positions in one direction").
|
|
428
431
|
- **✕** (amber) emits `pnlPillCloseAll` with every counted position. Your app
|
|
429
432
|
confirms and closes them; the chart never calls a broker.
|
|
430
433
|
|
|
@@ -825,10 +828,12 @@ new ChartEngine({
|
|
|
825
828
|
| `trade` | `actionAlert` … `actionTsl` | `'Alert'`, `'Pending'`, `'SL'`, `'TP'`, `'TSL'` | Trade action bar chips (`features.tradeActionBar`) |
|
|
826
829
|
| `trade` | `actionCloseTitle` | `'Close'` | Trade action bar × tooltip |
|
|
827
830
|
| `trade` | `directionAbove`, `directionBelow` | `'Above'`, `'Below'` | Pending sub-menu header — side of the market the clicked price is on |
|
|
831
|
+
| `trade` | `actionBulkNoPositionsTitle`, `actionBulkMixedTitle` | `'No open {symbol} positions'`, `'Bulk levels need all {symbol} positions in one direction'` | SL / TP / TSL chips greyed out — why |
|
|
828
832
|
| `pnlPill` | `positionsAbbrev` | `'POS'` | On-chart P/L pill — word after the count (`3 POS`), shown uppercase |
|
|
829
833
|
| `pnlPill` | `showPositionsTitle` | `'Show positions on chart · drag handle to move · double-click to reset'` | Pill tooltip while collapsed — a body click fans the positions out |
|
|
830
834
|
| `pnlPill` | `hidePositionsTitle` | `'Hide positions on chart · drag handle to move · double-click to reset'` | Pill tooltip while fanned out |
|
|
831
835
|
| `pnlPill` | `bulkLevelsTitle` | `'Set SL · TP · TSL on all {count} {symbol} positions'` | ◎ tooltip — opens the host's Bulk Levels dialog |
|
|
836
|
+
| `pnlPill` | `bulkLevelsMixedTitle` | `'Bulk levels need all {count} {symbol} positions in one direction'` | ◎ tooltip while greyed out for mixed sides |
|
|
832
837
|
| `pnlPill` | `closeAllTitle` | `'Close all {symbol} positions'` | Amber ✕ tooltip; `{symbol}` and `{count}` are filled in |
|
|
833
838
|
| `dialogs.settings` | `title` | `'Chart Settings'` | Dialog title |
|
|
834
839
|
| `dialogs.settings` | `tfcSection` | `'Trade from Charts'` | Section heading |
|
|
@@ -345,6 +345,10 @@ interface TradeLabels {
|
|
|
345
345
|
/** Pending sub-menu header: which side of the market the clicked price is on. */
|
|
346
346
|
directionAbove: string;
|
|
347
347
|
directionBelow: string;
|
|
348
|
+
/** SL / TP / TSL chips greyed out: no open positions on the symbol. `{symbol}` is filled in. */
|
|
349
|
+
actionBulkNoPositionsTitle: string;
|
|
350
|
+
/** SL / TP / TSL chips greyed out: buys and sells both open — one price cannot suit both. */
|
|
351
|
+
actionBulkMixedTitle: string;
|
|
348
352
|
}
|
|
349
353
|
interface DialogLabels {
|
|
350
354
|
/** Chart Settings dialog. */
|
|
@@ -402,6 +406,8 @@ interface PnlPillLabels {
|
|
|
402
406
|
hidePositionsTitle: string;
|
|
403
407
|
/** ◎ tooltip — it opens the host's Bulk Levels dialog. `{count}` and `{symbol}` are filled in. */
|
|
404
408
|
bulkLevelsTitle: string;
|
|
409
|
+
/** ◎ tooltip while greyed out because buys and sells are both open. */
|
|
410
|
+
bulkLevelsMixedTitle: string;
|
|
405
411
|
/** Amber ✕ tooltip. */
|
|
406
412
|
closeAllTitle: string;
|
|
407
413
|
}
|
|
@@ -345,6 +345,10 @@ interface TradeLabels {
|
|
|
345
345
|
/** Pending sub-menu header: which side of the market the clicked price is on. */
|
|
346
346
|
directionAbove: string;
|
|
347
347
|
directionBelow: string;
|
|
348
|
+
/** SL / TP / TSL chips greyed out: no open positions on the symbol. `{symbol}` is filled in. */
|
|
349
|
+
actionBulkNoPositionsTitle: string;
|
|
350
|
+
/** SL / TP / TSL chips greyed out: buys and sells both open — one price cannot suit both. */
|
|
351
|
+
actionBulkMixedTitle: string;
|
|
348
352
|
}
|
|
349
353
|
interface DialogLabels {
|
|
350
354
|
/** Chart Settings dialog. */
|
|
@@ -402,6 +406,8 @@ interface PnlPillLabels {
|
|
|
402
406
|
hidePositionsTitle: string;
|
|
403
407
|
/** ◎ tooltip — it opens the host's Bulk Levels dialog. `{count}` and `{symbol}` are filled in. */
|
|
404
408
|
bulkLevelsTitle: string;
|
|
409
|
+
/** ◎ tooltip while greyed out because buys and sells are both open. */
|
|
410
|
+
bulkLevelsMixedTitle: string;
|
|
405
411
|
/** Amber ✕ tooltip. */
|
|
406
412
|
closeAllTitle: string;
|
|
407
413
|
}
|
package/dist/index.cjs
CHANGED
|
@@ -745,6 +745,7 @@ var DEFAULT_LABELS = {
|
|
|
745
745
|
showPositionsTitle: "Show positions on chart \xB7 drag handle to move \xB7 double-click to reset",
|
|
746
746
|
hidePositionsTitle: "Hide positions on chart \xB7 drag handle to move \xB7 double-click to reset",
|
|
747
747
|
bulkLevelsTitle: "Set SL \xB7 TP \xB7 TSL on all {count} {symbol} positions",
|
|
748
|
+
bulkLevelsMixedTitle: "Bulk levels need all {count} {symbol} positions in one direction",
|
|
748
749
|
closeAllTitle: "Close all {symbol} positions"
|
|
749
750
|
},
|
|
750
751
|
topBar: {
|
|
@@ -933,7 +934,9 @@ var DEFAULT_LABELS = {
|
|
|
933
934
|
actionTsl: "TSL",
|
|
934
935
|
actionCloseTitle: "Close",
|
|
935
936
|
directionAbove: "Above",
|
|
936
|
-
directionBelow: "Below"
|
|
937
|
+
directionBelow: "Below",
|
|
938
|
+
actionBulkNoPositionsTitle: "No open {symbol} positions",
|
|
939
|
+
actionBulkMixedTitle: "Bulk levels need all {symbol} positions in one direction"
|
|
937
940
|
},
|
|
938
941
|
dialogs: {
|
|
939
942
|
settings: {
|
|
@@ -18278,18 +18281,22 @@ function summarisePositionLevels(levels, draftLabel = null) {
|
|
|
18278
18281
|
const positions = [];
|
|
18279
18282
|
let pnl = 0;
|
|
18280
18283
|
let hasPnl2 = false;
|
|
18284
|
+
let buys = 0;
|
|
18285
|
+
let sells = 0;
|
|
18281
18286
|
for (const level of levels) {
|
|
18282
18287
|
if (level.type !== "position") continue;
|
|
18283
18288
|
const position = level;
|
|
18284
18289
|
if (position.entryPriceEditable) continue;
|
|
18285
18290
|
if (draftLabel !== null && position.label === draftLabel) continue;
|
|
18286
18291
|
positions.push(position);
|
|
18292
|
+
if (position.side === "buy") buys++;
|
|
18293
|
+
else if (position.side === "sell") sells++;
|
|
18287
18294
|
if (typeof position.pnl === "number" && Number.isFinite(position.pnl)) {
|
|
18288
18295
|
pnl += position.pnl;
|
|
18289
18296
|
hasPnl2 = true;
|
|
18290
18297
|
}
|
|
18291
18298
|
}
|
|
18292
|
-
return { count: positions.length, pnl, hasPnl: hasPnl2, positions };
|
|
18299
|
+
return { count: positions.length, pnl, hasPnl: hasPnl2, positions, buys, sells, mixed: buys > 0 && sells > 0 };
|
|
18293
18300
|
}
|
|
18294
18301
|
function formatPnlPillValue(pnl, currency) {
|
|
18295
18302
|
const amount = Math.abs(pnl).toFixed(2);
|
|
@@ -18322,6 +18329,8 @@ var PnlPill = class {
|
|
|
18322
18329
|
this.lastSummary = null;
|
|
18323
18330
|
this.count = 0;
|
|
18324
18331
|
this.symbol = "";
|
|
18332
|
+
/** Buys and sells both open — ◎ is greyed out, one price cannot suit both. */
|
|
18333
|
+
this.mixed = false;
|
|
18325
18334
|
this.pnlTone = "none";
|
|
18326
18335
|
/** Set once the user has dragged; null means the default top-right spot. */
|
|
18327
18336
|
this.pos = null;
|
|
@@ -18496,6 +18505,7 @@ var PnlPill = class {
|
|
|
18496
18505
|
update(summary, symbol = "") {
|
|
18497
18506
|
this.count = summary.count;
|
|
18498
18507
|
this.symbol = symbol;
|
|
18508
|
+
this.mixed = summary.mixed;
|
|
18499
18509
|
this.lastSummary = summary;
|
|
18500
18510
|
if (summary.count === 0 || this.userHidden) {
|
|
18501
18511
|
this.el.style.display = "none";
|
|
@@ -18593,9 +18603,12 @@ var PnlPill = class {
|
|
|
18593
18603
|
}
|
|
18594
18604
|
applyTitles() {
|
|
18595
18605
|
this.el.title = this.fill(this.expanded ? this.labels.hidePositionsTitle : this.labels.showPositionsTitle);
|
|
18596
|
-
const bulk = this.fill(this.labels.bulkLevelsTitle);
|
|
18606
|
+
const bulk = this.fill(this.mixed ? this.labels.bulkLevelsMixedTitle : this.labels.bulkLevelsTitle);
|
|
18597
18607
|
this.toggleBtn.title = bulk;
|
|
18598
18608
|
this.toggleBtn.setAttribute("aria-label", bulk);
|
|
18609
|
+
this.toggleBtn.disabled = this.mixed;
|
|
18610
|
+
this.toggleBtn.setAttribute("aria-disabled", String(this.mixed));
|
|
18611
|
+
this.applyToggleColor();
|
|
18599
18612
|
const closeAll = this.fill(this.labels.closeAllTitle);
|
|
18600
18613
|
this.closeBtn.title = closeAll;
|
|
18601
18614
|
this.closeBtn.setAttribute("aria-label", closeAll);
|
|
@@ -18631,9 +18644,10 @@ var PnlPill = class {
|
|
|
18631
18644
|
const t = this.theme;
|
|
18632
18645
|
Object.assign(this.toggleBtn.style, {
|
|
18633
18646
|
color: t.ui.accent,
|
|
18634
|
-
background: withAlpha4(t.ui.accent, this.toggleHover ? 0.2 : 0.12),
|
|
18647
|
+
background: withAlpha4(t.ui.accent, this.toggleHover && !this.mixed ? 0.2 : 0.12),
|
|
18635
18648
|
border: "1px solid transparent",
|
|
18636
|
-
opacity: "1"
|
|
18649
|
+
opacity: this.mixed ? "0.4" : "1",
|
|
18650
|
+
cursor: this.mixed ? "not-allowed" : "pointer"
|
|
18637
18651
|
});
|
|
18638
18652
|
}
|
|
18639
18653
|
/* border-yellow-500/60, hover border-yellow-400 + bg-yellow-500/15; the ✕ is yellow-500. */
|
|
@@ -18851,6 +18865,7 @@ var TradeActionBar = class {
|
|
|
18851
18865
|
const wasVisible = this.isVisible;
|
|
18852
18866
|
this.price = price;
|
|
18853
18867
|
if (ctx) this.ctx = ctx;
|
|
18868
|
+
this.applyBulkAvailability();
|
|
18854
18869
|
this.closeSubmenu();
|
|
18855
18870
|
this.el.style.display = "block";
|
|
18856
18871
|
this.el.style.right = `${right}px`;
|
|
@@ -18909,11 +18924,34 @@ var TradeActionBar = class {
|
|
|
18909
18924
|
this.applyCloseColor();
|
|
18910
18925
|
}
|
|
18911
18926
|
/* Alert amber · Pending foreground/85 → primary on hover · SL/TSL negative · TP positive. */
|
|
18927
|
+
/*
|
|
18928
|
+
* SL / TP / TSL act on every open position of the symbol. With none there is
|
|
18929
|
+
* nothing to act on; with buys AND sells open, one stop or target price would
|
|
18930
|
+
* have to sit below the market for one side and above it for the other, so the
|
|
18931
|
+
* host's dialog could never accept it. Both states grey the chips out and say why.
|
|
18932
|
+
*/
|
|
18933
|
+
applyBulkAvailability() {
|
|
18934
|
+
const count = this.ctx.positionCount;
|
|
18935
|
+
const mixed = this.ctx.mixedSides === true;
|
|
18936
|
+
const unavailable = count === 0 || mixed;
|
|
18937
|
+
const symbol = this.ctx.symbol ?? "";
|
|
18938
|
+
const title = !unavailable ? "" : (count === 0 ? this.labels.actionBulkNoPositionsTitle : this.labels.actionBulkMixedTitle).replace(/\{symbol\}/g, symbol);
|
|
18939
|
+
for (const kind of ["sl", "tp", "tsl"]) {
|
|
18940
|
+
const btn = this.chips.get(kind);
|
|
18941
|
+
if (!btn) continue;
|
|
18942
|
+
btn.disabled = unavailable;
|
|
18943
|
+
btn.setAttribute("aria-disabled", String(unavailable));
|
|
18944
|
+
btn.title = title;
|
|
18945
|
+
btn.style.opacity = unavailable ? "0.4" : "1";
|
|
18946
|
+
btn.style.cursor = unavailable ? "not-allowed" : "pointer";
|
|
18947
|
+
this.applyChipColor(kind);
|
|
18948
|
+
}
|
|
18949
|
+
}
|
|
18912
18950
|
applyChipColor(kind) {
|
|
18913
18951
|
const btn = this.chips.get(kind);
|
|
18914
18952
|
if (!btn) return;
|
|
18915
18953
|
const t = this.theme;
|
|
18916
|
-
const hover = this.hovered === kind;
|
|
18954
|
+
const hover = this.hovered === kind && !btn.disabled;
|
|
18917
18955
|
let color;
|
|
18918
18956
|
let hoverBg;
|
|
18919
18957
|
switch (kind) {
|
|
@@ -26909,10 +26947,14 @@ var _ChartEngine = class _ChartEngine {
|
|
|
26909
26947
|
const { price, y } = this._tradeButtonClickData;
|
|
26910
26948
|
if (this.tradeActionBar) {
|
|
26911
26949
|
this.tradePopover.hide();
|
|
26950
|
+
const positions = summarisePositionLevels(this.levels, this.draftOrderLabel);
|
|
26912
26951
|
this.tradeActionBar.show(price, y, btnRight, {
|
|
26913
26952
|
pricePrecision: this.dataStore.getPricePrecision(),
|
|
26914
26953
|
buyOrderType: this._orderTypeForPrice("buy", price),
|
|
26915
|
-
sellOrderType: this._orderTypeForPrice("sell", price)
|
|
26954
|
+
sellOrderType: this._orderTypeForPrice("sell", price),
|
|
26955
|
+
symbol: this.symbol,
|
|
26956
|
+
positionCount: positions.count,
|
|
26957
|
+
mixedSides: positions.mixed
|
|
26916
26958
|
});
|
|
26917
26959
|
return;
|
|
26918
26960
|
}
|
|
@@ -27828,6 +27870,7 @@ var _ChartEngine = class _ChartEngine {
|
|
|
27828
27870
|
onToggleExpand: () => this.togglePnlPillExpanded(),
|
|
27829
27871
|
// ◎ hands every open position on the symbol to the host's Bulk Levels dialog.
|
|
27830
27872
|
onBulkLevels: () => {
|
|
27873
|
+
if (summarisePositionLevels(this.levels, this.draftOrderLabel).mixed) return;
|
|
27831
27874
|
this.emitter.emit("bulkLevelsRequested", {
|
|
27832
27875
|
kind: "sl",
|
|
27833
27876
|
price: null,
|