@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.mjs CHANGED
@@ -658,6 +658,10 @@ var init_displayControl_desktop = __esm({
658
658
  {
659
659
  label: t("orderEntry.orderType.trailingStop"),
660
660
  id: "trailingStop"
661
+ },
662
+ {
663
+ label: t("tradingView.displayControl.liquidationPrice"),
664
+ id: "liquidationPrice"
661
665
  }
662
666
  ];
663
667
  }, [t]);
@@ -719,7 +723,7 @@ var init_displayControl_desktop = __esm({
719
723
  {
720
724
  className: cn(
721
725
  "oui-text-sm oui-text-base-contrast-80",
722
- !displayControlState[item.id] && "oui-text-base-contrast-36"
726
+ !(displayControlState[item.id] ?? true) && "oui-text-base-contrast-36"
723
727
  ),
724
728
  children: item.label
725
729
  }
@@ -728,7 +732,7 @@ var init_displayControl_desktop = __esm({
728
732
  Switch,
729
733
  {
730
734
  className: "oui-h-4 oui-w-8",
731
- checked: displayControlState[item.id],
735
+ checked: displayControlState[item.id] ?? true,
732
736
  onCheckedChange: (checked) => {
733
737
  changeDisplayControlState({
734
738
  ...displayControlState,
@@ -793,8 +797,10 @@ var init_displayControl_mobile = __esm({
793
797
  label: t("orderEntry.orderType.trailingStop"),
794
798
  id: "trailingStop"
795
799
  },
796
- // placeholder
797
- {}
800
+ {
801
+ label: t("tradingView.displayControl.liquidationPrice"),
802
+ id: "liquidationPrice"
803
+ }
798
804
  ]
799
805
  ];
800
806
  }, [t]);
@@ -847,7 +853,7 @@ var init_displayControl_mobile = __esm({
847
853
  "oui-flex oui-h-6 oui-w-full oui-items-center oui-justify-between",
848
854
  "oui-rounded oui-px-2 oui-text-2xs",
849
855
  item.id && "oui-bg-base-5",
850
- props.displayControlState[item.id] ? "oui-text-base-contrast" : "oui-text-base-contrast-36"
856
+ props.displayControlState[item.id] ?? true ? "oui-text-base-contrast" : "oui-text-base-contrast-36"
851
857
  ),
852
858
  onClick: () => {
853
859
  if (!item.id) {
@@ -860,7 +866,7 @@ var init_displayControl_mobile = __esm({
860
866
  },
861
867
  children: item.id && /* @__PURE__ */ jsxs(Fragment, { children: [
862
868
  /* @__PURE__ */ jsx("div", { children: item.label }),
863
- props.displayControlState[item.id] ? /* @__PURE__ */ jsx(SelectedIcon, { className: "oui-size-3" }) : /* @__PURE__ */ jsx(UnSelectIcon, { className: "oui-size-3" })
869
+ props.displayControlState[item.id] ?? true ? /* @__PURE__ */ jsx(SelectedIcon, { className: "oui-size-3" }) : /* @__PURE__ */ jsx(UnSelectIcon, { className: "oui-size-3" })
864
870
  ] })
865
871
  },
866
872
  item.id || index
@@ -2741,41 +2747,42 @@ var ExecutionService = class _ExecutionService {
2741
2747
  };
2742
2748
  var LiquidationLineService = class {
2743
2749
  constructor(instance, broker) {
2744
- this.line = null;
2745
- /** Tracks whether the current line source is estimated liq. price (vs position liq. price). */
2746
- this.isUsingEstimatedPrice = false;
2750
+ /** Single temporary line driven by Order Entry estimated liquidation price. */
2751
+ this.estimatedLine = null;
2752
+ /** Persistent lines driven by current positions (can be multiple, e.g. cross + isolated). */
2753
+ this.positionLines = [];
2747
2754
  this.instance = instance;
2748
2755
  this.broker = broker;
2749
2756
  }
2750
2757
  /**
2751
- * Render or update the liquidation line. Call when position or estimated liq. price changes.
2758
+ * Render or update liquidation lines. Call when position or estimated liq. price changes.
2752
2759
  */
2753
2760
  renderLiquidationLine(params) {
2754
- const { positionLiqPrice, estimatedLiqPrice } = params;
2761
+ const { positionLiqItems, estimatedLiqPrice } = params;
2755
2762
  const hasValidEst = estimatedLiqPrice != null && Number.isFinite(estimatedLiqPrice);
2756
- const hasValidPosition = positionLiqPrice != null && Number.isFinite(positionLiqPrice);
2763
+ const validPositionItems = (positionLiqItems ?? []).filter(
2764
+ (item) => item != null && item.price != null && Number.isFinite(item.price)
2765
+ );
2757
2766
  if (hasValidEst) {
2758
- this.isUsingEstimatedPrice = true;
2759
- this.setLinePrice(estimatedLiqPrice);
2760
- this.line?.setLineStyle(1);
2767
+ this.removePositionLines();
2768
+ this.setEstimatedLinePrice(estimatedLiqPrice);
2769
+ this.estimatedLine?.setLineStyle(1);
2761
2770
  return;
2762
2771
  }
2763
- if (hasValidPosition) {
2764
- this.isUsingEstimatedPrice = false;
2765
- this.setLinePrice(positionLiqPrice);
2766
- this.line?.setLineStyle(0);
2772
+ this.removeEstimatedLine();
2773
+ if (validPositionItems.length > 0) {
2774
+ this.renderPositionLines(validPositionItems);
2767
2775
  return;
2768
2776
  }
2769
- this.removeLine();
2777
+ this.removePositionLines();
2770
2778
  }
2771
- /** Remove the line (e.g. on destroy). */
2779
+ /** Remove all liquidation lines (e.g. on destroy). */
2772
2780
  remove() {
2773
- this.removeLine();
2781
+ this.removeEstimatedLine();
2782
+ this.removePositionLines();
2774
2783
  }
2775
- getOrCreateLine() {
2776
- if (this.line != null) {
2777
- return this.line;
2778
- }
2784
+ /** Build a TradingView order line and apply shared style. */
2785
+ createBaseLine() {
2779
2786
  try {
2780
2787
  const activeChart = this.instance.activeChart();
2781
2788
  if (!activeChart) return null;
@@ -2784,41 +2791,93 @@ var LiquidationLineService = class {
2784
2791
  const colorConfig = this.broker.colorConfig;
2785
2792
  const lineColor = colorConfig.liqLineColor ?? colorConfig.textColor;
2786
2793
  if (!lineColor) return null;
2787
- this.line = orderLine.setCancellable(false).setLineLength(100).setEditable(false).setExtendLeft(true).setQuantity("").setLineStyle(1).setLineColor(lineColor).setBodyBorderColor(lineColor);
2788
- this.updateLineLabel();
2794
+ let line = orderLine.setCancellable(false).setLineLength(100).setEditable(false).setExtendLeft(true).setQuantity("").setLineStyle(0).setLineColor(lineColor).setBodyBorderColor(lineColor);
2789
2795
  if (colorConfig.chartBG) {
2790
- this.line = this.line.setBodyBackgroundColor(colorConfig.chartBG).setQuantityBackgroundColor(colorConfig.chartBG);
2796
+ line = line.setBodyBackgroundColor(colorConfig.chartBG).setQuantityBackgroundColor(colorConfig.chartBG);
2791
2797
  }
2792
2798
  if (colorConfig.textColor) {
2793
- this.line = this.line.setBodyTextColor(colorConfig.textColor);
2799
+ line = line.setBodyTextColor(colorConfig.textColor);
2794
2800
  }
2795
2801
  if (colorConfig.font) {
2796
- this.line = this.line.setBodyFont(colorConfig.font).setQuantityFont(colorConfig.font);
2802
+ line = line.setBodyFont(colorConfig.font).setQuantityFont(colorConfig.font);
2797
2803
  }
2798
- return this.line;
2804
+ return line;
2799
2805
  } catch {
2800
2806
  return null;
2801
2807
  }
2802
2808
  }
2803
- setLinePrice(price) {
2804
- const line = this.getOrCreateLine();
2809
+ /** Get or create the single estimated liquidation line. */
2810
+ getOrCreateEstimatedLine() {
2811
+ if (this.estimatedLine != null) {
2812
+ return this.estimatedLine;
2813
+ }
2814
+ const line = this.createBaseLine();
2815
+ if (line) {
2816
+ this.estimatedLine = line;
2817
+ this.updateLineLabel(line, true);
2818
+ }
2819
+ return line;
2820
+ }
2821
+ /** Get or create one position liquidation line by index. */
2822
+ getOrCreatePositionLine(index) {
2823
+ if (this.positionLines[index] != null) {
2824
+ return this.positionLines[index];
2825
+ }
2826
+ const line = this.createBaseLine();
2805
2827
  if (line) {
2806
- line.setPrice(price);
2807
- this.updateLineLabel();
2828
+ this.positionLines[index] = line;
2829
+ this.updateLineLabel(line, false);
2830
+ }
2831
+ return line;
2832
+ }
2833
+ /** Update estimated line price and metadata. */
2834
+ setEstimatedLinePrice(price) {
2835
+ const line = this.getOrCreateEstimatedLine();
2836
+ if (!line) return;
2837
+ line.setPrice(price);
2838
+ this.updateLineLabel(line, true);
2839
+ }
2840
+ /** Sync position lines to input items (create/update/remove extra lines). */
2841
+ renderPositionLines(items) {
2842
+ for (let i = 0; i < items.length; i += 1) {
2843
+ const line = this.getOrCreatePositionLine(i);
2844
+ if (!line) continue;
2845
+ line.setLineStyle(0);
2846
+ line.setPrice(items[i].price);
2847
+ this.updateLineLabel(line, false, items[i].marginMode, items[i].leverage);
2808
2848
  }
2849
+ for (let i = items.length; i < this.positionLines.length; i += 1) {
2850
+ this.positionLines[i]?.remove();
2851
+ }
2852
+ this.positionLines = this.positionLines.slice(0, items.length);
2809
2853
  }
2810
- removeLine() {
2811
- if (this.line) {
2812
- this.line.remove();
2813
- this.line = null;
2854
+ /** Remove the estimated line if it exists. */
2855
+ removeEstimatedLine() {
2856
+ if (this.estimatedLine) {
2857
+ this.estimatedLine.remove();
2858
+ this.estimatedLine = null;
2814
2859
  }
2815
2860
  }
2816
- /** Ensure tooltip/text reflect whether we are showing estimated or position liq. price. */
2817
- updateLineLabel() {
2818
- if (!this.line) return;
2819
- const key = this.isUsingEstimatedPrice ? "orderEntry.estLiqPrice" : "positions.column.liqPrice";
2820
- const label = i18n.t(key);
2821
- this.line.setTooltip(label).setText(label);
2861
+ /** Remove all position lines if they exist. */
2862
+ removePositionLines() {
2863
+ this.positionLines.forEach((line) => line.remove());
2864
+ this.positionLines = [];
2865
+ }
2866
+ /**
2867
+ * Ensure line tooltip/text reflect its source (estimated vs position + margin mode).
2868
+ * When showing margin mode, we also append leverage (if available) right after it.
2869
+ */
2870
+ updateLineLabel(line, isEstimated, marginMode, leverage) {
2871
+ const key = isEstimated ? "orderEntry.estLiqPrice" : "positions.column.liqPrice";
2872
+ let label = i18n.t(key);
2873
+ if (!isEstimated && marginMode) {
2874
+ const marginModeLabel = i18n.t(
2875
+ marginMode === "ISOLATED" ? "marginMode.isolated" : "marginMode.cross"
2876
+ );
2877
+ const leverageLabel = leverage != null && Number.isFinite(leverage) ? ` ${leverage}x` : "";
2878
+ label += ` (${marginModeLabel}${leverageLabel})`;
2879
+ }
2880
+ line.setTooltip(label).setText(label);
2822
2881
  }
2823
2882
  };
2824
2883
 
@@ -3234,7 +3293,11 @@ var PositionLineService = class _PositionLineService {
3234
3293
  );
3235
3294
  const quantity = _PositionLineService.getPositionQuantity(position.balance);
3236
3295
  if (needDrawMarginMode) {
3237
- text += ` (${position.marginMode === "ISOLATED" ? "Isolated" : "Cross"})`;
3296
+ const marginModeLabel = i18n.t(
3297
+ position.marginMode === "ISOLATED" ? "marginMode.isolated" : "marginMode.cross"
3298
+ );
3299
+ const leverageLabel = position.leverage != null && Number.isFinite(position.leverage) ? ` ${position.leverage}x` : "";
3300
+ text += ` (${marginModeLabel}${leverageLabel})`;
3238
3301
  }
3239
3302
  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);
3240
3303
  if (colorConfig.closeIcon) {
@@ -3552,7 +3615,7 @@ var Renderer = class {
3552
3615
  this.orderLineService.updatePositions(positions);
3553
3616
  this.tpslService.updatePositions(positions);
3554
3617
  }
3555
- /** Update the single liquidation price line (position + optional estimated from Order Entry). */
3618
+ /** Update liquidation price lines (positions + optional estimated from Order Entry). */
3556
3619
  renderLiquidationLine(params) {
3557
3620
  this.liquidationLineService.renderLiquidationLine(params);
3558
3621
  }
@@ -3609,9 +3672,7 @@ function useCreateRenderer(symbol, displayControlSetting, marginMode) {
3609
3672
  });
3610
3673
  const positions = useMemo(() => {
3611
3674
  if (!rows?.length) return [];
3612
- return rows.filter(
3613
- (item) => item.symbol === symbol && (marginMode == null || item.margin_mode === marginMode)
3614
- );
3675
+ return rows.filter((item) => item.symbol === symbol);
3615
3676
  }, [rows, symbol, marginMode]);
3616
3677
  const [pendingOrders] = useOrderStream({
3617
3678
  status: OrderStatus.INCOMPLETE,
@@ -3656,6 +3717,7 @@ function useCreateRenderer(symbol, displayControlSetting, marginMode) {
3656
3717
  symbol: item.symbol,
3657
3718
  open: item.average_open_price,
3658
3719
  balance: item.position_qty,
3720
+ leverage: item.leverage,
3659
3721
  closablePosition: 9999,
3660
3722
  // @ts-ignore
3661
3723
  unrealPnl: item.unrealized_pnl ?? 0,
@@ -3682,11 +3744,24 @@ function useCreateRenderer(symbol, displayControlSetting, marginMode) {
3682
3744
  }, [ee, symbol]);
3683
3745
  useEffect(() => {
3684
3746
  if (!renderer || !displayControlSetting?.position) return;
3685
- const symbolPosition = (positions ?? []).find((p) => p.symbol === symbol);
3686
- const positionLiqPrice = symbolPosition != null ? symbolPosition.est_liq_price ?? null : null;
3747
+ const positionLiqItems = (positions ?? []).filter((p) => p.symbol === symbol).flatMap((p) => {
3748
+ const price = p.est_liq_price;
3749
+ const leverage = p.leverage;
3750
+ if (price == null || !Number.isFinite(price)) {
3751
+ return [];
3752
+ }
3753
+ return [
3754
+ {
3755
+ price,
3756
+ marginMode: p.margin_mode,
3757
+ leverage: leverage ?? void 0
3758
+ }
3759
+ ];
3760
+ });
3687
3761
  const effectiveEstimatedLiqPrice = estimatedLiqPrice != null && Number.isFinite(estimatedLiqPrice) ? estimatedLiqPrice : null;
3762
+ const showPositionLiqItems = displayControlSetting?.liquidationPrice !== false ? positionLiqItems : [];
3688
3763
  renderer.renderLiquidationLine({
3689
- positionLiqPrice,
3764
+ positionLiqItems: showPositionLiqItems,
3690
3765
  estimatedLiqPrice: effectiveEstimatedLiqPrice
3691
3766
  });
3692
3767
  }, [
@@ -3694,7 +3769,8 @@ function useCreateRenderer(symbol, displayControlSetting, marginMode) {
3694
3769
  positions,
3695
3770
  symbol,
3696
3771
  estimatedLiqPrice,
3697
- displayControlSetting?.position
3772
+ displayControlSetting?.position,
3773
+ displayControlSetting?.liquidationPrice
3698
3774
  ]);
3699
3775
  useEffect(() => {
3700
3776
  if (!displayControlSetting || !displayControlSetting.buySell) {
@@ -4315,7 +4391,8 @@ function useTradingviewScript(props) {
4315
4391
  stopOrders: true,
4316
4392
  tpsl: true,
4317
4393
  positionTpsl: true,
4318
- trailingStop: true
4394
+ trailingStop: true,
4395
+ liquidationPrice: true
4319
4396
  };
4320
4397
  });
4321
4398
  const [interval, setInterval] = useState(() => {