@orderly.network/ui-positions 2.8.5 → 2.8.6-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
@@ -1,17 +1,17 @@
1
- import { registerSimpleDialog, Flex, Text, CloseIcon, Button, ThrottledButton, useScreen, Grid, Statistic, ExclamationFillIcon, modal, Tooltip, DataTable, cn, ListView, SimpleSheet, SimpleDialog, usePagination, DataFilter, toast, Badge, formatAddress, Box, HoverCard, Divider, capitalizeFirstLetter, ShareIcon, EditIcon, Input, inputFormatter, Select, PopoverRoot, PopoverTrigger, PopoverContent, Slider } from '@orderly.network/ui';
2
- import React, { createContext, useContext, useCallback, useMemo, useState, useEffect, useRef } from 'react';
3
- import { useTranslation, i18n } from '@orderly.network/i18n';
4
- import { EMPTY_LIST, AccountStatusEnum, OrderSide, OrderType, TrackerEventName, PositionType, AlgoOrderType } from '@orderly.network/types';
1
+ import { registerSimpleDialog, useModal, SimpleDialog, Flex, Text, toast, Badge, Divider, CloseIcon, Button, ThrottledButton, useScreen, ArrowDownShortIcon, ArrowUpShortIcon, Grid, Statistic, ExclamationFillIcon, modal, Tooltip, DataTable, cn, ListView, SimpleSheet, usePagination, DataFilter, formatAddress, Box, HoverCard, ArrowLeftRightIcon, capitalizeFirstLetter, ShareIcon, EditIcon, Input, inputFormatter, Select, PopoverRoot, PopoverTrigger, PopoverContent, Slider } from '@orderly.network/ui';
2
+ import React2, { createContext, useMemo, useCallback, useContext, useState, useEffect, useRef } from 'react';
3
+ import { i18n, useTranslation } from '@orderly.network/i18n';
4
+ import { OrderSide, OrderType, EMPTY_LIST, AccountStatusEnum, TrackerEventName, PositionType, AlgoOrderType } from '@orderly.network/types';
5
5
  import { commifyOptional, Decimal, formatNum, getTimestamp, commify } from '@orderly.network/utils';
6
- import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
7
- import { usePrivateInfiniteQuery, useBoolean, useSessionStorage, useAccount, usePrivateQuery, useTrack, usePositionStream, useSubAccountMutation, useSymbolsInfo, usePositionClose, useSWR, fetcher, useGetRwaSymbolOpenStatus, useLocalStorage, useConfig, useReferralInfo, useAccountInfo, useLeverageBySymbol, utils, useMaxLeverage } from '@orderly.network/hooks';
6
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
7
+ import { useSymbolsInfo, useMarkPrice, useMaxQty, useSubAccountMutation, useLocalStorage, usePrivateInfiniteQuery, useBoolean, useSessionStorage, useAccount, usePrivateQuery, useTrack, usePositionStream, usePositionClose, useSWR, fetcher, useGetRwaSymbolOpenStatus, useTpslPriceChecker, useConfig, useReferralInfo, useAccountInfo, useLeverageBySymbol, utils, useMaxLeverage } from '@orderly.network/hooks';
8
8
  import { produce } from 'immer';
9
9
  import { positions, account } from '@orderly.network/perp';
10
10
  import { useDataTap, useOrderEntryFormErrorMsg } from '@orderly.network/react-app';
11
11
  import { AuthGuardDataTable } from '@orderly.network/ui-connector';
12
12
  import { SymbolLeverageDialogId, SymbolLeverageSheetId } from '@orderly.network/ui-leverage';
13
13
  import { SharePnLDialogId, SharePnLBottomSheetId } from '@orderly.network/ui-share';
14
- import { TPSLSheetId, TPSLDialogId, TPSLDetailSheetId, TPSLDetailDialogId } from '@orderly.network/ui-tpsl';
14
+ import { CloseToLiqPriceIcon, TPSLSheetId, TPSLDialogId, TPSLDetailSheetId, TPSLDetailDialogId } from '@orderly.network/ui-tpsl';
15
15
  import { subDays, differenceInDays } from 'date-fns';
16
16
 
17
17
  // src/index.ts
@@ -870,6 +870,404 @@ function useSort(initialSort, onSortChange) {
870
870
  getSortedList
871
871
  };
872
872
  }
873
+ var OrderInfoCard = ({
874
+ title,
875
+ side,
876
+ leverage,
877
+ qty,
878
+ baseDp,
879
+ estLiqPrice,
880
+ className
881
+ }) => {
882
+ const { t } = useTranslation();
883
+ return /* @__PURE__ */ jsxs(
884
+ Flex,
885
+ {
886
+ direction: "column",
887
+ gap: 3,
888
+ itemAlign: "start",
889
+ className: `oui-bg-base-6 oui-rounded-lg oui-p-3 oui-w-full oui-font-weight-semibold ${className || ""}`,
890
+ children: [
891
+ /* @__PURE__ */ jsxs(Flex, { justify: "between", itemAlign: "center", gap: 2, children: [
892
+ /* @__PURE__ */ jsx(Text, { size: "sm", weight: "semibold", intensity: 98, children: title }),
893
+ /* @__PURE__ */ jsxs(Flex, { itemAlign: "center", gap: 1, children: [
894
+ /* @__PURE__ */ jsx(Badge, { color: side === OrderSide.SELL ? "sell" : "buy", size: "xs", children: side === OrderSide.SELL ? t("common.sell") : t("common.buy") }),
895
+ /* @__PURE__ */ jsxs(Badge, { color: "neutral", size: "xs", children: [
896
+ leverage,
897
+ "X"
898
+ ] })
899
+ ] })
900
+ ] }),
901
+ /* @__PURE__ */ jsxs(
902
+ Flex,
903
+ {
904
+ direction: "column",
905
+ justify: "between",
906
+ itemAlign: "center",
907
+ width: "100%",
908
+ children: [
909
+ /* @__PURE__ */ jsxs(
910
+ Flex,
911
+ {
912
+ direction: "row",
913
+ justify: "between",
914
+ itemAlign: "center",
915
+ width: "100%",
916
+ gap: 1,
917
+ children: [
918
+ /* @__PURE__ */ jsx(Text, { size: "sm", intensity: 54, children: t("common.qty") }),
919
+ /* @__PURE__ */ jsx(Text.numeral, { dp: baseDp, size: "sm", color: "danger", padding: false, children: qty })
920
+ ]
921
+ }
922
+ ),
923
+ /* @__PURE__ */ jsxs(
924
+ Flex,
925
+ {
926
+ direction: "row",
927
+ justify: "between",
928
+ itemAlign: "center",
929
+ width: "100%",
930
+ gap: 1,
931
+ children: [
932
+ /* @__PURE__ */ jsx(Text, { size: "sm", intensity: 54, children: t("common.price") }),
933
+ /* @__PURE__ */ jsx(Text, { size: "sm", weight: "semibold", children: t("common.market") })
934
+ ]
935
+ }
936
+ ),
937
+ estLiqPrice && /* @__PURE__ */ jsxs(
938
+ Flex,
939
+ {
940
+ direction: "row",
941
+ justify: "between",
942
+ itemAlign: "center",
943
+ width: "100%",
944
+ gap: 1,
945
+ children: [
946
+ /* @__PURE__ */ jsx(Text, { size: "sm", intensity: 54, children: t("orderEntry.estLiqPrice") }),
947
+ /* @__PURE__ */ jsx(Text, { size: "sm", weight: "semibold", children: estLiqPrice })
948
+ ]
949
+ }
950
+ )
951
+ ]
952
+ }
953
+ )
954
+ ]
955
+ }
956
+ );
957
+ };
958
+ var ReversePosition = (props) => {
959
+ const { displayInfo, className, style, onConfirm, onCancel } = props;
960
+ const { t } = useTranslation();
961
+ if (!displayInfo) {
962
+ return null;
963
+ }
964
+ const {
965
+ symbol,
966
+ base,
967
+ quote,
968
+ baseDp,
969
+ quoteDp,
970
+ positionQty,
971
+ reverseQty,
972
+ markPrice,
973
+ leverage,
974
+ isLong
975
+ } = displayInfo;
976
+ const closeSide = !isLong ? OrderSide.SELL : OrderSide.BUY;
977
+ const openSide = isLong ? OrderSide.SELL : OrderSide.BUY;
978
+ const closeAction = isLong ? t("positions.reverse.marketCloseLong") : t("positions.reverse.marketCloseShort");
979
+ const openAction = openSide === OrderSide.BUY ? t("positions.reverse.marketOpenLong") : t("positions.reverse.marketOpenShort");
980
+ const reverseTo = isLong ? t("positions.reverse.reverseToShort") : t("positions.reverse.reverseToLong");
981
+ const reverseToIcon = isLong ? /* @__PURE__ */ jsx(ArrowDownShortIcon, { size: 16, color: "danger", opacity: 1 }) : /* @__PURE__ */ jsx(ArrowUpShortIcon, { size: 16, color: "success", opacity: 1 });
982
+ const priceLabel = /* @__PURE__ */ jsxs(Flex, { itemAlign: "center", gap: 1, children: [
983
+ /* @__PURE__ */ jsx(Text.numeral, { dp: quoteDp, size: "sm", intensity: 80, children: markPrice }),
984
+ /* @__PURE__ */ jsx(Text, { size: "sm", intensity: 36, children: quote })
985
+ ] });
986
+ return /* @__PURE__ */ jsxs(
987
+ Flex,
988
+ {
989
+ direction: "column",
990
+ className,
991
+ style,
992
+ gap: 4,
993
+ width: "100%",
994
+ children: [
995
+ /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 2, width: "100%", children: [
996
+ /* @__PURE__ */ jsxs(Flex, { justify: "between", itemAlign: "center", width: "100%", children: [
997
+ /* @__PURE__ */ jsx(
998
+ Text.formatted,
999
+ {
1000
+ size: "base",
1001
+ weight: "semibold",
1002
+ rule: "symbol",
1003
+ formatString: "base-type",
1004
+ intensity: 98,
1005
+ showIcon: true,
1006
+ children: symbol
1007
+ }
1008
+ ),
1009
+ /* @__PURE__ */ jsx(Badge, { color: isLong ? "sell" : "buy", size: "xs", children: reverseTo })
1010
+ ] }),
1011
+ /* @__PURE__ */ jsxs(Flex, { justify: "between", itemAlign: "center", width: "100%", children: [
1012
+ /* @__PURE__ */ jsx(Text, { size: "sm", intensity: 54, children: t("common.markPrice") }),
1013
+ priceLabel
1014
+ ] })
1015
+ ] }),
1016
+ /* @__PURE__ */ jsx(Divider, { intensity: 4, className: "oui-w-full" }),
1017
+ /* @__PURE__ */ jsx(
1018
+ OrderInfoCard,
1019
+ {
1020
+ title: closeAction,
1021
+ side: closeSide,
1022
+ leverage,
1023
+ qty: positionQty,
1024
+ baseDp
1025
+ }
1026
+ ),
1027
+ /* @__PURE__ */ jsxs(Flex, { direction: "row", itemAlign: "center", width: "100%", children: [
1028
+ /* @__PURE__ */ jsx(Divider, { intensity: 8, className: "oui-w-full" }),
1029
+ /* @__PURE__ */ jsxs(Flex, { className: "oui-px-4 oui-py-[3px] oui-border oui-border-base-contrast-12 oui-rounded-full oui-shrink-0", children: [
1030
+ reverseToIcon,
1031
+ /* @__PURE__ */ jsx(Text, { size: "2xs", color: isLong ? "danger" : "success", children: reverseTo })
1032
+ ] }),
1033
+ /* @__PURE__ */ jsx(Divider, { intensity: 8, className: "oui-w-full" })
1034
+ ] }),
1035
+ /* @__PURE__ */ jsx(
1036
+ OrderInfoCard,
1037
+ {
1038
+ title: openAction,
1039
+ side: openSide,
1040
+ leverage,
1041
+ qty: reverseQty,
1042
+ baseDp
1043
+ }
1044
+ ),
1045
+ /* @__PURE__ */ jsx(Text, { size: "2xs", color: "warning", weight: "semibold", children: t("positions.reverse.description") })
1046
+ ]
1047
+ }
1048
+ );
1049
+ };
1050
+ var useReversePositionEnabled = () => {
1051
+ const { isMobile, isDesktop } = useScreen();
1052
+ const [desktopEnabled, setDesktopEnabled] = useLocalStorage(
1053
+ "orderly_reverse_position_enabled_desktop",
1054
+ true
1055
+ );
1056
+ const [mobileEnabled, setMobileEnabled] = useLocalStorage(
1057
+ "orderly_reverse_position_enabled_mobile",
1058
+ false
1059
+ );
1060
+ const isEnabled = useMemo(() => {
1061
+ if (isMobile) {
1062
+ return mobileEnabled;
1063
+ }
1064
+ if (isDesktop) {
1065
+ return desktopEnabled;
1066
+ }
1067
+ return false;
1068
+ }, [isMobile, isDesktop, desktopEnabled, mobileEnabled]);
1069
+ const setEnabled = useCallback(
1070
+ (enabled) => {
1071
+ if (isMobile) {
1072
+ setMobileEnabled(enabled);
1073
+ } else if (isDesktop) {
1074
+ setDesktopEnabled(enabled);
1075
+ }
1076
+ },
1077
+ [isMobile, isDesktop, setMobileEnabled, setDesktopEnabled]
1078
+ );
1079
+ return {
1080
+ isEnabled,
1081
+ setEnabled
1082
+ };
1083
+ };
1084
+ var useReversePositionScript = (options) => {
1085
+ const { position, onSuccess, onError } = options || {};
1086
+ const { t } = useTranslation();
1087
+ const { isEnabled, setEnabled } = useReversePositionEnabled();
1088
+ const symbolsInfo = useSymbolsInfo();
1089
+ const symbol = position?.symbol || "";
1090
+ const { data: symbolMarketPrice } = useMarkPrice(symbol);
1091
+ const symbolInfo = symbolsInfo?.[symbol];
1092
+ const positionQty = useMemo(() => {
1093
+ if (!position)
1094
+ return 0;
1095
+ return Math.abs(position.position_qty);
1096
+ }, [position]);
1097
+ const isLong = useMemo(() => {
1098
+ if (!position)
1099
+ return false;
1100
+ return position.position_qty > 0;
1101
+ }, [position]);
1102
+ const oppositeSide = useMemo(() => {
1103
+ return isLong ? OrderSide.SELL : OrderSide.BUY;
1104
+ }, [isLong]);
1105
+ const maxOpenQty = useMaxQty(symbol, oppositeSide, false);
1106
+ const reverseQty = useMemo(() => {
1107
+ if (!position)
1108
+ return 0;
1109
+ const desiredQty = positionQty;
1110
+ if (desiredQty > maxOpenQty && maxOpenQty > 0) {
1111
+ return maxOpenQty;
1112
+ }
1113
+ return desiredQty;
1114
+ }, [positionQty, maxOpenQty]);
1115
+ const [doCreateOrder, { isMutating }] = useSubAccountMutation(
1116
+ "/v1/order",
1117
+ "POST",
1118
+ {
1119
+ accountId: position?.account_id
1120
+ }
1121
+ );
1122
+ const reversePosition = useCallback(async () => {
1123
+ if (!position || positionQty === 0) {
1124
+ toast.error("No position to reverse");
1125
+ return false;
1126
+ }
1127
+ try {
1128
+ const closeSide = isLong ? OrderSide.SELL : OrderSide.BUY;
1129
+ const closeOrder = await doCreateOrder({
1130
+ symbol: position.symbol,
1131
+ order_type: OrderType.MARKET,
1132
+ side: closeSide,
1133
+ order_quantity: new Decimal(positionQty).toString(),
1134
+ reduce_only: true
1135
+ });
1136
+ const openSide = isLong ? OrderSide.SELL : OrderSide.BUY;
1137
+ const openOrder = await doCreateOrder({
1138
+ symbol: position.symbol,
1139
+ order_type: OrderType.MARKET,
1140
+ side: openSide,
1141
+ order_quantity: new Decimal(reverseQty).toString(),
1142
+ reduce_only: false
1143
+ });
1144
+ if (!openOrder.success) {
1145
+ throw new Error(
1146
+ openOrder.message || "Failed to open opposite position"
1147
+ );
1148
+ }
1149
+ onSuccess?.();
1150
+ return true;
1151
+ } catch (error) {
1152
+ onError?.(error);
1153
+ return false;
1154
+ }
1155
+ }, [position, positionQty, reverseQty, isLong, doCreateOrder, t, onSuccess]);
1156
+ const displayInfo = useMemo(() => {
1157
+ if (!position || !symbolInfo) {
1158
+ return null;
1159
+ }
1160
+ const base = symbolInfo("base");
1161
+ const quote = symbolInfo("quote");
1162
+ const baseDp = symbolInfo("base_dp");
1163
+ const quoteDp = symbolInfo("quote_dp");
1164
+ const leverage = position.leverage || 1;
1165
+ return {
1166
+ symbol: position.symbol,
1167
+ base,
1168
+ quote,
1169
+ baseDp,
1170
+ quoteDp,
1171
+ positionQty: new Decimal(positionQty).todp(baseDp).toString(),
1172
+ reverseQty: new Decimal(reverseQty).todp(baseDp).toString(),
1173
+ markPrice: symbolMarketPrice ? new Decimal(symbolMarketPrice).todp(quoteDp).toString() : "--",
1174
+ leverage,
1175
+ isLong
1176
+ };
1177
+ }, [
1178
+ position,
1179
+ symbolMarketPrice,
1180
+ symbolInfo,
1181
+ positionQty,
1182
+ reverseQty,
1183
+ isLong
1184
+ ]);
1185
+ return {
1186
+ isEnabled,
1187
+ setEnabled,
1188
+ reversePosition,
1189
+ isReversing: isMutating,
1190
+ displayInfo,
1191
+ positionQty,
1192
+ reverseQty,
1193
+ isLong
1194
+ };
1195
+ };
1196
+ var ReversePositionWidget = (props) => {
1197
+ const { position, close, resolve, reject } = props;
1198
+ const { t } = useTranslation();
1199
+ const { visible, hide, onOpenChange } = useModal();
1200
+ const state = useReversePositionScript({
1201
+ position,
1202
+ onSuccess: () => {
1203
+ resolve?.(true);
1204
+ hide();
1205
+ },
1206
+ onError: (error) => {
1207
+ reject?.(error);
1208
+ hide();
1209
+ }
1210
+ });
1211
+ const actions = useMemo(() => {
1212
+ return {
1213
+ primary: {
1214
+ label: t("common.confirm"),
1215
+ onClick: async () => {
1216
+ try {
1217
+ const result = await state.reversePosition();
1218
+ if (result) {
1219
+ resolve?.(true);
1220
+ hide();
1221
+ return true;
1222
+ } else {
1223
+ reject?.(false);
1224
+ return false;
1225
+ }
1226
+ } catch (error) {
1227
+ reject?.(error);
1228
+ throw error;
1229
+ }
1230
+ },
1231
+ loading: state.isReversing,
1232
+ disabled: state.isReversing || !state.displayInfo
1233
+ },
1234
+ secondary: {
1235
+ label: t("common.cancel"),
1236
+ onClick: async () => {
1237
+ reject?.("cancel");
1238
+ hide();
1239
+ return false;
1240
+ }
1241
+ }
1242
+ };
1243
+ }, [state, t, resolve, reject, hide]);
1244
+ return /* @__PURE__ */ jsx(
1245
+ SimpleDialog,
1246
+ {
1247
+ open: visible,
1248
+ onOpenChange,
1249
+ size: "sm",
1250
+ title: i18n.t("positions.reverse.title"),
1251
+ classNames: {
1252
+ content: "oui-border oui-border-line-6"
1253
+ },
1254
+ actions,
1255
+ children: /* @__PURE__ */ jsx(ReversePosition, { ...state })
1256
+ }
1257
+ );
1258
+ };
1259
+ var ReversePositionDialogId = "ReversePositionDialogId";
1260
+ registerSimpleDialog(
1261
+ ReversePositionDialogId,
1262
+ ReversePositionWidget,
1263
+ {
1264
+ size: "sm",
1265
+ classNames: {
1266
+ content: "oui-border oui-border-line-6"
1267
+ },
1268
+ title: () => i18n.t("positions.reverse.title")
1269
+ }
1270
+ );
873
1271
  var PositionsTabName = /* @__PURE__ */ ((PositionsTabName2) => {
874
1272
  PositionsTabName2["Positions"] = "positions";
875
1273
  PositionsTabName2["PositionHistory"] = "positionHistory";
@@ -911,6 +1309,7 @@ var usePositionsScript = (props) => {
911
1309
  // Default to true for backward compatibility
912
1310
  } = props;
913
1311
  const { pagination, setPage } = usePagination({ pageSize: 50 });
1312
+ const { isEnabled: positionReverse } = useReversePositionEnabled();
914
1313
  const { tabSort, onTabSort } = useTabSort({
915
1314
  storageKey: TRADING_POSITIONS_SORT_STORAGE_KEY
916
1315
  });
@@ -918,7 +1317,7 @@ var usePositionsScript = (props) => {
918
1317
  enableSortingStorage ? tabSort?.["positions" /* Positions */] : void 0,
919
1318
  enableSortingStorage ? onTabSort("positions" /* Positions */) : void 0
920
1319
  );
921
- React.useEffect(() => {
1320
+ React2.useEffect(() => {
922
1321
  setPage(1);
923
1322
  }, [symbol]);
924
1323
  const [data, , { isLoading }] = usePositionStream(symbol, {
@@ -937,6 +1336,7 @@ var usePositionsScript = (props) => {
937
1336
  onSymbolChange,
938
1337
  pagination,
939
1338
  onSort,
1339
+ positionReverse,
940
1340
  initialSort: enableSortingStorage ? tabSort?.["positions" /* Positions */] : void 0
941
1341
  };
942
1342
  };
@@ -1693,9 +2093,20 @@ var PartialTPSL = (props) => {
1693
2093
  slTriggerPrice,
1694
2094
  direction = "column"
1695
2095
  } = props;
1696
- const { partialTPSLOrder: order, quoteDp, baseDp } = usePositionsRowContext();
2096
+ const {
2097
+ partialTPSLOrder: order,
2098
+ quoteDp,
2099
+ baseDp,
2100
+ position
2101
+ } = usePositionsRowContext();
1697
2102
  const symbolInfo = useSymbolsInfo();
1698
2103
  const { t } = useTranslation();
2104
+ const side = position.position_qty > 0 ? OrderSide.BUY : OrderSide.SELL;
2105
+ const slPriceError = useTpslPriceChecker({
2106
+ slPrice: slTriggerPrice?.toString() ?? void 0,
2107
+ liqPrice: position.est_liq_price ?? null,
2108
+ side
2109
+ });
1699
2110
  const child = useMemo(() => {
1700
2111
  const children = [];
1701
2112
  if (!order?.symbol)
@@ -1728,6 +2139,7 @@ var PartialTPSL = (props) => {
1728
2139
  rule: "price",
1729
2140
  dp: symbolInfo[order.symbol]("quote_dp", 2),
1730
2141
  prefix: /* @__PURE__ */ jsx(Text, { intensity: 54, children: `${t("tpsl.sl")} - ` }),
2142
+ suffix: /* @__PURE__ */ jsx(CloseToLiqPriceIcon, { slPriceError }),
1731
2143
  children: slTriggerPrice
1732
2144
  },
1733
2145
  "sl"
@@ -1740,7 +2152,7 @@ var PartialTPSL = (props) => {
1740
2152
  children.splice(1, 0, /* @__PURE__ */ jsx(Text, { children: "/" }, "split"));
1741
2153
  }
1742
2154
  return children;
1743
- }, [tpTriggerPrice, slTriggerPrice, order?.symbol, t]);
2155
+ }, [tpTriggerPrice, slTriggerPrice, order?.symbol, t, slPriceError]);
1744
2156
  const hasTPSL = Array.isArray(child) ? !!child.length : !child;
1745
2157
  return /* @__PURE__ */ jsxs(Flex, { className: "oui-gap-[6px]", children: [
1746
2158
  /* @__PURE__ */ jsx(
@@ -1763,6 +2175,29 @@ var PartialTPSL = (props) => {
1763
2175
  ] })
1764
2176
  ] });
1765
2177
  };
2178
+ var ReversePositionButton = (props) => {
2179
+ const { position } = props;
2180
+ return /* @__PURE__ */ jsx(
2181
+ "div",
2182
+ {
2183
+ className: "",
2184
+ style: { transform: "rotate(90deg)" },
2185
+ onClick: () => {
2186
+ modal.show(ReversePositionDialogId, {
2187
+ position
2188
+ });
2189
+ },
2190
+ children: /* @__PURE__ */ jsx(
2191
+ ArrowLeftRightIcon,
2192
+ {
2193
+ size: 15,
2194
+ opacity: 1,
2195
+ className: "oui-cursor-pointer oui-text-base-contrast-54 hover:oui-text-base-contrast-80"
2196
+ }
2197
+ )
2198
+ }
2199
+ );
2200
+ };
1766
2201
  var ShareButton = (props) => {
1767
2202
  if (!props.sharePnLConfig) {
1768
2203
  return null;
@@ -1863,6 +2298,12 @@ var ShareButtonWidget = (props) => {
1863
2298
  var TriggerPrice = (props) => {
1864
2299
  const { stopLossPrice, takeProfitPrice } = props;
1865
2300
  const { tpslOrder, position } = usePositionsRowContext();
2301
+ const side = position.position_qty > 0 ? OrderSide.BUY : OrderSide.SELL;
2302
+ const slPriceError = useTpslPriceChecker({
2303
+ slPrice: stopLossPrice?.toString() ?? void 0,
2304
+ liqPrice: position.est_liq_price ?? null,
2305
+ side
2306
+ });
1866
2307
  return /* @__PURE__ */ jsx(
1867
2308
  TPSLTriggerPrice,
1868
2309
  {
@@ -1871,6 +2312,7 @@ var TriggerPrice = (props) => {
1871
2312
  direction: "column",
1872
2313
  order: tpslOrder,
1873
2314
  position,
2315
+ slPriceError,
1874
2316
  tooltip: true
1875
2317
  }
1876
2318
  );
@@ -1993,7 +2435,8 @@ var TPSLTriggerPrice = (props) => {
1993
2435
  rule: "price",
1994
2436
  dp: symbolInfo[order.symbol]("quote_dp", 2),
1995
2437
  children: props.stopLossPrice,
1996
- prefix: !props.takeProfitPrice || direction === "column" ? /* @__PURE__ */ jsx(Text, { intensity: 54, children: `${t("tpsl.sl")} - ` }) : ""
2438
+ prefix: !props.takeProfitPrice || direction === "column" ? /* @__PURE__ */ jsx(Text, { intensity: 54, children: `${t("tpsl.sl")} - ` }) : "",
2439
+ suffix: /* @__PURE__ */ jsx(CloseToLiqPriceIcon, { slPriceError: props.slPriceError })
1997
2440
  },
1998
2441
  "sl"
1999
2442
  )
@@ -2005,7 +2448,13 @@ var TPSLTriggerPrice = (props) => {
2005
2448
  children.splice(1, 0, /* @__PURE__ */ jsx(Text, { children: "/" }, "split"));
2006
2449
  }
2007
2450
  return children;
2008
- }, [props.takeProfitPrice, props.stopLossPrice, order?.symbol, t]);
2451
+ }, [
2452
+ props.takeProfitPrice,
2453
+ props.stopLossPrice,
2454
+ order?.symbol,
2455
+ t,
2456
+ props.slPriceError
2457
+ ]);
2009
2458
  const content = /* @__PURE__ */ jsx(
2010
2459
  "div",
2011
2460
  {
@@ -2140,7 +2589,12 @@ var UnselIcon = () => {
2140
2589
  );
2141
2590
  };
2142
2591
  var useColumn = (config) => {
2143
- const { pnlNotionalDecimalPrecision, sharePnLConfig, onSymbolChange } = config;
2592
+ const {
2593
+ pnlNotionalDecimalPrecision,
2594
+ sharePnLConfig,
2595
+ onSymbolChange,
2596
+ positionReverse
2597
+ } = config;
2144
2598
  const { t } = useTranslation();
2145
2599
  useRef(Date.now().toString());
2146
2600
  const column = useMemo(
@@ -2411,14 +2865,17 @@ var useColumn = (config) => {
2411
2865
  title: null,
2412
2866
  dataIndex: "close_position",
2413
2867
  align: "right",
2414
- width: 70,
2868
+ width: positionReverse ? 100 : 70,
2415
2869
  fixed: "right",
2416
- render() {
2417
- return /* @__PURE__ */ jsx(Flex, { gapX: 2, justify: "end", children: /* @__PURE__ */ jsx(ClosePositionWidget, {}) });
2870
+ render(_, record) {
2871
+ return /* @__PURE__ */ jsxs(Flex, { gapX: 2, justify: "end", children: [
2872
+ /* @__PURE__ */ jsx(ClosePositionWidget, {}),
2873
+ positionReverse && /* @__PURE__ */ jsx(ReversePositionButton, { position: record })
2874
+ ] });
2418
2875
  }
2419
2876
  }
2420
2877
  ],
2421
- [pnlNotionalDecimalPrecision, sharePnLConfig, t]
2878
+ [pnlNotionalDecimalPrecision, sharePnLConfig, t, positionReverse]
2422
2879
  );
2423
2880
  return column;
2424
2881
  };
@@ -2598,13 +3055,32 @@ var LiqPrice = (props) => {
2598
3055
  var TPSLPrice = (props) => {
2599
3056
  const { item } = props;
2600
3057
  const { t } = useTranslation();
3058
+ const slPriceError = useTpslPriceChecker({
3059
+ slPrice: item.full_tp_sl?.sl_trigger_price?.toString() ?? void 0,
3060
+ liqPrice: item.est_liq_price ?? null,
3061
+ side: item.position_qty > 0 ? OrderSide.BUY : OrderSide.SELL
3062
+ });
3063
+ const partialSlPriceError = useTpslPriceChecker({
3064
+ slPrice: item.partial_tp_sl?.sl_trigger_price?.toString() ?? void 0,
3065
+ liqPrice: item.est_liq_price ?? null,
3066
+ side: item.position_qty > 0 ? OrderSide.BUY : OrderSide.SELL
3067
+ });
2601
3068
  const fullTPSL = useMemo(() => {
2602
3069
  if (item.full_tp_sl?.tp_trigger_price == null && item.full_tp_sl?.sl_trigger_price == null)
2603
3070
  return /* @__PURE__ */ jsx(AddIcon, { positionType: PositionType.FULL });
2604
3071
  return /* @__PURE__ */ jsxs(Flex, { className: "oui-gap-[2px]", children: [
2605
3072
  item.full_tp_sl?.tp_trigger_price && /* @__PURE__ */ jsx(Text.numeral, { color: "buy", children: item.full_tp_sl.tp_trigger_price }),
2606
3073
  item.full_tp_sl?.sl_trigger_price && "/",
2607
- item.full_tp_sl?.sl_trigger_price && /* @__PURE__ */ jsx(Text.numeral, { color: "sell", children: item.full_tp_sl.sl_trigger_price }),
3074
+ item.full_tp_sl?.sl_trigger_price && /* @__PURE__ */ jsx(
3075
+ Text.numeral,
3076
+ {
3077
+ as: "div",
3078
+ color: "sell",
3079
+ suffix: /* @__PURE__ */ jsx(CloseToLiqPriceIcon, { slPriceError }),
3080
+ className: "oui-flex oui-items-center",
3081
+ children: item.full_tp_sl.sl_trigger_price
3082
+ }
3083
+ ),
2608
3084
  /* @__PURE__ */ jsx(TPSLEditIcon, {})
2609
3085
  ] });
2610
3086
  }, [item.full_tp_sl]);
@@ -2614,7 +3090,16 @@ var TPSLPrice = (props) => {
2614
3090
  return /* @__PURE__ */ jsxs(Flex, { className: "oui-gap-[2px]", itemAlign: "center", children: [
2615
3091
  item.partial_tp_sl?.tp_trigger_price && /* @__PURE__ */ jsx(Text.numeral, { color: "buy", children: item.partial_tp_sl.tp_trigger_price }),
2616
3092
  item.partial_tp_sl?.sl_trigger_price && "/",
2617
- item.partial_tp_sl?.sl_trigger_price && /* @__PURE__ */ jsx(Text.numeral, { color: "sell", children: item.partial_tp_sl.sl_trigger_price }),
3093
+ item.partial_tp_sl?.sl_trigger_price && /* @__PURE__ */ jsx(
3094
+ Text.numeral,
3095
+ {
3096
+ as: "div",
3097
+ color: "sell",
3098
+ suffix: /* @__PURE__ */ jsx(CloseToLiqPriceIcon, { slPriceError: partialSlPriceError }),
3099
+ className: "oui-flex oui-items-center",
3100
+ children: item.partial_tp_sl.sl_trigger_price
3101
+ }
3102
+ ),
2618
3103
  /* @__PURE__ */ jsx(Text, { children: `(${item.partial_tp_sl?.order_num})` }),
2619
3104
  /* @__PURE__ */ jsx(TPSLEditIcon, {})
2620
3105
  ] });
@@ -2685,7 +3170,10 @@ var PositionCell = (props) => {
2685
3170
  /* @__PURE__ */ jsx(Divider, { intensity: 6, className: "oui-w-full" }),
2686
3171
  body,
2687
3172
  /* @__PURE__ */ jsx(TPSLPrice, { ...rest }),
2688
- buttons
3173
+ /* @__PURE__ */ jsxs(Flex, { justify: "between", width: "100%", gap: 2, children: [
3174
+ buttons,
3175
+ props.positionReverse && /* @__PURE__ */ jsx(ReversePositionButton, { position: props.item })
3176
+ ] })
2689
3177
  ]
2690
3178
  }
2691
3179
  );
@@ -2852,12 +3340,14 @@ var Positions = (props) => {
2852
3340
  pagination,
2853
3341
  isLoading,
2854
3342
  dataSource,
2855
- onSymbolChange
3343
+ onSymbolChange,
3344
+ positionReverse
2856
3345
  } = props;
2857
3346
  const columns = useColumn({
2858
3347
  pnlNotionalDecimalPrecision,
2859
3348
  sharePnLConfig,
2860
- onSymbolChange
3349
+ onSymbolChange,
3350
+ positionReverse
2861
3351
  });
2862
3352
  return /* @__PURE__ */ jsx(
2863
3353
  AuthGuardDataTable,
@@ -2890,7 +3380,8 @@ var MobilePositions = (props) => {
2890
3380
  pnlNotionalDecimalPrecision,
2891
3381
  sharePnLConfig,
2892
3382
  dataSource,
2893
- onSymbolChange
3383
+ onSymbolChange,
3384
+ positionReverse
2894
3385
  } = props;
2895
3386
  return /* @__PURE__ */ jsx(
2896
3387
  ListView,
@@ -2905,7 +3396,8 @@ var MobilePositions = (props) => {
2905
3396
  index,
2906
3397
  pnlNotionalDecimalPrecision,
2907
3398
  sharePnLConfig,
2908
- onSymbolChange
3399
+ onSymbolChange,
3400
+ positionReverse
2909
3401
  }
2910
3402
  ) }) })
2911
3403
  }
@@ -4833,6 +5325,6 @@ registerSimpleDialog(MarketCloseConfirmID, MarketCloseConfirm, {
4833
5325
  closable: false
4834
5326
  });
4835
5327
 
4836
- export { CloseAllPositions, CloseAllPositionsWidget, CombinePositionsWidget, FundingFeeButton, FundingFeeHistoryUI, Liquidation, LiquidationWidget, MarketCloseConfirmID, MobileLiquidation, MobileLiquidationWidget, MobilePositionHistory, MobilePositionHistoryWidget, MobilePositionsWidget, PositionHistory, PositionHistoryWidget, PositionsTabName, PositionsWidget, sortList, useCloseAllPositionsScript, useLiquidationScript, usePositionHistoryScript, usePositionsRowContext, useSort, useTabSort };
5328
+ export { CloseAllPositions, CloseAllPositionsWidget, CombinePositionsWidget, FundingFeeButton, FundingFeeHistoryUI, Liquidation, LiquidationWidget, MarketCloseConfirmID, MobileLiquidation, MobileLiquidationWidget, MobilePositionHistory, MobilePositionHistoryWidget, MobilePositionsWidget, OrderInfoCard, PositionHistory, PositionHistoryWidget, PositionsTabName, PositionsWidget, ReversePosition, ReversePositionDialogId, ReversePositionWidget, sortList, useCloseAllPositionsScript, useLiquidationScript, usePositionHistoryScript, usePositionsRowContext, useReversePositionEnabled, useReversePositionScript, useSort, useTabSort };
4837
5329
  //# sourceMappingURL=out.js.map
4838
5330
  //# sourceMappingURL=index.mjs.map