@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.
@@ -1,5 +1,5 @@
1
1
  import React11, { createContext, forwardRef, useRef, useState, useImperativeHandle, useEffect, useCallback, useMemo, useContext, useReducer } from 'react';
2
- import { TextStyle, Application, Container, Graphics, Text, FillGradient } from 'pixi.js';
2
+ import { TextStyle, Application, Container, Graphics, Text, FillGradient, CanvasTextMetrics } from 'pixi.js';
3
3
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
4
4
  import ReactDOM from 'react-dom';
5
5
 
@@ -7709,9 +7709,11 @@ function orderRoleLabel(role) {
7709
7709
  }
7710
7710
  }
7711
7711
  function isDraggableRole(role) {
7712
- return role === "stop_loss" || role === "take_profit";
7712
+ return role === "stop_loss" || role === "take_profit" || role === "limit" || role === "stop";
7713
7713
  }
7714
7714
  var LINE_H = 15;
7715
+ var LABEL_GAP = 6;
7716
+ var LABEL_PAD = 6;
7715
7717
  var PILL_H = 16;
7716
7718
  var PILL_W = 28;
7717
7719
  var PILL_R = 4;
@@ -7878,13 +7880,18 @@ var PixiTradingRenderer = class {
7878
7880
  this._drawDragHandle(plotWidth - 26, y, color, alpha);
7879
7881
  }
7880
7882
  const boxY = y - LINE_H / 2;
7883
+ const roleStr = orderRoleLabel(order.role);
7884
+ const text = roleStr ? `${roleStr} ${order.qty}` : `${order.side.toUpperCase()} ${order.qty}`;
7885
+ const textW = Math.ceil(CanvasTextMetrics.measureText(text, labelStyle).width);
7886
+ const pillW = textW + LABEL_PAD * 2;
7887
+ const pillX = Math.max(0, plotWidth - LABEL_GAP - pillW);
7888
+ this._boxGfx.roundRect(pillX, boxY, pillW, LINE_H, PILL_R).fill({ color, alpha });
7889
+ labelIdx = this._drawLabel(text, pillX + pillW / 2, y, labelIdx, labelStyle, true);
7881
7890
  this._boxGfx.rect(plotWidth, boxY, psWidth, LINE_H).fill({ color, alpha });
7891
+ labelIdx = this._drawLabel(order.price.toFixed(2), plotWidth + 4, y, labelIdx, labelStyle);
7882
7892
  if (isDraggableRole(order.role)) {
7883
7893
  this._orderHitZones.push({ id: order.id, role: order.role, x: 0, y: boxY, w: plotWidth + psWidth, h: LINE_H });
7884
7894
  }
7885
- const roleStr = orderRoleLabel(order.role);
7886
- const text = roleStr && isDraggableRole(order.role) ? `${roleStr} ${order.price.toFixed(2)}` : roleStr ? `${roleStr} ${order.qty}` : `${order.side.toUpperCase()} ${order.qty}`;
7887
- labelIdx = this._drawLabel(text, plotWidth + 4, y, labelIdx, labelStyle);
7888
7895
  if (isEntry && !order.groupId && !bracketEntryIds.has(order.id)) {
7889
7896
  const tpPillY = y - PILL_H / 2;
7890
7897
  this._boxGfx.roundRect(PILL_TP_X, tpPillY, PILL_W, PILL_H, PILL_R).fill({ color: TP_PILL_COLOR, alpha: 0.85 });
@@ -7949,19 +7956,56 @@ var PixiTradingRenderer = class {
7949
7956
  }
7950
7957
  this._lineGfx.stroke();
7951
7958
  const boxY = y - LINE_H / 2;
7952
- this._boxGfx.rect(plotWidth, boxY, psWidth, LINE_H).fill({ color, alpha: 0.9 });
7953
- this._positionHitZones.push({ id: pos.id, x: plotWidth, y: boxY, w: psWidth, h: LINE_H });
7954
7959
  let text;
7955
7960
  if (pos.label) {
7956
7961
  text = pos.label;
7957
7962
  } else {
7958
- text = `Entry ${pos.entryPrice}`;
7963
+ text = `${pos.side.toUpperCase()} ${pos.qty}`;
7959
7964
  if (pos.unrealizedPnl !== void 0) {
7960
7965
  const pnlSign = pos.unrealizedPnl >= 0 ? "+" : "";
7961
7966
  text += ` ${pnlSign}${pos.unrealizedPnl.toFixed(2)}`;
7962
7967
  }
7963
7968
  }
7964
- labelIdx = this._drawLabel(text, plotWidth + 4, y, labelIdx, labelStyle);
7969
+ const textW = Math.ceil(CanvasTextMetrics.measureText(text, labelStyle).width);
7970
+ const pillW = textW + LABEL_PAD * 2;
7971
+ const pillX = Math.max(0, plotWidth - LABEL_GAP - pillW);
7972
+ this._boxGfx.roundRect(pillX, boxY, pillW, LINE_H, PILL_R).fill({ color, alpha: 0.9 });
7973
+ labelIdx = this._drawLabel(text, pillX + pillW / 2, y, labelIdx, labelStyle, true);
7974
+ this._boxGfx.rect(plotWidth, boxY, psWidth, LINE_H).fill({ color, alpha: 0.9 });
7975
+ labelIdx = this._drawLabel(String(pos.entryPrice), plotWidth + 4, y, labelIdx, labelStyle);
7976
+ this._positionHitZones.push({ id: pos.id, x: pillX, y: boxY, w: pillW, h: LINE_H });
7977
+ const linked = pos.linkedOrderIds ?? [];
7978
+ const hasTp = linked.some((id) => id.endsWith("-tp"));
7979
+ const hasSl = linked.some((id) => id.endsWith("-sl"));
7980
+ const entrySide = pos.side === "long" ? "buy" : "sell";
7981
+ if (!hasTp) {
7982
+ const tpY = y - PILL_H / 2;
7983
+ this._boxGfx.roundRect(PILL_TP_X, tpY, PILL_W, PILL_H, PILL_R).fill({ color: TP_PILL_COLOR, alpha: 0.85 });
7984
+ labelIdx = this._drawLabel("TP", PILL_TP_X + PILL_W / 2, y, labelIdx, pillLabelStyle, true);
7985
+ this._pillHitZones.push({
7986
+ kind: "tp",
7987
+ entryOrderId: pos.id,
7988
+ entrySide,
7989
+ x: PILL_TP_X,
7990
+ y: tpY,
7991
+ w: PILL_W,
7992
+ h: PILL_H
7993
+ });
7994
+ }
7995
+ if (!hasSl) {
7996
+ const slY = y - PILL_H / 2;
7997
+ this._boxGfx.roundRect(PILL_SL_X, slY, PILL_W, PILL_H, PILL_R).fill({ color: SL_PILL_COLOR, alpha: 0.85 });
7998
+ labelIdx = this._drawLabel("SL", PILL_SL_X + PILL_W / 2, y, labelIdx, pillLabelStyle, true);
7999
+ this._pillHitZones.push({
8000
+ kind: "sl",
8001
+ entryOrderId: pos.id,
8002
+ entrySide,
8003
+ x: PILL_SL_X,
8004
+ y: slY,
8005
+ w: PILL_W,
8006
+ h: PILL_H
8007
+ });
8008
+ }
7965
8009
  }
7966
8010
  }
7967
8011
  }
@@ -11887,6 +11931,24 @@ var TChart = class _TChart {
11887
11931
  this._bus.emit("symbolChanged", { symbol });
11888
11932
  if (symbol) this._connector?.reconnect(symbol, this._interval);
11889
11933
  }
11934
+ /**
11935
+ * Re-fetch history for the current symbol/interval without changing either.
11936
+ *
11937
+ * setSymbol and setInterval both no-op when the value is unchanged, so a host
11938
+ * whose datafeed reads external state per request — a trading-session filter
11939
+ * (RTH/ETH), a timezone, a contract roll rule — had no way to tell the chart
11940
+ * that state had changed. The next request would carry the new value, but
11941
+ * nothing triggered a request, so the toggle appeared dead until the user
11942
+ * panned or switched symbol.
11943
+ *
11944
+ * @public
11945
+ * @since 1.5.21
11946
+ */
11947
+ reloadData() {
11948
+ this._assertAlive();
11949
+ this._core.setDataBoundaryTime(null);
11950
+ this._connector?.reconnect(this._symbol, this._interval);
11951
+ }
11890
11952
  /** Per-symbol drawing store — swapped in/out on setSymbol (TV behavior). */
11891
11953
  _drawingsBySymbol = /* @__PURE__ */ new Map();
11892
11954
  /**
@@ -22952,6 +23014,12 @@ var ChartCanvas = forwardRef(
22952
23014
  getOverlayStore: () => chartRef.current?.getTradingOverlayStore() ?? null,
22953
23015
  selectPointerTool: (tool) => selectPointerToolRef.current(tool),
22954
23016
  getLastPrice: () => chartRef.current?.getLastPrice() ?? 0,
23017
+ /**
23018
+ * Re-fetch history without changing symbol or interval. For hosts whose
23019
+ * datafeed reads external state per request (RTH/ETH session filter,
23020
+ * timezone, roll rule) and needs the chart to ask again after it changes.
23021
+ */
23022
+ reloadData: () => chartRef.current?.reloadData(),
22955
23023
  captureScreenshot: async () => {
22956
23024
  const container = outerRef.current;
22957
23025
  if (!container) return null;
@@ -23094,7 +23162,11 @@ var ChartCanvas = forwardRef(
23094
23162
  type: "modify",
23095
23163
  orderId,
23096
23164
  symbol: symbolRef.current,
23097
- limitPrice: newPrice,
23165
+ // Route by role: a stop order's price is its TRIGGER, not a limit.
23166
+ // Sending limitPrice for a stop would modify the wrong field on the
23167
+ // broker (or be rejected), which matters now that stop orders are
23168
+ // draggable and not just bracket legs.
23169
+ ...order?.role === "stop" ? { stopPrice: newPrice } : { limitPrice: newPrice },
23098
23170
  timestamp: Date.now()
23099
23171
  });
23100
23172
  }