@orderly.network/ui-tradingview 2.11.2 → 2.12.0-alpha.0

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/index.d.mts CHANGED
@@ -15529,6 +15529,7 @@ interface DisplayControlSettingInterface {
15529
15529
  tpsl: boolean;
15530
15530
  positionTpsl: boolean;
15531
15531
  trailingStop: boolean;
15532
+ liquidationPrice: boolean;
15532
15533
  }
15533
15534
 
15534
15535
  declare const TradingviewWidget: React$1.ForwardRefExoticComponent<TradingviewWidgetPropsInterface & React$1.RefAttributes<HTMLDivElement>>;
package/dist/index.d.ts CHANGED
@@ -15529,6 +15529,7 @@ interface DisplayControlSettingInterface {
15529
15529
  tpsl: boolean;
15530
15530
  positionTpsl: boolean;
15531
15531
  trailingStop: boolean;
15532
+ liquidationPrice: boolean;
15532
15533
  }
15533
15534
 
15534
15535
  declare const TradingviewWidget: React$1.ForwardRefExoticComponent<TradingviewWidgetPropsInterface & React$1.RefAttributes<HTMLDivElement>>;
package/dist/index.js CHANGED
@@ -664,6 +664,10 @@ var init_displayControl_desktop = __esm({
664
664
  {
665
665
  label: t("orderEntry.orderType.trailingStop"),
666
666
  id: "trailingStop"
667
+ },
668
+ {
669
+ label: t("tradingView.displayControl.liquidationPrice"),
670
+ id: "liquidationPrice"
667
671
  }
668
672
  ];
669
673
  }, [t]);
@@ -725,7 +729,7 @@ var init_displayControl_desktop = __esm({
725
729
  {
726
730
  className: ui.cn(
727
731
  "oui-text-sm oui-text-base-contrast-80",
728
- !displayControlState[item.id] && "oui-text-base-contrast-36"
732
+ !(displayControlState[item.id] ?? true) && "oui-text-base-contrast-36"
729
733
  ),
730
734
  children: item.label
731
735
  }
@@ -734,7 +738,7 @@ var init_displayControl_desktop = __esm({
734
738
  ui.Switch,
735
739
  {
736
740
  className: "oui-h-4 oui-w-8",
737
- checked: displayControlState[item.id],
741
+ checked: displayControlState[item.id] ?? true,
738
742
  onCheckedChange: (checked) => {
739
743
  changeDisplayControlState({
740
744
  ...displayControlState,
@@ -799,8 +803,10 @@ var init_displayControl_mobile = __esm({
799
803
  label: t("orderEntry.orderType.trailingStop"),
800
804
  id: "trailingStop"
801
805
  },
802
- // placeholder
803
- {}
806
+ {
807
+ label: t("tradingView.displayControl.liquidationPrice"),
808
+ id: "liquidationPrice"
809
+ }
804
810
  ]
805
811
  ];
806
812
  }, [t]);
@@ -853,7 +859,7 @@ var init_displayControl_mobile = __esm({
853
859
  "oui-flex oui-h-6 oui-w-full oui-items-center oui-justify-between",
854
860
  "oui-rounded oui-px-2 oui-text-2xs",
855
861
  item.id && "oui-bg-base-5",
856
- props.displayControlState[item.id] ? "oui-text-base-contrast" : "oui-text-base-contrast-36"
862
+ props.displayControlState[item.id] ?? true ? "oui-text-base-contrast" : "oui-text-base-contrast-36"
857
863
  ),
858
864
  onClick: () => {
859
865
  if (!item.id) {
@@ -866,7 +872,7 @@ var init_displayControl_mobile = __esm({
866
872
  },
867
873
  children: item.id && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
868
874
  /* @__PURE__ */ jsxRuntime.jsx("div", { children: item.label }),
869
- props.displayControlState[item.id] ? /* @__PURE__ */ jsxRuntime.jsx(SelectedIcon, { className: "oui-size-3" }) : /* @__PURE__ */ jsxRuntime.jsx(UnSelectIcon, { className: "oui-size-3" })
875
+ props.displayControlState[item.id] ?? true ? /* @__PURE__ */ jsxRuntime.jsx(SelectedIcon, { className: "oui-size-3" }) : /* @__PURE__ */ jsxRuntime.jsx(UnSelectIcon, { className: "oui-size-3" })
870
876
  ] })
871
877
  },
872
878
  item.id || index
@@ -2747,41 +2753,42 @@ var ExecutionService = class _ExecutionService {
2747
2753
  };
2748
2754
  var LiquidationLineService = class {
2749
2755
  constructor(instance, broker) {
2750
- this.line = null;
2751
- /** Tracks whether the current line source is estimated liq. price (vs position liq. price). */
2752
- this.isUsingEstimatedPrice = false;
2756
+ /** Single temporary line driven by Order Entry estimated liquidation price. */
2757
+ this.estimatedLine = null;
2758
+ /** Persistent lines driven by current positions (can be multiple, e.g. cross + isolated). */
2759
+ this.positionLines = [];
2753
2760
  this.instance = instance;
2754
2761
  this.broker = broker;
2755
2762
  }
2756
2763
  /**
2757
- * Render or update the liquidation line. Call when position or estimated liq. price changes.
2764
+ * Render or update liquidation lines. Call when position or estimated liq. price changes.
2758
2765
  */
2759
2766
  renderLiquidationLine(params) {
2760
- const { positionLiqPrice, estimatedLiqPrice } = params;
2767
+ const { positionLiqItems, estimatedLiqPrice } = params;
2761
2768
  const hasValidEst = estimatedLiqPrice != null && Number.isFinite(estimatedLiqPrice);
2762
- const hasValidPosition = positionLiqPrice != null && Number.isFinite(positionLiqPrice);
2769
+ const validPositionItems = (positionLiqItems ?? []).filter(
2770
+ (item) => item != null && item.price != null && Number.isFinite(item.price)
2771
+ );
2763
2772
  if (hasValidEst) {
2764
- this.isUsingEstimatedPrice = true;
2765
- this.setLinePrice(estimatedLiqPrice);
2766
- this.line?.setLineStyle(1);
2773
+ this.removePositionLines();
2774
+ this.setEstimatedLinePrice(estimatedLiqPrice);
2775
+ this.estimatedLine?.setLineStyle(1);
2767
2776
  return;
2768
2777
  }
2769
- if (hasValidPosition) {
2770
- this.isUsingEstimatedPrice = false;
2771
- this.setLinePrice(positionLiqPrice);
2772
- this.line?.setLineStyle(0);
2778
+ this.removeEstimatedLine();
2779
+ if (validPositionItems.length > 0) {
2780
+ this.renderPositionLines(validPositionItems);
2773
2781
  return;
2774
2782
  }
2775
- this.removeLine();
2783
+ this.removePositionLines();
2776
2784
  }
2777
- /** Remove the line (e.g. on destroy). */
2785
+ /** Remove all liquidation lines (e.g. on destroy). */
2778
2786
  remove() {
2779
- this.removeLine();
2787
+ this.removeEstimatedLine();
2788
+ this.removePositionLines();
2780
2789
  }
2781
- getOrCreateLine() {
2782
- if (this.line != null) {
2783
- return this.line;
2784
- }
2790
+ /** Build a TradingView order line and apply shared style. */
2791
+ createBaseLine() {
2785
2792
  try {
2786
2793
  const activeChart = this.instance.activeChart();
2787
2794
  if (!activeChart) return null;
@@ -2790,41 +2797,93 @@ var LiquidationLineService = class {
2790
2797
  const colorConfig = this.broker.colorConfig;
2791
2798
  const lineColor = colorConfig.liqLineColor ?? colorConfig.textColor;
2792
2799
  if (!lineColor) return null;
2793
- this.line = orderLine.setCancellable(false).setLineLength(100).setEditable(false).setExtendLeft(true).setQuantity("").setLineStyle(1).setLineColor(lineColor).setBodyBorderColor(lineColor);
2794
- this.updateLineLabel();
2800
+ let line = orderLine.setCancellable(false).setLineLength(100).setEditable(false).setExtendLeft(true).setQuantity("").setLineStyle(0).setLineColor(lineColor).setBodyBorderColor(lineColor);
2795
2801
  if (colorConfig.chartBG) {
2796
- this.line = this.line.setBodyBackgroundColor(colorConfig.chartBG).setQuantityBackgroundColor(colorConfig.chartBG);
2802
+ line = line.setBodyBackgroundColor(colorConfig.chartBG).setQuantityBackgroundColor(colorConfig.chartBG);
2797
2803
  }
2798
2804
  if (colorConfig.textColor) {
2799
- this.line = this.line.setBodyTextColor(colorConfig.textColor);
2805
+ line = line.setBodyTextColor(colorConfig.textColor);
2800
2806
  }
2801
2807
  if (colorConfig.font) {
2802
- this.line = this.line.setBodyFont(colorConfig.font).setQuantityFont(colorConfig.font);
2808
+ line = line.setBodyFont(colorConfig.font).setQuantityFont(colorConfig.font);
2803
2809
  }
2804
- return this.line;
2810
+ return line;
2805
2811
  } catch {
2806
2812
  return null;
2807
2813
  }
2808
2814
  }
2809
- setLinePrice(price) {
2810
- const line = this.getOrCreateLine();
2815
+ /** Get or create the single estimated liquidation line. */
2816
+ getOrCreateEstimatedLine() {
2817
+ if (this.estimatedLine != null) {
2818
+ return this.estimatedLine;
2819
+ }
2820
+ const line = this.createBaseLine();
2821
+ if (line) {
2822
+ this.estimatedLine = line;
2823
+ this.updateLineLabel(line, true);
2824
+ }
2825
+ return line;
2826
+ }
2827
+ /** Get or create one position liquidation line by index. */
2828
+ getOrCreatePositionLine(index) {
2829
+ if (this.positionLines[index] != null) {
2830
+ return this.positionLines[index];
2831
+ }
2832
+ const line = this.createBaseLine();
2811
2833
  if (line) {
2812
- line.setPrice(price);
2813
- this.updateLineLabel();
2834
+ this.positionLines[index] = line;
2835
+ this.updateLineLabel(line, false);
2836
+ }
2837
+ return line;
2838
+ }
2839
+ /** Update estimated line price and metadata. */
2840
+ setEstimatedLinePrice(price) {
2841
+ const line = this.getOrCreateEstimatedLine();
2842
+ if (!line) return;
2843
+ line.setPrice(price);
2844
+ this.updateLineLabel(line, true);
2845
+ }
2846
+ /** Sync position lines to input items (create/update/remove extra lines). */
2847
+ renderPositionLines(items) {
2848
+ for (let i = 0; i < items.length; i += 1) {
2849
+ const line = this.getOrCreatePositionLine(i);
2850
+ if (!line) continue;
2851
+ line.setLineStyle(0);
2852
+ line.setPrice(items[i].price);
2853
+ this.updateLineLabel(line, false, items[i].marginMode, items[i].leverage);
2814
2854
  }
2855
+ for (let i = items.length; i < this.positionLines.length; i += 1) {
2856
+ this.positionLines[i]?.remove();
2857
+ }
2858
+ this.positionLines = this.positionLines.slice(0, items.length);
2815
2859
  }
2816
- removeLine() {
2817
- if (this.line) {
2818
- this.line.remove();
2819
- this.line = null;
2860
+ /** Remove the estimated line if it exists. */
2861
+ removeEstimatedLine() {
2862
+ if (this.estimatedLine) {
2863
+ this.estimatedLine.remove();
2864
+ this.estimatedLine = null;
2820
2865
  }
2821
2866
  }
2822
- /** Ensure tooltip/text reflect whether we are showing estimated or position liq. price. */
2823
- updateLineLabel() {
2824
- if (!this.line) return;
2825
- const key = this.isUsingEstimatedPrice ? "orderEntry.estLiqPrice" : "positions.column.liqPrice";
2826
- const label = i18n.i18n.t(key);
2827
- this.line.setTooltip(label).setText(label);
2867
+ /** Remove all position lines if they exist. */
2868
+ removePositionLines() {
2869
+ this.positionLines.forEach((line) => line.remove());
2870
+ this.positionLines = [];
2871
+ }
2872
+ /**
2873
+ * Ensure line tooltip/text reflect its source (estimated vs position + margin mode).
2874
+ * When showing margin mode, we also append leverage (if available) right after it.
2875
+ */
2876
+ updateLineLabel(line, isEstimated, marginMode, leverage) {
2877
+ const key = isEstimated ? "orderEntry.estLiqPrice" : "positions.column.liqPrice";
2878
+ let label = i18n.i18n.t(key);
2879
+ if (!isEstimated && marginMode) {
2880
+ const marginModeLabel = i18n.i18n.t(
2881
+ marginMode === "ISOLATED" ? "marginMode.isolated" : "marginMode.cross"
2882
+ );
2883
+ const leverageLabel = leverage != null && Number.isFinite(leverage) ? ` ${leverage}x` : "";
2884
+ label += ` (${marginModeLabel}${leverageLabel})`;
2885
+ }
2886
+ line.setTooltip(label).setText(label);
2828
2887
  }
2829
2888
  };
2830
2889
 
@@ -3240,7 +3299,11 @@ var PositionLineService = class _PositionLineService {
3240
3299
  );
3241
3300
  const quantity = _PositionLineService.getPositionQuantity(position.balance);
3242
3301
  if (needDrawMarginMode) {
3243
- text += ` (${position.marginMode === "ISOLATED" ? "Isolated" : "Cross"})`;
3302
+ const marginModeLabel = i18n.i18n.t(
3303
+ position.marginMode === "ISOLATED" ? "marginMode.isolated" : "marginMode.cross"
3304
+ );
3305
+ const leverageLabel = position.leverage != null && Number.isFinite(position.leverage) ? ` ${position.leverage}x` : "";
3306
+ text += ` (${marginModeLabel}${leverageLabel})`;
3244
3307
  }
3245
3308
  const line = this.positionLines[idx].setQuantity(quantity).setPrice(price).setCloseButtonIconColor(colorConfig.closeIcon).setCloseButtonBorderColor(sideColor).setBodyBackgroundColor(pnlColor).setQuantityTextColor(sideColor).setBodyBorderColor(pnlColor).setLineColor(sideColor).setQuantityBorderColor(sideColor).setText(text);
3246
3309
  if (colorConfig.closeIcon) {
@@ -3558,7 +3621,7 @@ var Renderer = class {
3558
3621
  this.orderLineService.updatePositions(positions);
3559
3622
  this.tpslService.updatePositions(positions);
3560
3623
  }
3561
- /** Update the single liquidation price line (position + optional estimated from Order Entry). */
3624
+ /** Update liquidation price lines (positions + optional estimated from Order Entry). */
3562
3625
  renderLiquidationLine(params) {
3563
3626
  this.liquidationLineService.renderLiquidationLine(params);
3564
3627
  }
@@ -3615,9 +3678,7 @@ function useCreateRenderer(symbol, displayControlSetting, marginMode) {
3615
3678
  });
3616
3679
  const positions = React3.useMemo(() => {
3617
3680
  if (!rows?.length) return [];
3618
- return rows.filter(
3619
- (item) => item.symbol === symbol && (marginMode == null || item.margin_mode === marginMode)
3620
- );
3681
+ return rows.filter((item) => item.symbol === symbol);
3621
3682
  }, [rows, symbol, marginMode]);
3622
3683
  const [pendingOrders] = hooks.useOrderStream({
3623
3684
  status: types.OrderStatus.INCOMPLETE,
@@ -3662,6 +3723,7 @@ function useCreateRenderer(symbol, displayControlSetting, marginMode) {
3662
3723
  symbol: item.symbol,
3663
3724
  open: item.average_open_price,
3664
3725
  balance: item.position_qty,
3726
+ leverage: item.leverage,
3665
3727
  closablePosition: 9999,
3666
3728
  // @ts-ignore
3667
3729
  unrealPnl: item.unrealized_pnl ?? 0,
@@ -3688,11 +3750,24 @@ function useCreateRenderer(symbol, displayControlSetting, marginMode) {
3688
3750
  }, [ee, symbol]);
3689
3751
  React3.useEffect(() => {
3690
3752
  if (!renderer || !displayControlSetting?.position) return;
3691
- const symbolPosition = (positions ?? []).find((p) => p.symbol === symbol);
3692
- const positionLiqPrice = symbolPosition != null ? symbolPosition.est_liq_price ?? null : null;
3753
+ const positionLiqItems = (positions ?? []).filter((p) => p.symbol === symbol).flatMap((p) => {
3754
+ const price = p.est_liq_price;
3755
+ const leverage = p.leverage;
3756
+ if (price == null || !Number.isFinite(price)) {
3757
+ return [];
3758
+ }
3759
+ return [
3760
+ {
3761
+ price,
3762
+ marginMode: p.margin_mode,
3763
+ leverage: leverage ?? void 0
3764
+ }
3765
+ ];
3766
+ });
3693
3767
  const effectiveEstimatedLiqPrice = estimatedLiqPrice != null && Number.isFinite(estimatedLiqPrice) ? estimatedLiqPrice : null;
3768
+ const showPositionLiqItems = displayControlSetting?.liquidationPrice !== false ? positionLiqItems : [];
3694
3769
  renderer.renderLiquidationLine({
3695
- positionLiqPrice,
3770
+ positionLiqItems: showPositionLiqItems,
3696
3771
  estimatedLiqPrice: effectiveEstimatedLiqPrice
3697
3772
  });
3698
3773
  }, [
@@ -3700,7 +3775,8 @@ function useCreateRenderer(symbol, displayControlSetting, marginMode) {
3700
3775
  positions,
3701
3776
  symbol,
3702
3777
  estimatedLiqPrice,
3703
- displayControlSetting?.position
3778
+ displayControlSetting?.position,
3779
+ displayControlSetting?.liquidationPrice
3704
3780
  ]);
3705
3781
  React3.useEffect(() => {
3706
3782
  if (!displayControlSetting || !displayControlSetting.buySell) {
@@ -4321,7 +4397,8 @@ function useTradingviewScript(props) {
4321
4397
  stopOrders: true,
4322
4398
  tpsl: true,
4323
4399
  positionTpsl: true,
4324
- trailingStop: true
4400
+ trailingStop: true,
4401
+ liquidationPrice: true
4325
4402
  };
4326
4403
  });
4327
4404
  const [interval, setInterval] = React3.useState(() => {