@orderly.network/ui-positions 2.8.8-alpha.0 → 2.8.9-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 +12 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +317 -140
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +321 -144
- package/dist/index.mjs.map +1 -1
- package/package.json +13 -13
package/dist/index.js
CHANGED
|
@@ -7,9 +7,8 @@ var types = require('@orderly.network/types');
|
|
|
7
7
|
var utils = require('@orderly.network/utils');
|
|
8
8
|
var jsxRuntime = require('react/jsx-runtime');
|
|
9
9
|
var hooks = require('@orderly.network/hooks');
|
|
10
|
-
var immer = require('immer');
|
|
11
|
-
var perp = require('@orderly.network/perp');
|
|
12
10
|
var reactApp = require('@orderly.network/react-app');
|
|
11
|
+
var perp = require('@orderly.network/perp');
|
|
13
12
|
var uiConnector = require('@orderly.network/ui-connector');
|
|
14
13
|
var uiLeverage = require('@orderly.network/ui-leverage');
|
|
15
14
|
var uiShare = require('@orderly.network/ui-share');
|
|
@@ -599,6 +598,102 @@ var FundingFeeButton = ({ fee, symbol, start_t, end_t }) => {
|
|
|
599
598
|
)
|
|
600
599
|
] });
|
|
601
600
|
};
|
|
601
|
+
var calculatePositions = (positions2, symbolsInfo, accountInfo, tpslOrders) => {
|
|
602
|
+
return positions2.map((item) => {
|
|
603
|
+
const info = symbolsInfo[item.symbol];
|
|
604
|
+
const notional = perp.positions.notional(item.position_qty, item.mark_price);
|
|
605
|
+
const account2 = accountInfo.find(
|
|
606
|
+
(acc) => acc.account_id === item.account_id
|
|
607
|
+
);
|
|
608
|
+
const baseMMR = info?.("base_mmr");
|
|
609
|
+
const baseIMR = info?.("base_imr");
|
|
610
|
+
if (!baseMMR || !baseIMR) {
|
|
611
|
+
return item;
|
|
612
|
+
}
|
|
613
|
+
const MMR = perp.positions.MMR({
|
|
614
|
+
baseMMR,
|
|
615
|
+
baseIMR,
|
|
616
|
+
IMRFactor: account2?.imr_factor[item.symbol] ?? 0,
|
|
617
|
+
positionNotional: notional,
|
|
618
|
+
IMR_factor_power: 4 / 5
|
|
619
|
+
});
|
|
620
|
+
const mm = perp.positions.maintenanceMargin({
|
|
621
|
+
positionQty: item.position_qty,
|
|
622
|
+
markPrice: item.mark_price,
|
|
623
|
+
MMR
|
|
624
|
+
});
|
|
625
|
+
const unrealPnl = perp.positions.unrealizedPnL({
|
|
626
|
+
qty: item.position_qty,
|
|
627
|
+
openPrice: item?.average_open_price,
|
|
628
|
+
markPrice: item.mark_price
|
|
629
|
+
});
|
|
630
|
+
const maxLeverage = item.leverage || 1;
|
|
631
|
+
const imr = perp.account.IMR({
|
|
632
|
+
maxLeverage,
|
|
633
|
+
baseIMR,
|
|
634
|
+
IMR_Factor: account2?.imr_factor[item.symbol] ?? 0,
|
|
635
|
+
positionNotional: notional,
|
|
636
|
+
ordersNotional: 0,
|
|
637
|
+
IMR_factor_power: 4 / 5
|
|
638
|
+
});
|
|
639
|
+
const unrealPnlROI = perp.positions.unrealizedPnLROI({
|
|
640
|
+
positionQty: item.position_qty,
|
|
641
|
+
openPrice: item.average_open_price,
|
|
642
|
+
IMR: imr,
|
|
643
|
+
unrealizedPnL: unrealPnl
|
|
644
|
+
});
|
|
645
|
+
let unrealPnl_index = 0;
|
|
646
|
+
let unrealPnlROI_index = 0;
|
|
647
|
+
if (item.index_price) {
|
|
648
|
+
unrealPnl_index = perp.positions.unrealizedPnL({
|
|
649
|
+
qty: item.position_qty,
|
|
650
|
+
openPrice: item?.average_open_price,
|
|
651
|
+
markPrice: item.index_price
|
|
652
|
+
});
|
|
653
|
+
unrealPnlROI_index = perp.positions.unrealizedPnLROI({
|
|
654
|
+
positionQty: item.position_qty,
|
|
655
|
+
openPrice: item.average_open_price,
|
|
656
|
+
IMR: imr,
|
|
657
|
+
unrealizedPnL: unrealPnl_index
|
|
658
|
+
});
|
|
659
|
+
}
|
|
660
|
+
const filteredTPSLOrders = tpslOrders.filter(
|
|
661
|
+
(tpslOrder) => tpslOrder.account_id === item.account_id
|
|
662
|
+
);
|
|
663
|
+
const tpsl = formatTPSL(filteredTPSLOrders, item.symbol);
|
|
664
|
+
return {
|
|
665
|
+
...item,
|
|
666
|
+
...tpsl,
|
|
667
|
+
mmr: MMR,
|
|
668
|
+
mm,
|
|
669
|
+
notional,
|
|
670
|
+
unrealized_pnl: unrealPnl,
|
|
671
|
+
unrealized_pnl_ROI: unrealPnlROI,
|
|
672
|
+
unrealized_pnl_ROI_index: unrealPnlROI_index
|
|
673
|
+
};
|
|
674
|
+
});
|
|
675
|
+
};
|
|
676
|
+
function formatTPSL(tpslOrders, symbol) {
|
|
677
|
+
if (Array.isArray(tpslOrders) && tpslOrders.length) {
|
|
678
|
+
const { fullPositionOrder, partialPositionOrders } = hooks.findPositionTPSLFromOrders(tpslOrders, symbol);
|
|
679
|
+
const full_tp_sl = fullPositionOrder ? hooks.findTPSLFromOrder(fullPositionOrder) : void 0;
|
|
680
|
+
const partialPossitionOrder = partialPositionOrders && partialPositionOrders.length ? partialPositionOrders[0] : void 0;
|
|
681
|
+
const partial_tp_sl = partialPossitionOrder ? hooks.findTPSLFromOrder(partialPossitionOrder) : void 0;
|
|
682
|
+
return {
|
|
683
|
+
full_tp_sl: {
|
|
684
|
+
tp_trigger_price: full_tp_sl?.tp_trigger_price,
|
|
685
|
+
sl_trigger_price: full_tp_sl?.sl_trigger_price,
|
|
686
|
+
algo_order: fullPositionOrder
|
|
687
|
+
},
|
|
688
|
+
partial_tp_sl: {
|
|
689
|
+
order_num: partialPositionOrders?.length ?? 0,
|
|
690
|
+
tp_trigger_price: partial_tp_sl?.tp_trigger_price,
|
|
691
|
+
sl_trigger_price: partial_tp_sl?.sl_trigger_price,
|
|
692
|
+
algo_order: partialPossitionOrder
|
|
693
|
+
}
|
|
694
|
+
};
|
|
695
|
+
}
|
|
696
|
+
}
|
|
602
697
|
var signatureMiddleware = (account2, accountId) => {
|
|
603
698
|
const apiBaseUrl = hooks.useConfig("apiBaseUrl");
|
|
604
699
|
return (useSWRNext) => {
|
|
@@ -648,6 +743,48 @@ var useSubAccountQuery = (query, options) => {
|
|
|
648
743
|
}
|
|
649
744
|
);
|
|
650
745
|
};
|
|
746
|
+
function useSubAccountTPSL(subAccountIds) {
|
|
747
|
+
const ee = hooks.useEventEmitter();
|
|
748
|
+
const { data: algoOrdersResponse, mutate: mutateTPSLOrders } = useSubAccountQuery(
|
|
749
|
+
`/v1/algo/orders?size=100&page=1&status=${types.OrderStatus.INCOMPLETE}`,
|
|
750
|
+
{
|
|
751
|
+
accountId: subAccountIds,
|
|
752
|
+
formatter: (data) => data,
|
|
753
|
+
revalidateOnFocus: false
|
|
754
|
+
}
|
|
755
|
+
);
|
|
756
|
+
const tpslOrders = React2.useMemo(() => {
|
|
757
|
+
if (!Array.isArray(algoOrdersResponse)) {
|
|
758
|
+
return [];
|
|
759
|
+
}
|
|
760
|
+
const algoOrders = algoOrdersResponse?.map(
|
|
761
|
+
(item, index) => item.rows.map((order) => ({
|
|
762
|
+
...order,
|
|
763
|
+
account_id: subAccountIds[index]
|
|
764
|
+
}))
|
|
765
|
+
)?.flat();
|
|
766
|
+
return algoOrders?.filter(
|
|
767
|
+
(order) => [types.AlgoOrderRootType.POSITIONAL_TP_SL, types.AlgoOrderRootType.TP_SL].includes(
|
|
768
|
+
order.algo_type
|
|
769
|
+
)
|
|
770
|
+
);
|
|
771
|
+
}, [algoOrdersResponse, subAccountIds]);
|
|
772
|
+
const refresh = hooks.useDebouncedCallback(() => {
|
|
773
|
+
mutateTPSLOrders();
|
|
774
|
+
}, 200);
|
|
775
|
+
React2.useEffect(() => {
|
|
776
|
+
const handler = (position) => {
|
|
777
|
+
if (position.account_id) {
|
|
778
|
+
refresh();
|
|
779
|
+
}
|
|
780
|
+
};
|
|
781
|
+
ee.on("tpsl:updateOrder", handler);
|
|
782
|
+
return () => {
|
|
783
|
+
ee.off("tpsl:updateOrder", handler);
|
|
784
|
+
};
|
|
785
|
+
}, [ee]);
|
|
786
|
+
return { tpslOrders, mutateTPSLOrders };
|
|
787
|
+
}
|
|
651
788
|
|
|
652
789
|
// src/components/positions/combinePositions.script.ts
|
|
653
790
|
var useCombinePositionsScript = (props) => {
|
|
@@ -661,12 +798,9 @@ var useCombinePositionsScript = (props) => {
|
|
|
661
798
|
selectedAccount
|
|
662
799
|
} = props;
|
|
663
800
|
const { pagination, setPage } = ui.usePagination({ pageSize: 50 });
|
|
664
|
-
React2.useEffect(() => {
|
|
665
|
-
setPage(1);
|
|
666
|
-
}, [symbol]);
|
|
667
801
|
const symbolsInfo = hooks.useSymbolsInfo();
|
|
668
802
|
const { state } = hooks.useAccount();
|
|
669
|
-
const [
|
|
803
|
+
const [mainAccountPositions, , { isLoading }] = hooks.usePositionStream(symbol, {
|
|
670
804
|
calcMode,
|
|
671
805
|
includedPendingOrder
|
|
672
806
|
});
|
|
@@ -675,90 +809,37 @@ var useCombinePositionsScript = (props) => {
|
|
|
675
809
|
isLoading: isPositionLoading,
|
|
676
810
|
mutate: mutatePositions
|
|
677
811
|
} = hooks.usePrivateQuery("/v1/client/aggregate/positions", {
|
|
678
|
-
// formatter: (data) => data,
|
|
679
812
|
errorRetryCount: 3
|
|
680
813
|
});
|
|
814
|
+
const { allAccountIds, subAccountIds } = React2.useMemo(() => {
|
|
815
|
+
const uniqueIds = new Set(
|
|
816
|
+
newPositions.filter((item) => item.account_id).map((item) => item.account_id).filter(Boolean)
|
|
817
|
+
);
|
|
818
|
+
const allAccountIds2 = Array.from(uniqueIds);
|
|
819
|
+
const subAccountIds2 = allAccountIds2.filter(
|
|
820
|
+
(item) => item !== state.mainAccountId
|
|
821
|
+
);
|
|
822
|
+
return { allAccountIds: allAccountIds2, subAccountIds: subAccountIds2 };
|
|
823
|
+
}, [newPositions, state.mainAccountId]);
|
|
681
824
|
const { data: accountInfo = [], isLoading: isAccountInfoLoading } = useSubAccountQuery("/v1/client/info", {
|
|
682
|
-
accountId:
|
|
825
|
+
accountId: allAccountIds,
|
|
683
826
|
revalidateOnFocus: false
|
|
684
827
|
});
|
|
685
|
-
const
|
|
686
|
-
|
|
687
|
-
(
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
baseMMR,
|
|
701
|
-
baseIMR,
|
|
702
|
-
IMRFactor: account2?.imr_factor[item.symbol] ?? 0,
|
|
703
|
-
positionNotional: notional,
|
|
704
|
-
IMR_factor_power: 4 / 5
|
|
705
|
-
});
|
|
706
|
-
const mm = perp.positions.maintenanceMargin({
|
|
707
|
-
positionQty: item.position_qty,
|
|
708
|
-
markPrice: item.mark_price,
|
|
709
|
-
MMR
|
|
710
|
-
});
|
|
711
|
-
const unrealPnl = perp.positions.unrealizedPnL({
|
|
712
|
-
qty: item.position_qty,
|
|
713
|
-
openPrice: item?.average_open_price,
|
|
714
|
-
// markPrice: unRealizedPrice,
|
|
715
|
-
markPrice: item.mark_price
|
|
716
|
-
});
|
|
717
|
-
const maxLeverage = item.leverage || 1;
|
|
718
|
-
const imr = perp.account.IMR({
|
|
719
|
-
maxLeverage,
|
|
720
|
-
baseIMR,
|
|
721
|
-
IMR_Factor: account2?.imr_factor[item.symbol] ?? 0,
|
|
722
|
-
positionNotional: notional,
|
|
723
|
-
ordersNotional: 0,
|
|
724
|
-
IMR_factor_power: 4 / 5
|
|
725
|
-
});
|
|
726
|
-
const unrealPnlROI = perp.positions.unrealizedPnLROI({
|
|
727
|
-
positionQty: item.position_qty,
|
|
728
|
-
openPrice: item.average_open_price,
|
|
729
|
-
IMR: imr,
|
|
730
|
-
unrealizedPnL: unrealPnl
|
|
731
|
-
});
|
|
732
|
-
let unrealPnl_index = 0;
|
|
733
|
-
let unrealPnlROI_index = 0;
|
|
734
|
-
if (item.index_price) {
|
|
735
|
-
unrealPnl_index = perp.positions.unrealizedPnL({
|
|
736
|
-
qty: item.position_qty,
|
|
737
|
-
openPrice: item?.average_open_price,
|
|
738
|
-
// markPrice: unRealizedPrice,
|
|
739
|
-
markPrice: item.index_price
|
|
740
|
-
});
|
|
741
|
-
unrealPnlROI_index = perp.positions.unrealizedPnLROI({
|
|
742
|
-
positionQty: item.position_qty,
|
|
743
|
-
openPrice: item.average_open_price,
|
|
744
|
-
IMR: imr,
|
|
745
|
-
unrealizedPnL: unrealPnl_index
|
|
746
|
-
});
|
|
747
|
-
}
|
|
748
|
-
item.mmr = MMR;
|
|
749
|
-
item.mm = mm;
|
|
750
|
-
item.notional = notional;
|
|
751
|
-
item.unrealized_pnl = unrealPnl;
|
|
752
|
-
item.unrealized_pnl_ROI = unrealPnlROI;
|
|
753
|
-
item.unrealized_pnl_ROI_index = unrealPnlROI_index;
|
|
754
|
-
}
|
|
755
|
-
}
|
|
756
|
-
);
|
|
757
|
-
const dataSource = reactApp.useDataTap(
|
|
758
|
-
[...oldPositions?.rows, ...processPositions].filter(
|
|
759
|
-
(acc) => acc.position_qty !== 0
|
|
760
|
-
)
|
|
761
|
-
) ?? [];
|
|
828
|
+
const { tpslOrders, mutateTPSLOrders } = useSubAccountTPSL(subAccountIds);
|
|
829
|
+
const subAccountPositions = React2.useMemo(() => {
|
|
830
|
+
return calculatePositions(
|
|
831
|
+
newPositions.filter((item) => item.account_id !== state.mainAccountId),
|
|
832
|
+
symbolsInfo,
|
|
833
|
+
accountInfo,
|
|
834
|
+
tpslOrders
|
|
835
|
+
);
|
|
836
|
+
}, [newPositions, symbolsInfo, accountInfo, state.mainAccountId, tpslOrders]);
|
|
837
|
+
const allPositions = React2.useMemo(() => {
|
|
838
|
+
return [...mainAccountPositions?.rows, ...subAccountPositions].filter(
|
|
839
|
+
(item) => item.position_qty !== 0
|
|
840
|
+
);
|
|
841
|
+
}, [mainAccountPositions, subAccountPositions]);
|
|
842
|
+
const dataSource = reactApp.useDataTap(allPositions) ?? [];
|
|
762
843
|
const filtered = React2.useMemo(() => {
|
|
763
844
|
if (!selectedAccount || selectedAccount === "All accounts" /* ALL */) {
|
|
764
845
|
return dataSource;
|
|
@@ -777,18 +858,23 @@ var useCombinePositionsScript = (props) => {
|
|
|
777
858
|
subAccounts: state.subAccounts
|
|
778
859
|
});
|
|
779
860
|
}, [filtered, state.mainAccountId, state.subAccounts]);
|
|
780
|
-
const
|
|
781
|
-
|
|
782
|
-
|
|
861
|
+
const loading = isLoading || isPositionLoading || isAccountInfoLoading;
|
|
862
|
+
React2.useEffect(() => {
|
|
863
|
+
setPage(1);
|
|
864
|
+
}, [symbol]);
|
|
865
|
+
const mutateList = React2.useCallback(() => {
|
|
866
|
+
mutatePositions();
|
|
867
|
+
mutateTPSLOrders();
|
|
868
|
+
}, []);
|
|
783
869
|
return {
|
|
784
870
|
tableData: groupDataSource,
|
|
785
|
-
isLoading:
|
|
871
|
+
isLoading: loading,
|
|
786
872
|
pnlNotionalDecimalPrecision,
|
|
787
873
|
sharePnLConfig,
|
|
788
874
|
symbol,
|
|
789
875
|
onSymbolChange,
|
|
790
876
|
pagination,
|
|
791
|
-
mutatePositions
|
|
877
|
+
mutatePositions: mutateList
|
|
792
878
|
};
|
|
793
879
|
};
|
|
794
880
|
var groupDataByAccount = (data, options) => {
|
|
@@ -796,12 +882,12 @@ var groupDataByAccount = (data, options) => {
|
|
|
796
882
|
const map = /* @__PURE__ */ new Map();
|
|
797
883
|
for (const item of data) {
|
|
798
884
|
const accountId = item.account_id || mainAccountId;
|
|
799
|
-
const findSubAccount = subAccounts.find((
|
|
885
|
+
const findSubAccount = subAccounts.find((item2) => item2.id === accountId);
|
|
800
886
|
if (map.has(accountId)) {
|
|
801
887
|
map.get(accountId)?.children?.push(item);
|
|
802
888
|
} else {
|
|
803
889
|
map.set(accountId, {
|
|
804
|
-
|
|
890
|
+
account_id: accountId,
|
|
805
891
|
description: accountId === mainAccountId ? i18n.i18n.t("common.mainAccount") : findSubAccount?.description || ui.formatAddress(findSubAccount?.id || ""),
|
|
806
892
|
children: [item]
|
|
807
893
|
});
|
|
@@ -962,7 +1048,14 @@ var OrderInfoCard = ({
|
|
|
962
1048
|
);
|
|
963
1049
|
};
|
|
964
1050
|
var ReversePosition = (props) => {
|
|
965
|
-
const {
|
|
1051
|
+
const {
|
|
1052
|
+
displayInfo,
|
|
1053
|
+
validationError,
|
|
1054
|
+
className,
|
|
1055
|
+
style,
|
|
1056
|
+
onConfirm,
|
|
1057
|
+
onCancel
|
|
1058
|
+
} = props;
|
|
966
1059
|
const { t } = i18n.useTranslation();
|
|
967
1060
|
if (!displayInfo) {
|
|
968
1061
|
return null;
|
|
@@ -989,6 +1082,7 @@ var ReversePosition = (props) => {
|
|
|
989
1082
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Text.numeral, { dp: quoteDp, size: "sm", intensity: 80, children: markPrice }),
|
|
990
1083
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "sm", intensity: 36, children: quote })
|
|
991
1084
|
] });
|
|
1085
|
+
const showBelowMinError = validationError === "belowMin";
|
|
992
1086
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
993
1087
|
ui.Flex,
|
|
994
1088
|
{
|
|
@@ -1048,11 +1142,12 @@ var ReversePosition = (props) => {
|
|
|
1048
1142
|
baseDp
|
|
1049
1143
|
}
|
|
1050
1144
|
),
|
|
1051
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "2xs", color: "warning", weight: "semibold", children: t("positions.reverse.description") })
|
|
1145
|
+
showBelowMinError ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "2xs", color: "danger", weight: "semibold", children: t("positions.reverse.error.belowMin") }) : /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "2xs", color: "warning", weight: "semibold", children: t("positions.reverse.description") })
|
|
1052
1146
|
]
|
|
1053
1147
|
}
|
|
1054
1148
|
);
|
|
1055
1149
|
};
|
|
1150
|
+
var MAX_BATCH_ORDER_SIZE = 20;
|
|
1056
1151
|
var useReversePositionEnabled = () => {
|
|
1057
1152
|
const { isMobile, isDesktop } = ui.useScreen();
|
|
1058
1153
|
const [desktopEnabled, setDesktopEnabled] = hooks.useLocalStorage(
|
|
@@ -1089,12 +1184,26 @@ var useReversePositionEnabled = () => {
|
|
|
1089
1184
|
};
|
|
1090
1185
|
var useReversePositionScript = (options) => {
|
|
1091
1186
|
const { position, onSuccess, onError } = options || {};
|
|
1092
|
-
const { t } = i18n.useTranslation();
|
|
1093
1187
|
const { isEnabled, setEnabled } = useReversePositionEnabled();
|
|
1094
1188
|
const symbolsInfo = hooks.useSymbolsInfo();
|
|
1095
1189
|
const symbol = position?.symbol || "";
|
|
1096
1190
|
const { data: symbolMarketPrice } = hooks.useMarkPrice(symbol);
|
|
1097
1191
|
const symbolInfo = symbolsInfo?.[symbol];
|
|
1192
|
+
const baseMin = React2.useMemo(() => {
|
|
1193
|
+
if (!symbolInfo)
|
|
1194
|
+
return 0;
|
|
1195
|
+
return symbolInfo("base_min") || 0;
|
|
1196
|
+
}, [symbolInfo]);
|
|
1197
|
+
const baseMax = React2.useMemo(() => {
|
|
1198
|
+
if (!symbolInfo)
|
|
1199
|
+
return 0;
|
|
1200
|
+
return symbolInfo("base_max") || 0;
|
|
1201
|
+
}, [symbolInfo]);
|
|
1202
|
+
const baseDp = React2.useMemo(() => {
|
|
1203
|
+
if (!symbolInfo)
|
|
1204
|
+
return 6;
|
|
1205
|
+
return symbolInfo("base_dp") || 6;
|
|
1206
|
+
}, [symbolInfo]);
|
|
1098
1207
|
const positionQty = React2.useMemo(() => {
|
|
1099
1208
|
if (!position)
|
|
1100
1209
|
return 0;
|
|
@@ -1105,21 +1214,62 @@ var useReversePositionScript = (options) => {
|
|
|
1105
1214
|
return false;
|
|
1106
1215
|
return position.position_qty > 0;
|
|
1107
1216
|
}, [position]);
|
|
1108
|
-
const
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
return 0;
|
|
1115
|
-
const desiredQty = positionQty;
|
|
1116
|
-
if (desiredQty > maxOpenQty && maxOpenQty > 0) {
|
|
1117
|
-
return maxOpenQty;
|
|
1217
|
+
const reverseQty = positionQty;
|
|
1218
|
+
const validationError = React2.useMemo(() => {
|
|
1219
|
+
if (!position || !symbolInfo)
|
|
1220
|
+
return null;
|
|
1221
|
+
if (baseMin > 0 && reverseQty < baseMin) {
|
|
1222
|
+
return "belowMin";
|
|
1118
1223
|
}
|
|
1119
|
-
return
|
|
1120
|
-
}, [
|
|
1121
|
-
const
|
|
1122
|
-
|
|
1224
|
+
return null;
|
|
1225
|
+
}, [position, symbolInfo, reverseQty, baseMin]);
|
|
1226
|
+
const splitOrders = React2.useMemo(() => {
|
|
1227
|
+
if (!position || !symbolInfo || baseMax <= 0 || reverseQty <= 0) {
|
|
1228
|
+
return { needsSplit: false, orders: [] };
|
|
1229
|
+
}
|
|
1230
|
+
const buildOrder = (qty, side, reduceOnly) => {
|
|
1231
|
+
return {
|
|
1232
|
+
symbol: position.symbol,
|
|
1233
|
+
order_type: types.OrderType.MARKET,
|
|
1234
|
+
side,
|
|
1235
|
+
order_quantity: new utils.Decimal(qty).todp(baseDp).toString(),
|
|
1236
|
+
reduce_only: reduceOnly
|
|
1237
|
+
};
|
|
1238
|
+
};
|
|
1239
|
+
const closeSide = isLong ? types.OrderSide.SELL : types.OrderSide.BUY;
|
|
1240
|
+
const openSide = isLong ? types.OrderSide.SELL : types.OrderSide.BUY;
|
|
1241
|
+
if (reverseQty <= baseMax) {
|
|
1242
|
+
return {
|
|
1243
|
+
needsSplit: false,
|
|
1244
|
+
orders: [
|
|
1245
|
+
buildOrder(reverseQty, closeSide, true),
|
|
1246
|
+
buildOrder(reverseQty, openSide, false)
|
|
1247
|
+
]
|
|
1248
|
+
};
|
|
1249
|
+
}
|
|
1250
|
+
const orders = [];
|
|
1251
|
+
const perOrderQty = baseMax;
|
|
1252
|
+
const numOrders = Math.ceil(reverseQty / baseMax);
|
|
1253
|
+
for (let i = 0; i < numOrders - 1; i++) {
|
|
1254
|
+
orders.push(buildOrder(perOrderQty, closeSide, true));
|
|
1255
|
+
}
|
|
1256
|
+
orders.push(
|
|
1257
|
+
buildOrder(reverseQty - perOrderQty * (numOrders - 1), closeSide, true)
|
|
1258
|
+
);
|
|
1259
|
+
for (let i = 0; i < numOrders - 1; i++) {
|
|
1260
|
+
orders.push(buildOrder(perOrderQty, openSide, false));
|
|
1261
|
+
}
|
|
1262
|
+
orders.push(
|
|
1263
|
+
buildOrder(reverseQty - perOrderQty * (numOrders - 1), openSide, false)
|
|
1264
|
+
);
|
|
1265
|
+
return {
|
|
1266
|
+
needsSplit: true,
|
|
1267
|
+
orders
|
|
1268
|
+
};
|
|
1269
|
+
}, [position, symbolInfo, reverseQty, baseMax, baseDp]);
|
|
1270
|
+
const [isReversing, setIsReversing] = React2.useState(false);
|
|
1271
|
+
const [doBatchCreateOrder] = hooks.useSubAccountMutation(
|
|
1272
|
+
"/v1/batch-order",
|
|
1123
1273
|
"POST",
|
|
1124
1274
|
{
|
|
1125
1275
|
accountId: position?.account_id
|
|
@@ -1127,55 +1277,74 @@ var useReversePositionScript = (options) => {
|
|
|
1127
1277
|
);
|
|
1128
1278
|
const reversePosition = React2.useCallback(async () => {
|
|
1129
1279
|
if (!position || positionQty === 0) {
|
|
1130
|
-
ui.toast.error("No position to reverse");
|
|
1131
1280
|
return false;
|
|
1132
1281
|
}
|
|
1282
|
+
if (validationError) {
|
|
1283
|
+
return false;
|
|
1284
|
+
}
|
|
1285
|
+
setIsReversing(true);
|
|
1133
1286
|
try {
|
|
1134
|
-
const
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
}
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
);
|
|
1287
|
+
const ordersArray = splitOrders.orders;
|
|
1288
|
+
if (ordersArray.length > MAX_BATCH_ORDER_SIZE) {
|
|
1289
|
+
for (let i = 0; i < ordersArray.length; i += MAX_BATCH_ORDER_SIZE) {
|
|
1290
|
+
const batch = ordersArray.slice(i, i + MAX_BATCH_ORDER_SIZE);
|
|
1291
|
+
const result = await doBatchCreateOrder({
|
|
1292
|
+
orders: batch,
|
|
1293
|
+
symbol: position.symbol
|
|
1294
|
+
});
|
|
1295
|
+
await new Promise(
|
|
1296
|
+
(resolve) => setTimeout(resolve, batch.length * 110)
|
|
1297
|
+
);
|
|
1298
|
+
if (!result || result.error) {
|
|
1299
|
+
throw result?.error || new Error("Batch order failed");
|
|
1300
|
+
}
|
|
1301
|
+
}
|
|
1302
|
+
} else {
|
|
1303
|
+
const result = await doBatchCreateOrder({
|
|
1304
|
+
orders: ordersArray,
|
|
1305
|
+
symbol: position.symbol
|
|
1306
|
+
});
|
|
1307
|
+
if (!result || result.error) {
|
|
1308
|
+
throw result?.error || new Error("Batch order failed");
|
|
1309
|
+
}
|
|
1154
1310
|
}
|
|
1155
1311
|
onSuccess?.();
|
|
1156
1312
|
return true;
|
|
1157
1313
|
} catch (error) {
|
|
1158
1314
|
onError?.(error);
|
|
1159
1315
|
return false;
|
|
1316
|
+
} finally {
|
|
1317
|
+
setIsReversing(false);
|
|
1160
1318
|
}
|
|
1161
|
-
}, [
|
|
1319
|
+
}, [
|
|
1320
|
+
position,
|
|
1321
|
+
positionQty,
|
|
1322
|
+
reverseQty,
|
|
1323
|
+
isLong,
|
|
1324
|
+
doBatchCreateOrder,
|
|
1325
|
+
splitOrders,
|
|
1326
|
+
symbolInfo,
|
|
1327
|
+
validationError,
|
|
1328
|
+
onSuccess,
|
|
1329
|
+
onError
|
|
1330
|
+
]);
|
|
1162
1331
|
const displayInfo = React2.useMemo(() => {
|
|
1163
1332
|
if (!position || !symbolInfo) {
|
|
1164
1333
|
return null;
|
|
1165
1334
|
}
|
|
1166
1335
|
const base = symbolInfo("base");
|
|
1167
1336
|
const quote = symbolInfo("quote");
|
|
1168
|
-
const
|
|
1337
|
+
const baseDp2 = symbolInfo("base_dp");
|
|
1169
1338
|
const quoteDp = symbolInfo("quote_dp");
|
|
1170
1339
|
const leverage = position.leverage || 1;
|
|
1171
1340
|
return {
|
|
1172
1341
|
symbol: position.symbol,
|
|
1173
1342
|
base,
|
|
1174
1343
|
quote,
|
|
1175
|
-
baseDp,
|
|
1344
|
+
baseDp: baseDp2,
|
|
1176
1345
|
quoteDp,
|
|
1177
|
-
positionQty: new utils.Decimal(positionQty).todp(
|
|
1178
|
-
reverseQty: new utils.Decimal(reverseQty).todp(
|
|
1346
|
+
positionQty: new utils.Decimal(positionQty).todp(baseDp2).toString(),
|
|
1347
|
+
reverseQty: new utils.Decimal(reverseQty).todp(baseDp2).toString(),
|
|
1179
1348
|
markPrice: symbolMarketPrice ? new utils.Decimal(symbolMarketPrice).todp(quoteDp).toString() : "--",
|
|
1180
1349
|
leverage,
|
|
1181
1350
|
isLong
|
|
@@ -1192,11 +1361,13 @@ var useReversePositionScript = (options) => {
|
|
|
1192
1361
|
isEnabled,
|
|
1193
1362
|
setEnabled,
|
|
1194
1363
|
reversePosition,
|
|
1195
|
-
isReversing
|
|
1364
|
+
isReversing,
|
|
1196
1365
|
displayInfo,
|
|
1197
1366
|
positionQty,
|
|
1198
1367
|
reverseQty,
|
|
1199
|
-
isLong
|
|
1368
|
+
isLong,
|
|
1369
|
+
validationError,
|
|
1370
|
+
splitOrders
|
|
1200
1371
|
};
|
|
1201
1372
|
};
|
|
1202
1373
|
var ReversePositionWidget = (props) => {
|
|
@@ -1215,6 +1386,7 @@ var ReversePositionWidget = (props) => {
|
|
|
1215
1386
|
}
|
|
1216
1387
|
});
|
|
1217
1388
|
const actions = React2.useMemo(() => {
|
|
1389
|
+
const hasValidationError = !!state.validationError;
|
|
1218
1390
|
return {
|
|
1219
1391
|
primary: {
|
|
1220
1392
|
label: t("common.confirm"),
|
|
@@ -1235,10 +1407,11 @@ var ReversePositionWidget = (props) => {
|
|
|
1235
1407
|
}
|
|
1236
1408
|
},
|
|
1237
1409
|
loading: state.isReversing,
|
|
1238
|
-
disabled: state.isReversing || !state.displayInfo
|
|
1410
|
+
disabled: state.isReversing || !state.displayInfo || hasValidationError
|
|
1239
1411
|
},
|
|
1240
1412
|
secondary: {
|
|
1241
1413
|
label: t("common.cancel"),
|
|
1414
|
+
disabled: state.isReversing,
|
|
1242
1415
|
onClick: async () => {
|
|
1243
1416
|
reject?.("cancel");
|
|
1244
1417
|
hide();
|
|
@@ -1258,6 +1431,7 @@ var ReversePositionWidget = (props) => {
|
|
|
1258
1431
|
content: "oui-border oui-border-line-6"
|
|
1259
1432
|
},
|
|
1260
1433
|
actions,
|
|
1434
|
+
closable: !state.isReversing,
|
|
1261
1435
|
children: /* @__PURE__ */ jsxRuntime.jsx(ReversePosition, { ...state })
|
|
1262
1436
|
}
|
|
1263
1437
|
);
|
|
@@ -2020,12 +2194,12 @@ var TPSLEditIcon = () => {
|
|
|
2020
2194
|
};
|
|
2021
2195
|
var AddIcon = (props) => {
|
|
2022
2196
|
const { position, baseDp, quoteDp, tpslOrder } = usePositionsRowContext();
|
|
2023
|
-
const [needConfirm] = hooks.useLocalStorage("orderly_order_confirm", true);
|
|
2024
2197
|
const { t } = i18n.useTranslation();
|
|
2025
2198
|
const { isMobile } = ui.useScreen();
|
|
2026
2199
|
const onAdd = () => {
|
|
2027
2200
|
const dialogId = isMobile ? uiTpsl.TPSLSheetId : uiTpsl.TPSLDialogId;
|
|
2028
2201
|
const modalParams = {
|
|
2202
|
+
position,
|
|
2029
2203
|
symbol: position.symbol,
|
|
2030
2204
|
baseDP: baseDp,
|
|
2031
2205
|
quoteDP: quoteDp,
|
|
@@ -3435,7 +3609,7 @@ var CombinePositions = (props) => {
|
|
|
3435
3609
|
dataSource,
|
|
3436
3610
|
expanded: true,
|
|
3437
3611
|
getSubRows: (row) => row.children,
|
|
3438
|
-
generatedRowKey: (record) => record.
|
|
3612
|
+
generatedRowKey: (record) => `${record.account_id}${record.symbol || ""}`,
|
|
3439
3613
|
onCell: (column, record) => {
|
|
3440
3614
|
const isGroup = (record.children ?? []).length > 0;
|
|
3441
3615
|
if (isGroup) {
|
|
@@ -3459,6 +3633,9 @@ var CombinePositions = (props) => {
|
|
|
3459
3633
|
},
|
|
3460
3634
|
manualPagination: false,
|
|
3461
3635
|
pagination,
|
|
3636
|
+
classNames: {
|
|
3637
|
+
scroll: "oui-pb-10"
|
|
3638
|
+
},
|
|
3462
3639
|
testIds: {
|
|
3463
3640
|
body: "oui-testid-dataList-position-tab-body"
|
|
3464
3641
|
}
|