acttrader-charts 1.3.0-beta.6 → 1.3.0-beta.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -684,6 +684,9 @@ chart.loadData(newBars);
684
684
  chart.setSeries(series: SeriesType): this
685
685
  chart.setTheme('dark' | 'light'): this
686
686
  chart.setTimeframe(tf: Timeframe): this // change timeframe and reload data
687
+ chart.setDuration(d: Duration, timeframe?: Timeframe): this // select a duration; pairs the timeframe and reloads
688
+ chart.getDuration(): Duration | null // currently selected duration
689
+ chart.setBracketLabelMode(mode, currencySymbol?): this // SL/TP pills: 'price' (default) or 'amount'
687
690
  chart.setThemeOverrides(overrides: ThemeOverrides): this // update per-theme color overrides at runtime
688
691
  chart.setTimezone(tz: string): this // change display timezone at runtime
689
692
  chart.setVolume(show: boolean): this
@@ -888,6 +891,37 @@ Sub-pane heights are user-resizable by dragging the separator between panes.
888
891
  | `flatChannel` | Flat Channel | 2 clicks |
889
892
  | `disjointChannel` | Disjoint Channel | 3 clicks |
890
893
 
894
+ ### SL/TP bracket labels — price or amount
895
+
896
+ By default an SL/TP pill reads `SL 4159.00`. With `bracketLabelMode: 'amount'`
897
+ it reads `SL -$290.80` — the money the position gains or loses if that bracket
898
+ is hit, currency symbol in front.
899
+
900
+ The chart has no access to contract specs or the account currency, so each level
901
+ supplies what the maths needs:
902
+
903
+ ```ts
904
+ new ChartEngine({ container, bracketLabelMode: 'amount', currencySymbol: '$' });
905
+
906
+ chart.setLevels([{
907
+ label: 'POS-1', price: 4173.54, side: 'buy', lots: 0.20,
908
+ stopLossPrice: 4159.00, takeProfitPrice: 4183.00,
909
+ contractSize: 100, // units per lot (100 for XAUUSD, 100000 for most FX)
910
+ valuePerPoint: 1, // account-currency value of one price unit
911
+ currencySymbol: '$', // optional per-level override
912
+ }], 'label', 'price', 'position');
913
+ // pills render: SL -$290.80 TP +$189.20
914
+ ```
915
+
916
+ ```
917
+ amount = (bracket − entry) × direction × lots × contractSize × valuePerPoint
918
+ ```
919
+
920
+ `valuePerPoint` is where a quote → account currency conversion goes. A level
921
+ missing `lots` or `contractSize` keeps showing its price, so a partial rollout
922
+ degrades level by level rather than rendering `NaN`. Toggle at runtime with
923
+ `chart.setBracketLabelMode('amount')`.
924
+
891
925
  ### Fibonacci & Gann
892
926
 
893
927
  `fibRetracement` · `fibExtension` · `fibChannel` · `fibTimezone` · `fibCircles` · `fibSpiral` · `fibFan` · `fibProjection` · `gannFan` · `gannSquare` · `gannBox`
@@ -1009,8 +1009,11 @@ interface ChartConfig {
1009
1009
  * is hit — `SL -$290.80` — computed from the level's `lots`, `contractSize`
1010
1010
  * and `valuePerPoint`. Falls back to the price for any level lacking the
1011
1011
  * data needed to compute it, so a partial rollout degrades gracefully.
1012
+ * `'priceAndAmount'` keeps the price but puts the currency symbol in front
1013
+ * of it — `SL $1.27859` — and appends the P/L while the bracket is being
1014
+ * dragged: `SL $1.27859 -$29.08`.
1012
1015
  */
1013
- bracketLabelMode?: 'price' | 'amount';
1016
+ bracketLabelMode?: 'price' | 'amount' | 'priceAndAmount';
1014
1017
  /**
1015
1018
  * Currency symbol for SL/TP amounts, used when `bracketLabelMode: 'amount'`
1016
1019
  * and the level does not carry its own `currencySymbol`. Default `'$'`.
@@ -1009,8 +1009,11 @@ interface ChartConfig {
1009
1009
  * is hit — `SL -$290.80` — computed from the level's `lots`, `contractSize`
1010
1010
  * and `valuePerPoint`. Falls back to the price for any level lacking the
1011
1011
  * data needed to compute it, so a partial rollout degrades gracefully.
1012
+ * `'priceAndAmount'` keeps the price but puts the currency symbol in front
1013
+ * of it — `SL $1.27859` — and appends the P/L while the bracket is being
1014
+ * dragged: `SL $1.27859 -$29.08`.
1012
1015
  */
1013
- bracketLabelMode?: 'price' | 'amount';
1016
+ bracketLabelMode?: 'price' | 'amount' | 'priceAndAmount';
1014
1017
  /**
1015
1018
  * Currency symbol for SL/TP amounts, used when `bracketLabelMode: 'amount'`
1016
1019
  * and the level does not carry its own `currencySymbol`. Default `'$'`.
package/dist/index.cjs CHANGED
@@ -1906,10 +1906,12 @@ var BRACKET_BOX_PAD_Y = 3;
1906
1906
  var BRACKET_BOX_H = ROW_H + BRACKET_BOX_PAD_Y * 2;
1907
1907
  var FONT_BRACKET = "12px 'Inter', system-ui, sans-serif";
1908
1908
  var DEFAULT_BRACKET_LABEL = { mode: "price", currencySymbol: "$" };
1909
- function bracketBoxLabel(bracketType, price, precision, level, opts = DEFAULT_BRACKET_LABEL) {
1909
+ function bracketBoxLabel(bracketType, price, precision, level, opts = DEFAULT_BRACKET_LABEL, active = false) {
1910
1910
  const typeLabel = bracketType === "stopLoss" ? "SL" : "TP";
1911
- if (opts.mode === "amount" && level && level.side && typeof level.lots === "number") {
1912
- const amount = bracketPnl({
1911
+ const symbol = level?.currencySymbol ?? opts.currencySymbol;
1912
+ const amount = () => {
1913
+ if (!level || !level.side || typeof level.lots !== "number") return null;
1914
+ return bracketPnl({
1913
1915
  entryPrice: level.price,
1914
1916
  bracketPrice: price,
1915
1917
  side: level.side,
@@ -1917,9 +1919,16 @@ function bracketBoxLabel(bracketType, price, precision, level, opts = DEFAULT_BR
1917
1919
  contractSize: level.contractSize,
1918
1920
  valuePerPoint: level.valuePerPoint
1919
1921
  });
1920
- if (amount !== null) {
1921
- return `${typeLabel} ${formatMoney(amount, level.currencySymbol ?? opts.currencySymbol)}`;
1922
- }
1922
+ };
1923
+ if (opts.mode === "amount") {
1924
+ const pnl = amount();
1925
+ if (pnl !== null) return `${typeLabel} ${formatMoney(pnl, symbol)}`;
1926
+ }
1927
+ if (opts.mode === "priceAndAmount") {
1928
+ const priced = `${typeLabel} ${symbol}${price.toFixed(precision)}`;
1929
+ if (!active) return priced;
1930
+ const pnl = amount();
1931
+ return pnl === null ? priced : `${priced} ${formatMoney(pnl, symbol)}`;
1923
1932
  }
1924
1933
  return `${typeLabel} ${price.toFixed(precision)}`;
1925
1934
  }
@@ -2318,8 +2327,8 @@ function renderTradeLevels(ctx, levels, scale, priceRange, theme, chartW, priceH
2318
2327
  ctx.save();
2319
2328
  ctx.font = FONT_BRACKET;
2320
2329
  const closeSlot = CLOSE_R * 2 + BRACKET_BOX_PAD_X / 2;
2321
- const slBW = BRACKET_BOX_PAD_X + ctx.measureText(bracketBoxLabel("stopLoss", offSlPrice, precision, bh, bracketLabel)).width + BRACKET_BOX_PAD_X + closeSlot;
2322
- const tpBW = BRACKET_BOX_PAD_X + ctx.measureText(bracketBoxLabel("takeProfit", offTpPrice, precision, bh, bracketLabel)).width + BRACKET_BOX_PAD_X + closeSlot;
2330
+ const slBW = BRACKET_BOX_PAD_X + ctx.measureText(bracketBoxLabel("stopLoss", offSlPrice, precision, bh, bracketLabel, draggingLabel === slDragKey)).width + BRACKET_BOX_PAD_X + closeSlot;
2331
+ const tpBW = BRACKET_BOX_PAD_X + ctx.measureText(bracketBoxLabel("takeProfit", offTpPrice, precision, bh, bracketLabel, draggingLabel === tpDragKey)).width + BRACKET_BOX_PAD_X + closeSlot;
2323
2332
  ctx.restore();
2324
2333
  const connX = ((bracketLineXMap.get(slDragKey) ?? fallbackX) - slBW / 2 - 2 + ((bracketLineXMap.get(tpDragKey) ?? fallbackX) - tpBW / 2 - 2)) / 2;
2325
2334
  const slPillY = bracketBoxYMap.get(slDragKey) ?? slY - bracketBH / 2;
@@ -2642,8 +2651,8 @@ function drawLevel(ctx, level, layout, chartW, colors, theme, precision, hovered
2642
2651
  ctx.save();
2643
2652
  ctx.font = FONT_BRACKET;
2644
2653
  const closeSlot = hideConfirmCancel ? 0 : closeR * 2 + BRACKET_BOX_PAD_X / 2;
2645
- const slBW = BRACKET_BOX_PAD_X + ctx.measureText(bracketBoxLabel("stopLoss", slRenderPrice, precision, level, bracketLabel)).width + BRACKET_BOX_PAD_X + closeSlot;
2646
- const tpBW = BRACKET_BOX_PAD_X + ctx.measureText(bracketBoxLabel("takeProfit", tpRenderPrice, precision, level, bracketLabel)).width + BRACKET_BOX_PAD_X + closeSlot;
2654
+ const slBW = BRACKET_BOX_PAD_X + ctx.measureText(bracketBoxLabel("stopLoss", slRenderPrice, precision, level, bracketLabel, draggingLabel === slDragKey)).width + BRACKET_BOX_PAD_X + closeSlot;
2655
+ const tpBW = BRACKET_BOX_PAD_X + ctx.measureText(bracketBoxLabel("takeProfit", tpRenderPrice, precision, level, bracketLabel, draggingLabel === tpDragKey)).width + BRACKET_BOX_PAD_X + closeSlot;
2647
2656
  ctx.restore();
2648
2657
  const slBLineX = bracketLineXMap.get(slDragKey) ?? chartW * BRACKET_BASE_RATIO;
2649
2658
  const tpBLineX = bracketLineXMap.get(tpDragKey) ?? chartW * BRACKET_BASE_RATIO;
@@ -3083,7 +3092,7 @@ function drawBracketLine(ctx, level, bracketType, bracketPrice, scale, priceRang
3083
3092
  ctx.lineTo(chartW, y);
3084
3093
  ctx.stroke();
3085
3094
  ctx.globalAlpha = 1;
3086
- const boxLabel = bracketBoxLabel(bracketType, price, precision, level, bracketLabel);
3095
+ const boxLabel = bracketBoxLabel(bracketType, price, precision, level, bracketLabel, isDraggingThis);
3087
3096
  ctx.font = FONT_BRACKET;
3088
3097
  const textW = ctx.measureText(boxLabel).width;
3089
3098
  const pnlW = pnlText ? ctx.measureText(pnlText).width + BRACKET_BOX_PAD_X : 0;