@forgecharts/sdk 1.5.20 → 1.5.22

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/dist/internal.js CHANGED
@@ -1,4 +1,4 @@
1
- import { TextStyle, Application, Container, Graphics, Text, FillGradient } from 'pixi.js';
1
+ import { TextStyle, Application, Container, Graphics, Text, FillGradient, CanvasTextMetrics } from 'pixi.js';
2
2
  import { forwardRef, useRef, useState, useImperativeHandle, useEffect, useCallback, createContext, useMemo, useContext } from 'react';
3
3
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
4
4
  import ReactDOM from 'react-dom';
@@ -7771,9 +7771,11 @@ function orderRoleLabel(role) {
7771
7771
  }
7772
7772
  }
7773
7773
  function isDraggableRole(role) {
7774
- return role === "stop_loss" || role === "take_profit";
7774
+ return role === "stop_loss" || role === "take_profit" || role === "limit" || role === "stop";
7775
7775
  }
7776
7776
  var LINE_H = 15;
7777
+ var LABEL_GAP = 6;
7778
+ var LABEL_PAD = 6;
7777
7779
  var PILL_H = 16;
7778
7780
  var PILL_W = 28;
7779
7781
  var PILL_R = 4;
@@ -7940,13 +7942,18 @@ var PixiTradingRenderer = class {
7940
7942
  this._drawDragHandle(plotWidth - 26, y, color, alpha);
7941
7943
  }
7942
7944
  const boxY = y - LINE_H / 2;
7945
+ const roleStr = orderRoleLabel(order.role);
7946
+ const text = roleStr ? `${roleStr} ${order.qty}` : `${order.side.toUpperCase()} ${order.qty}`;
7947
+ const textW = Math.ceil(CanvasTextMetrics.measureText(text, labelStyle).width);
7948
+ const pillW = textW + LABEL_PAD * 2;
7949
+ const pillX = Math.max(0, plotWidth - LABEL_GAP - pillW);
7950
+ this._boxGfx.roundRect(pillX, boxY, pillW, LINE_H, PILL_R).fill({ color, alpha });
7951
+ labelIdx = this._drawLabel(text, pillX + pillW / 2, y, labelIdx, labelStyle, true);
7943
7952
  this._boxGfx.rect(plotWidth, boxY, psWidth, LINE_H).fill({ color, alpha });
7953
+ labelIdx = this._drawLabel(order.price.toFixed(2), plotWidth + 4, y, labelIdx, labelStyle);
7944
7954
  if (isDraggableRole(order.role)) {
7945
7955
  this._orderHitZones.push({ id: order.id, role: order.role, x: 0, y: boxY, w: plotWidth + psWidth, h: LINE_H });
7946
7956
  }
7947
- const roleStr = orderRoleLabel(order.role);
7948
- const text = roleStr && isDraggableRole(order.role) ? `${roleStr} ${order.price.toFixed(2)}` : roleStr ? `${roleStr} ${order.qty}` : `${order.side.toUpperCase()} ${order.qty}`;
7949
- labelIdx = this._drawLabel(text, plotWidth + 4, y, labelIdx, labelStyle);
7950
7957
  if (isEntry && !order.groupId && !bracketEntryIds.has(order.id)) {
7951
7958
  const tpPillY = y - PILL_H / 2;
7952
7959
  this._boxGfx.roundRect(PILL_TP_X, tpPillY, PILL_W, PILL_H, PILL_R).fill({ color: TP_PILL_COLOR, alpha: 0.85 });
@@ -8011,19 +8018,56 @@ var PixiTradingRenderer = class {
8011
8018
  }
8012
8019
  this._lineGfx.stroke();
8013
8020
  const boxY = y - LINE_H / 2;
8014
- this._boxGfx.rect(plotWidth, boxY, psWidth, LINE_H).fill({ color, alpha: 0.9 });
8015
- this._positionHitZones.push({ id: pos.id, x: plotWidth, y: boxY, w: psWidth, h: LINE_H });
8016
8021
  let text;
8017
8022
  if (pos.label) {
8018
8023
  text = pos.label;
8019
8024
  } else {
8020
- text = `Entry ${pos.entryPrice}`;
8025
+ text = `${pos.side.toUpperCase()} ${pos.qty}`;
8021
8026
  if (pos.unrealizedPnl !== void 0) {
8022
8027
  const pnlSign = pos.unrealizedPnl >= 0 ? "+" : "";
8023
8028
  text += ` ${pnlSign}${pos.unrealizedPnl.toFixed(2)}`;
8024
8029
  }
8025
8030
  }
8026
- labelIdx = this._drawLabel(text, plotWidth + 4, y, labelIdx, labelStyle);
8031
+ const textW = Math.ceil(CanvasTextMetrics.measureText(text, labelStyle).width);
8032
+ const pillW = textW + LABEL_PAD * 2;
8033
+ const pillX = Math.max(0, plotWidth - LABEL_GAP - pillW);
8034
+ this._boxGfx.roundRect(pillX, boxY, pillW, LINE_H, PILL_R).fill({ color, alpha: 0.9 });
8035
+ labelIdx = this._drawLabel(text, pillX + pillW / 2, y, labelIdx, labelStyle, true);
8036
+ this._boxGfx.rect(plotWidth, boxY, psWidth, LINE_H).fill({ color, alpha: 0.9 });
8037
+ labelIdx = this._drawLabel(String(pos.entryPrice), plotWidth + 4, y, labelIdx, labelStyle);
8038
+ this._positionHitZones.push({ id: pos.id, x: pillX, y: boxY, w: pillW, h: LINE_H });
8039
+ const linked = pos.linkedOrderIds ?? [];
8040
+ const hasTp = linked.some((id) => id.endsWith("-tp"));
8041
+ const hasSl = linked.some((id) => id.endsWith("-sl"));
8042
+ const entrySide = pos.side === "long" ? "buy" : "sell";
8043
+ if (!hasTp) {
8044
+ const tpY = y - PILL_H / 2;
8045
+ this._boxGfx.roundRect(PILL_TP_X, tpY, PILL_W, PILL_H, PILL_R).fill({ color: TP_PILL_COLOR, alpha: 0.85 });
8046
+ labelIdx = this._drawLabel("TP", PILL_TP_X + PILL_W / 2, y, labelIdx, pillLabelStyle, true);
8047
+ this._pillHitZones.push({
8048
+ kind: "tp",
8049
+ entryOrderId: pos.id,
8050
+ entrySide,
8051
+ x: PILL_TP_X,
8052
+ y: tpY,
8053
+ w: PILL_W,
8054
+ h: PILL_H
8055
+ });
8056
+ }
8057
+ if (!hasSl) {
8058
+ const slY = y - PILL_H / 2;
8059
+ this._boxGfx.roundRect(PILL_SL_X, slY, PILL_W, PILL_H, PILL_R).fill({ color: SL_PILL_COLOR, alpha: 0.85 });
8060
+ labelIdx = this._drawLabel("SL", PILL_SL_X + PILL_W / 2, y, labelIdx, pillLabelStyle, true);
8061
+ this._pillHitZones.push({
8062
+ kind: "sl",
8063
+ entryOrderId: pos.id,
8064
+ entrySide,
8065
+ x: PILL_SL_X,
8066
+ y: slY,
8067
+ w: PILL_W,
8068
+ h: PILL_H
8069
+ });
8070
+ }
8027
8071
  }
8028
8072
  }
8029
8073
  }
@@ -12015,6 +12059,24 @@ var TChart = class _TChart {
12015
12059
  this._bus.emit("symbolChanged", { symbol });
12016
12060
  if (symbol) this._connector?.reconnect(symbol, this._interval);
12017
12061
  }
12062
+ /**
12063
+ * Re-fetch history for the current symbol/interval without changing either.
12064
+ *
12065
+ * setSymbol and setInterval both no-op when the value is unchanged, so a host
12066
+ * whose datafeed reads external state per request — a trading-session filter
12067
+ * (RTH/ETH), a timezone, a contract roll rule — had no way to tell the chart
12068
+ * that state had changed. The next request would carry the new value, but
12069
+ * nothing triggered a request, so the toggle appeared dead until the user
12070
+ * panned or switched symbol.
12071
+ *
12072
+ * @public
12073
+ * @since 1.5.21
12074
+ */
12075
+ reloadData() {
12076
+ this._assertAlive();
12077
+ this._core.setDataBoundaryTime(null);
12078
+ this._connector?.reconnect(this._symbol, this._interval);
12079
+ }
12018
12080
  /** Per-symbol drawing store — swapped in/out on setSymbol (TV behavior). */
12019
12081
  _drawingsBySymbol = /* @__PURE__ */ new Map();
12020
12082
  /**
@@ -23015,6 +23077,12 @@ var ChartCanvas = forwardRef(
23015
23077
  getOverlayStore: () => chartRef.current?.getTradingOverlayStore() ?? null,
23016
23078
  selectPointerTool: (tool) => selectPointerToolRef.current(tool),
23017
23079
  getLastPrice: () => chartRef.current?.getLastPrice() ?? 0,
23080
+ /**
23081
+ * Re-fetch history without changing symbol or interval. For hosts whose
23082
+ * datafeed reads external state per request (RTH/ETH session filter,
23083
+ * timezone, roll rule) and needs the chart to ask again after it changes.
23084
+ */
23085
+ reloadData: () => chartRef.current?.reloadData(),
23018
23086
  captureScreenshot: async () => {
23019
23087
  const container = outerRef.current;
23020
23088
  if (!container) return null;
@@ -23157,7 +23225,11 @@ var ChartCanvas = forwardRef(
23157
23225
  type: "modify",
23158
23226
  orderId,
23159
23227
  symbol: symbolRef.current,
23160
- limitPrice: newPrice,
23228
+ // Route by role: a stop order's price is its TRIGGER, not a limit.
23229
+ // Sending limitPrice for a stop would modify the wrong field on the
23230
+ // broker (or be rejected), which matters now that stop orders are
23231
+ // draggable and not just bracket legs.
23232
+ ...order?.role === "stop" ? { stopPrice: newPrice } : { limitPrice: newPrice },
23161
23233
  timestamp: Date.now()
23162
23234
  });
23163
23235
  }