@orderly.network/hooks 2.10.2-alpha.0 → 3.0.0-beta.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.js CHANGED
@@ -1,9 +1,10 @@
1
1
  'use strict';
2
2
 
3
3
  var net = require('@orderly.network/net');
4
+ var React = require('react');
4
5
  var useSWR5 = require('swr');
5
6
  var types = require('@orderly.network/types');
6
- var React = require('react');
7
+ var pluginCore = require('@orderly.network/plugin-core');
7
8
  var utils = require('@orderly.network/utils');
8
9
  var useSWRMutation = require('swr/mutation');
9
10
  var useConstant = require('use-constant');
@@ -46,8 +47,8 @@ function _interopNamespace(e) {
46
47
  return Object.freeze(n);
47
48
  }
48
49
 
49
- var useSWR5__namespace = /*#__PURE__*/_interopNamespace(useSWR5);
50
50
  var React__default = /*#__PURE__*/_interopDefault(React);
51
+ var useSWR5__namespace = /*#__PURE__*/_interopNamespace(useSWR5);
51
52
  var useSWRMutation__default = /*#__PURE__*/_interopDefault(useSWRMutation);
52
53
  var useConstant__default = /*#__PURE__*/_interopDefault(useConstant);
53
54
  var useSWRInfinite__default = /*#__PURE__*/_interopDefault(useSWRInfinite);
@@ -64,9 +65,9 @@ var __export = (target, all) => {
64
65
  // src/version.ts
65
66
  if (typeof window !== "undefined") {
66
67
  window.__ORDERLY_VERSION__ = window.__ORDERLY_VERSION__ || {};
67
- window.__ORDERLY_VERSION__["@orderly.network/hooks"] = "2.10.2-alpha.0";
68
+ window.__ORDERLY_VERSION__["@orderly.network/hooks"] = "3.0.0-beta.0";
68
69
  }
69
- var version_default = "2.10.2-alpha.0";
70
+ var version_default = "3.0.0-beta.0";
70
71
  var fetcher = (url, init2 = {}, queryOptions) => net.get(url, init2, queryOptions?.formatter);
71
72
  var noCacheConfig = {
72
73
  dedupingInterval: 0,
@@ -97,21 +98,26 @@ function useConfig(key, defaultValue) {
97
98
  }
98
99
  return configStore;
99
100
  }
100
-
101
- // src/useQuery.ts
101
+ var PLUGIN_ID_HEADER = "X-Orderly-Plugin-Id";
102
102
  var useQuery = (query, options) => {
103
103
  const apiBaseUrl = useConfig("apiBaseUrl");
104
+ const pluginScope = pluginCore.usePluginScope();
104
105
  const { formatter, ...swrOptions } = options || {};
105
106
  if (typeof apiBaseUrl === "undefined") {
106
107
  throw new types.SDKError("please add OrderlyConfigProvider to your app");
107
108
  }
108
- return useSWR5__namespace.default(
109
- query,
110
- (url, init2) => fetcher(url.startsWith("http") ? url : `${apiBaseUrl}${url}`, init2, {
111
- formatter
112
- }),
113
- swrOptions
109
+ const fetcherFn = React.useCallback(
110
+ (url, init2) => {
111
+ const fullUrl = url.startsWith("http") ? url : `${apiBaseUrl}${url}`;
112
+ const headers = new Headers(init2?.headers);
113
+ if (pluginScope?.pluginId) {
114
+ headers.set(PLUGIN_ID_HEADER, pluginScope.pluginId);
115
+ }
116
+ return fetcher(fullUrl, { ...init2, headers }, { formatter });
117
+ },
118
+ [apiBaseUrl, pluginScope?.pluginId, formatter]
114
119
  );
120
+ return useSWR5__namespace.default(query, fetcherFn, swrOptions);
115
121
  };
116
122
  var timestampOffsetPromise = null;
117
123
  var timestampOffsetReady = false;
@@ -1110,12 +1116,12 @@ var findTPSLOrderPriceFromOrder = (order) => {
1110
1116
  sl_order_price
1111
1117
  };
1112
1118
  };
1113
- var findPositionTPSLFromOrders = (orders, symbol) => {
1119
+ var findPositionTPSLFromOrders = (orders, symbol, marginMode = types.MarginMode.CROSS) => {
1114
1120
  const fullPositionOrder = orders?.find((order) => {
1115
- return order.symbol === symbol && order.algo_type === types.AlgoOrderRootType.POSITIONAL_TP_SL && (order.root_algo_status === types.OrderStatus.NEW || order.root_algo_status === types.OrderStatus.REPLACED || order.root_algo_status === types.OrderStatus.PARTIAL_FILLED);
1121
+ return order.symbol === symbol && order.algo_type === types.AlgoOrderRootType.POSITIONAL_TP_SL && order.margin_mode === marginMode && (order.root_algo_status === types.OrderStatus.NEW || order.root_algo_status === types.OrderStatus.REPLACED || order.root_algo_status === types.OrderStatus.PARTIAL_FILLED);
1116
1122
  });
1117
1123
  const partialPositionOrders = orders?.filter((order) => {
1118
- return order.symbol === symbol && order.algo_type === types.AlgoOrderRootType.TP_SL && (order.root_algo_status === types.OrderStatus.NEW || order.root_algo_status === types.OrderStatus.REPLACED || order.root_algo_status === types.OrderStatus.PARTIAL_FILLED);
1124
+ return order.symbol === symbol && order.margin_mode === marginMode && order.algo_type === types.AlgoOrderRootType.TP_SL && (order.root_algo_status === types.OrderStatus.NEW || order.root_algo_status === types.OrderStatus.REPLACED || order.root_algo_status === types.OrderStatus.PARTIAL_FILLED);
1119
1125
  }).sort((a, b) => {
1120
1126
  return b.created_time - a.created_time;
1121
1127
  });
@@ -2140,9 +2146,11 @@ var useAppStore = zustand.create()(
2140
2146
  totalCollateral: utils.zero,
2141
2147
  totalValue: null,
2142
2148
  freeCollateral: utils.zero,
2149
+ freeCollateralUSDCOnly: utils.zero,
2143
2150
  availableBalance: 0,
2144
2151
  unsettledPnL: 0,
2145
- totalUnrealizedROI: 0
2152
+ totalUnrealizedROI: 0,
2153
+ usdcHolding: 0
2146
2154
  },
2147
2155
  appState: {
2148
2156
  positionsLoading: false,
@@ -2163,9 +2171,11 @@ var useAppStore = zustand.create()(
2163
2171
  totalCollateral: utils.zero,
2164
2172
  totalValue: null,
2165
2173
  freeCollateral: utils.zero,
2174
+ freeCollateralUSDCOnly: utils.zero,
2166
2175
  availableBalance: 0,
2167
2176
  unsettledPnL: 0,
2168
- totalUnrealizedROI: 0
2177
+ totalUnrealizedROI: 0,
2178
+ usdcHolding: 0
2169
2179
  };
2170
2180
  }, false);
2171
2181
  },
@@ -3961,25 +3971,27 @@ var OrderbookService = class _OrderbookService {
3961
3971
  };
3962
3972
  var orderBookService = OrderbookService.getInstance();
3963
3973
  var orderbook_service_default = orderBookService;
3974
+ var useMarkPriceStore = zustand.create((set, get3) => ({
3975
+ markPrices: {},
3976
+ // orderBook: {},
3977
+ // ask_bid: [],
3978
+ actions: {
3979
+ updateMarkPrice: (markPrice) => {
3980
+ set({
3981
+ markPrices: markPrice
3982
+ });
3983
+ },
3984
+ getMarkPriceBySymbol: (symbol) => {
3985
+ return get3().markPrices[symbol];
3986
+ }
3987
+ }
3988
+ }));
3989
+ var useMarkPriceBySymbol = (symbol) => useMarkPriceStore((state) => state.actions.getMarkPriceBySymbol(symbol));
3990
+ var useMarkPriceActions = () => useMarkPriceStore((state) => state.actions);
3991
+
3992
+ // src/orderly/useMarkPrice.ts
3964
3993
  var useMarkPrice = (symbol) => {
3965
- const ws = useWS();
3966
- const [price, setPrice] = React.useState(0);
3967
- const symbolRef = React.useRef(symbol);
3968
- symbolRef.current = symbol;
3969
- React.useEffect(() => {
3970
- const unsubscribe = ws.subscribe(`${symbol}@markprice`, {
3971
- onMessage: (message) => {
3972
- if (message.symbol !== symbolRef.current) {
3973
- unsubscribe?.();
3974
- return;
3975
- }
3976
- setPrice(message.price);
3977
- }
3978
- });
3979
- return () => {
3980
- unsubscribe?.();
3981
- };
3982
- }, [symbol]);
3994
+ const price = useMarkPriceBySymbol(symbol);
3983
3995
  return { data: price };
3984
3996
  };
3985
3997
  var useIndexPrice = (symbol) => {
@@ -4002,6 +4014,12 @@ var useIndexPrice = (symbol) => {
4002
4014
  };
4003
4015
  });
4004
4016
  };
4017
+
4018
+ // src/orderly/useMarkPricesStream.ts
4019
+ var useMarkPricesStream = () => {
4020
+ const data = useMarkPriceStore((state) => state.markPrices);
4021
+ return { data };
4022
+ };
4005
4023
  var useOpenInterest = (symbol) => {
4006
4024
  const ws = useWS();
4007
4025
  const symbolRef = React.useRef(symbol);
@@ -4021,29 +4039,6 @@ var useOpenInterest = (symbol) => {
4021
4039
  };
4022
4040
  });
4023
4041
  };
4024
- var useMarkPriceStore = zustand.create((set, get3) => ({
4025
- markPrices: {},
4026
- // orderBook: {},
4027
- // ask_bid: [],
4028
- actions: {
4029
- updateMarkPrice: (markPrice) => {
4030
- set({
4031
- markPrices: markPrice
4032
- });
4033
- },
4034
- getMarkPriceBySymbol: (symbol) => {
4035
- return get3().markPrices[symbol];
4036
- }
4037
- }
4038
- }));
4039
- var useMarkPriceBySymbol = (symbol) => useMarkPriceStore((state) => state.actions.getMarkPriceBySymbol(symbol));
4040
- var useMarkPriceActions = () => useMarkPriceStore((state) => state.actions);
4041
-
4042
- // src/orderly/useMarkPricesStream.ts
4043
- var useMarkPricesStream = () => {
4044
- const data = useMarkPriceStore((state) => state.markPrices);
4045
- return { data };
4046
- };
4047
4042
 
4048
4043
  // src/orderly/useTickerStream.ts
4049
4044
  var useTickerStream = (symbol) => {
@@ -4736,6 +4731,94 @@ var useLeverage = () => {
4736
4731
  maxLeverage: memoizedMaxLeverage
4737
4732
  };
4738
4733
  };
4734
+ var buildKey = (symbol, marginMode) => `${symbol}_${marginMode ?? types.MarginMode.CROSS}`;
4735
+ var useSymbolLeverageMap = () => {
4736
+ const { data, error, isLoading, mutate: mutate6 } = usePrivateQuery("/v1/client/leverages", {
4737
+ revalidateOnFocus: false,
4738
+ revalidateOnReconnect: false,
4739
+ errorRetryCount: 1
4740
+ });
4741
+ const leverages = React.useMemo(() => {
4742
+ if (!data || !Array.isArray(data)) return {};
4743
+ const map = {};
4744
+ for (const item of data) {
4745
+ const key = buildKey(item.symbol, item.margin_mode);
4746
+ map[key] = item.leverage;
4747
+ }
4748
+ return map;
4749
+ }, [data]);
4750
+ const getSymbolLeverage = (symbol, marginMode) => {
4751
+ if (!symbol) return void 0;
4752
+ const key = buildKey(symbol, marginMode);
4753
+ return leverages[key];
4754
+ };
4755
+ return {
4756
+ leverages,
4757
+ getSymbolLeverage,
4758
+ isLoading,
4759
+ error,
4760
+ refresh: mutate6
4761
+ };
4762
+ };
4763
+ var useMarginModes = () => {
4764
+ const { data, error, isLoading, mutate: mutate6 } = usePrivateQuery("/v1/client/margin_modes", {
4765
+ revalidateOnFocus: false,
4766
+ revalidateOnMount: true
4767
+ });
4768
+ const [setMarginModeInternal, { isMutating }] = useMutation(
4769
+ "/v1/client/margin_mode",
4770
+ "POST"
4771
+ );
4772
+ const marginModes = React.useMemo(() => {
4773
+ if (!data || !Array.isArray(data)) return {};
4774
+ const map = {};
4775
+ for (const item of data) {
4776
+ map[item.symbol] = item.default_margin_mode;
4777
+ }
4778
+ return map;
4779
+ }, [data]);
4780
+ const setMarginMode = (payload) => setMarginModeInternal(payload);
4781
+ const updateMarginMode = React.useCallback(
4782
+ async (payload) => {
4783
+ const result = await setMarginMode(payload);
4784
+ if (result.success) {
4785
+ await mutate6();
4786
+ return result;
4787
+ }
4788
+ throw new Error(result.message ?? "Failed to update margin mode");
4789
+ },
4790
+ [setMarginMode, mutate6]
4791
+ );
4792
+ return {
4793
+ marginModes,
4794
+ isLoading,
4795
+ error,
4796
+ refresh: mutate6,
4797
+ setMarginMode,
4798
+ updateMarginMode,
4799
+ isMutating
4800
+ };
4801
+ };
4802
+ var useMarginModeBySymbol = (symbol, fallback = types.MarginMode.CROSS) => {
4803
+ const { marginModes, isLoading, error, refresh, updateMarginMode } = useMarginModes();
4804
+ const marginMode = fallback === null ? marginModes[symbol] : marginModes[symbol] ?? fallback;
4805
+ const update = React.useCallback(
4806
+ async (mode) => {
4807
+ return updateMarginMode({
4808
+ symbol_list: [symbol],
4809
+ default_margin_mode: mode
4810
+ });
4811
+ },
4812
+ [symbol, updateMarginMode]
4813
+ );
4814
+ return {
4815
+ marginMode,
4816
+ isLoading,
4817
+ error,
4818
+ refresh,
4819
+ update
4820
+ };
4821
+ };
4739
4822
 
4740
4823
  // src/orderly/useOdosQuote.ts
4741
4824
  var useOdosQuote = () => {
@@ -5093,10 +5176,13 @@ var CalculatorService = class {
5093
5176
  // this.pendingCalc = [];
5094
5177
  // }
5095
5178
  async handleCalcQueue(context) {
5096
- const first = this.calcQueue.shift();
5097
- if (first) {
5179
+ const batchCollector = /* @__PURE__ */ new Map();
5180
+ let currentContext = context;
5181
+ while (this.calcQueue.length > 0) {
5182
+ const first = this.calcQueue.shift();
5183
+ if (!first) break;
5098
5184
  const { scope, data, options } = first;
5099
- const ctx = context || CalculatorContext.create(scope, data);
5185
+ const ctx = currentContext || CalculatorContext.create(scope, data);
5100
5186
  const calculators = this.calculators.get(scope);
5101
5187
  if (Array.isArray(calculators) && calculators.length) {
5102
5188
  try {
@@ -5104,13 +5190,46 @@ var CalculatorService = class {
5104
5190
  } catch (e) {
5105
5191
  }
5106
5192
  if (!options?.skipUpdate) {
5107
- this.scheduler.update(scope, calculators, ctx.outputToValue());
5193
+ this.collectUpdates(
5194
+ batchCollector,
5195
+ scope,
5196
+ calculators,
5197
+ ctx.outputToValue()
5198
+ );
5108
5199
  }
5109
5200
  }
5110
- if (this.calcQueue.length) {
5111
- this.handleCalcQueue(ctx);
5201
+ currentContext = ctx;
5202
+ }
5203
+ await this.commitBatchUpdates(batchCollector);
5204
+ this.ctx = currentContext;
5205
+ }
5206
+ collectUpdates(collector, scope, calculators, data) {
5207
+ if (!collector.has(scope)) {
5208
+ collector.set(scope, /* @__PURE__ */ new Map());
5209
+ }
5210
+ const scopeCollector = collector.get(scope);
5211
+ for (const calculator of calculators) {
5212
+ const item = data[calculator.name];
5213
+ if (item !== void 0 && item !== null) {
5214
+ scopeCollector.set(calculator.name, item);
5215
+ }
5216
+ }
5217
+ }
5218
+ async commitBatchUpdates(collector) {
5219
+ if (collector.size === 0) return;
5220
+ for (const [scope, updateMap] of collector.entries()) {
5221
+ const calculators = this.calculators.get(scope);
5222
+ if (!Array.isArray(calculators)) continue;
5223
+ const batchData = {};
5224
+ for (const [calculatorName, data] of updateMap.entries()) {
5225
+ batchData[calculatorName] = data;
5226
+ }
5227
+ try {
5228
+ this.scheduler.update(scope, calculators, batchData);
5229
+ } catch (e) {
5112
5230
  }
5113
5231
  }
5232
+ collector.clear();
5114
5233
  }
5115
5234
  stop() {
5116
5235
  this.calcQueue = [];
@@ -5141,6 +5260,18 @@ var cancelIdleCallbackPolyfill = (id) => {
5141
5260
  var safeRequestIdleCallback = typeof window !== "undefined" && window.requestIdleCallback ? window.requestIdleCallback.bind(window) : requestIdleCallbackPolyfill;
5142
5261
  typeof window !== "undefined" && window.cancelIdleCallback ? window.cancelIdleCallback.bind(window) : cancelIdleCallbackPolyfill;
5143
5262
  var ShardingScheduler = class {
5263
+ constructor() {
5264
+ /**
5265
+ * Maximum continuous execution time per frame (in milliseconds)
5266
+ * Prevents blocking the main thread for too long
5267
+ */
5268
+ this.MAX_CONTINUOUS_MS = 5;
5269
+ /**
5270
+ * Minimum remaining idle time threshold (in milliseconds)
5271
+ * Ensures the browser has enough idle time for other tasks
5272
+ */
5273
+ this.MIN_IDLE_REMAINING = 2;
5274
+ }
5144
5275
  // run(calculators: Calculator[]) {}
5145
5276
  calc(scope, calculators, data, ctx) {
5146
5277
  return new Promise((resolve, reject) => {
@@ -5181,28 +5312,27 @@ var ShardingScheduler = class {
5181
5312
  computation(data, processor, onComplete) {
5182
5313
  let index = 0;
5183
5314
  const results = [];
5184
- const estimatedShardSize = Math.min(data.length, 2);
5185
- function processNextShard(deadline) {
5186
- let shardSize = estimatedShardSize;
5187
- while (index + shardSize <= data.length && deadline.timeRemaining() > 0) {
5188
- const shard = data.slice(index, index + shardSize);
5189
- const result = processor(shard);
5190
- results.push(result);
5191
- index += shardSize;
5192
- if (deadline.timeRemaining() < 1) {
5193
- shardSize = Math.max(1, Math.floor(shardSize / 2));
5194
- } else {
5195
- shardSize = Math.min(data.length - index, shardSize * 2);
5315
+ const MAX_CONTINUOUS_MS = this.MAX_CONTINUOUS_MS;
5316
+ const MIN_IDLE_REMAINING = this.MIN_IDLE_REMAINING;
5317
+ const processNextShard = (deadline) => {
5318
+ const frameStart = performance.now();
5319
+ while (index < data.length) {
5320
+ const elapsed = performance.now() - frameStart;
5321
+ const remaining = deadline.timeRemaining();
5322
+ if (elapsed > MAX_CONTINUOUS_MS || remaining < MIN_IDLE_REMAINING) {
5323
+ safeRequestIdleCallback(processNextShard, {
5324
+ timeout: 1e3
5325
+ });
5326
+ return;
5196
5327
  }
5328
+ const result = processor([data[index]]);
5329
+ if (result && result.length > 0) {
5330
+ results.push(...result);
5331
+ }
5332
+ index++;
5197
5333
  }
5198
- if (index < data.length) {
5199
- safeRequestIdleCallback(processNextShard, {
5200
- timeout: 1e3
5201
- });
5202
- } else {
5203
- onComplete(results.flat());
5204
- }
5205
- }
5334
+ onComplete(results);
5335
+ };
5206
5336
  safeRequestIdleCallback(processNextShard, {
5207
5337
  timeout: 1e3
5208
5338
  });
@@ -5415,13 +5545,14 @@ var PositionCalculator = class extends BaseCalculator {
5415
5545
  const unsettlementPnL = unsettlementPnL_total.toNumber();
5416
5546
  let totalUnrealizedROI = 0, totalUnrealizedROI_index = 0;
5417
5547
  if (portfolio) {
5418
- const { totalValue, totalCollateral } = portfolio;
5548
+ const { totalValue, totalCollateral: crossMarginCollateral } = portfolio;
5419
5549
  rows = rows.map((item) => {
5420
5550
  const info = symbolsInfo[item.symbol];
5551
+ const totalCollateral = item.margin_mode === types.MarginMode.ISOLATED ? new utils.Decimal(item.margin ?? 0).add(item.unsettlement_pnl ?? 0).toNumber() : crossMarginCollateral.toNumber();
5421
5552
  const est_liq_price = perp.positions.liqPrice({
5422
5553
  symbol: item.symbol,
5423
5554
  markPrice: item.mark_price,
5424
- totalCollateral: totalCollateral.toNumber(),
5555
+ totalCollateral,
5425
5556
  positionQty: item.position_qty,
5426
5557
  positions: rows,
5427
5558
  MMR: item.mmr,
@@ -5580,7 +5711,9 @@ var PortfolioCalculator = class extends BaseCalculator {
5580
5711
  return {
5581
5712
  ...item,
5582
5713
  holding: data.holding[item.token].holding,
5583
- frozen: data.holding[item.token].frozen
5714
+ frozen: data.holding[item.token].frozen,
5715
+ isolatedMargin: data.holding[item.token].isolatedMargin,
5716
+ isolatedOrderFrozen: data.holding[item.token].isolatedOrderFrozen
5584
5717
  };
5585
5718
  }
5586
5719
  return item;
@@ -5616,7 +5749,14 @@ var PortfolioCalculator = class extends BaseCalculator {
5616
5749
  if (!holding || !positions3 || !Array.isArray(positions3.rows) || !markPrices || !indexPrices || !accountInfo) {
5617
5750
  return null;
5618
5751
  }
5619
- const unsettledPnL = ramda.pathOr(0, ["total_unsettled_pnl"])(positions3);
5752
+ const totallCrossUnsettledPnL = positions3.rows.reduce(
5753
+ (sum, pos) => pos.margin_mode === types.MarginMode.ISOLATED ? sum : sum + (pos.unsettled_pnl ?? 0),
5754
+ 0
5755
+ );
5756
+ const totalUnsettlementPnL = positions3.rows.reduce(
5757
+ (sum, pos) => sum + (pos.unsettled_pnl ?? 0),
5758
+ 0
5759
+ );
5620
5760
  const unrealizedPnL = ramda.pathOr(0, ["total_unreal_pnl"])(positions3);
5621
5761
  const [USDC_holding, nonUSDC] = parseHolding(
5622
5762
  holding,
@@ -5627,28 +5767,51 @@ var PortfolioCalculator = class extends BaseCalculator {
5627
5767
  const totalCollateral = perp.account.totalCollateral({
5628
5768
  USDCHolding: USDC_holding,
5629
5769
  nonUSDCHolding: nonUSDC,
5630
- unsettlementPnL: unsettledPnL
5770
+ unsettlementPnL: totallCrossUnsettledPnL,
5771
+ usdcBalancePendingShortQty: usdc?.pending_short ?? 0,
5772
+ usdcBalanceIsolatedOrderFrozen: usdc?.isolated_order_frozen ?? 0
5631
5773
  });
5774
+ const sumIsolatedMargin = positions3.rows.reduce((acc, curr) => {
5775
+ if (curr.margin_mode !== types.MarginMode.ISOLATED) {
5776
+ return acc;
5777
+ }
5778
+ return acc.add(curr.margin ?? 0);
5779
+ }, utils.zero);
5632
5780
  const totalValue = perp.account.totalValue({
5633
- totalUnsettlementPnL: unsettledPnL,
5781
+ totalUnsettlementPnL,
5634
5782
  USDCHolding: USDC_holding,
5635
- nonUSDCHolding: nonUSDC
5783
+ nonUSDCHolding: nonUSDC,
5784
+ totalIsolatedPositionMargin: sumIsolatedMargin.toNumber()
5636
5785
  });
5637
5786
  const totalUnrealizedROI = perp.account.totalUnrealizedROI({
5638
5787
  totalUnrealizedPnL: unrealizedPnL,
5639
5788
  totalValue: totalValue.toNumber()
5640
5789
  });
5790
+ const maxLeverageBySymbol = positions3.rows.reduce(
5791
+ (acc, position) => {
5792
+ if (position.margin_mode !== types.MarginMode.ISOLATED && position.leverage && !acc[position.symbol]) {
5793
+ acc[position.symbol] = position.leverage;
5794
+ }
5795
+ return acc;
5796
+ },
5797
+ {}
5798
+ );
5641
5799
  const totalInitialMarginWithOrders = perp.account.totalInitialMarginWithQty({
5642
5800
  positions: positions3.rows,
5801
+ orders: [],
5643
5802
  markPrices,
5644
5803
  IMR_Factors: accountInfo.imr_factor,
5645
- maxLeverage: accountInfo.max_leverage,
5804
+ maxLeverageBySymbol,
5646
5805
  symbolInfo: createGetter({ ...symbolsInfo })
5647
5806
  });
5648
5807
  const freeCollateral = perp.account.freeCollateral({
5649
5808
  totalCollateral,
5650
5809
  totalInitialMarginWithOrders
5651
5810
  });
5811
+ const freeCollateralUSDCOnly = perp.account.freeCollateralUSDCOnly({
5812
+ freeCollateral,
5813
+ nonUSDCHolding: nonUSDC
5814
+ });
5652
5815
  const availableBalance = perp.account.availableBalance({
5653
5816
  USDCHolding: usdc?.holding ?? 0,
5654
5817
  unsettlementPnL: positions3.total_unsettled_pnl ?? 0
@@ -5659,8 +5822,10 @@ var PortfolioCalculator = class extends BaseCalculator {
5659
5822
  totalUnrealizedROI,
5660
5823
  freeCollateral,
5661
5824
  availableBalance,
5662
- unsettledPnL,
5663
- holding
5825
+ unsettledPnL: totalUnsettlementPnL,
5826
+ holding,
5827
+ usdcHolding: USDC_holding,
5828
+ freeCollateralUSDCOnly
5664
5829
  };
5665
5830
  }
5666
5831
  update(data, scope) {
@@ -5669,10 +5834,12 @@ var PortfolioCalculator = class extends BaseCalculator {
5669
5834
  totalCollateral: data.totalCollateral,
5670
5835
  totalValue: data.totalValue,
5671
5836
  freeCollateral: data.freeCollateral,
5837
+ freeCollateralUSDCOnly: data.freeCollateralUSDCOnly,
5672
5838
  availableBalance: data.availableBalance,
5673
5839
  totalUnrealizedROI: data.totalUnrealizedROI,
5674
5840
  unsettledPnL: data.unsettledPnL,
5675
- holding: Array.isArray(data.holding) ? data.holding : []
5841
+ holding: Array.isArray(data.holding) ? data.holding : [],
5842
+ usdcHolding: typeof data.usdcHolding === "number" ? data.usdcHolding : data.usdcHolding.toNumber()
5676
5843
  });
5677
5844
  }
5678
5845
  }
@@ -5803,7 +5970,7 @@ var usePositionStream = (symbol = "all", options) => {
5803
5970
  }
5804
5971
  if (Array.isArray(tpslOrders) && tpslOrders.length) {
5805
5972
  rows = rows.map((item) => {
5806
- const { fullPositionOrder, partialPositionOrders } = findPositionTPSLFromOrders(tpslOrders, item.symbol);
5973
+ const { fullPositionOrder, partialPositionOrders } = findPositionTPSLFromOrders(tpslOrders, item.symbol, item.margin_mode);
5807
5974
  const full_tp_sl = fullPositionOrder ? findTPSLFromOrder(fullPositionOrder) : void 0;
5808
5975
  const partialPossitionOrder = partialPositionOrders && partialPositionOrders.length ? partialPositionOrders[0] : void 0;
5809
5976
  const partial_tp_sl = partialPossitionOrder ? findTPSLFromOrder(partialPossitionOrder) : void 0;
@@ -5935,15 +6102,21 @@ var useOrderStream = (params, options) => {
5935
6102
  }
5936
6103
  };
5937
6104
  }, [normalOrderKeyFn, options?.keeplive]);
5938
- const normalOrdersResponse = usePrivateInfiniteQuery(normalOrderKeyFn, {
5939
- initialSize: 1,
5940
- formatter: (data) => data,
5941
- revalidateOnFocus: false
5942
- });
5943
- const algoOrdersResponse = usePrivateInfiniteQuery(algoOrderKeyFn, {
5944
- formatter: (data) => data,
5945
- revalidateOnFocus: false
5946
- });
6105
+ const normalOrdersResponse = usePrivateInfiniteQuery(
6106
+ normalOrderKeyFn,
6107
+ {
6108
+ initialSize: 1,
6109
+ formatter: (data) => data,
6110
+ revalidateOnFocus: false
6111
+ }
6112
+ );
6113
+ const algoOrdersResponse = usePrivateInfiniteQuery(
6114
+ algoOrderKeyFn,
6115
+ {
6116
+ formatter: (data) => data,
6117
+ revalidateOnFocus: false
6118
+ }
6119
+ );
5947
6120
  const flattenOrders = React.useMemo(() => {
5948
6121
  if (!normalOrdersResponse.data || !algoOrdersResponse.data && !sourceTypeAll) {
5949
6122
  return null;
@@ -6061,7 +6234,9 @@ var useOrderStream = (params, options) => {
6061
6234
  // trailing stop order fields
6062
6235
  activated_price: order.activated_price,
6063
6236
  callback_value: order.callback_value,
6064
- callback_rate: order.callback_rate
6237
+ callback_rate: order.callback_rate,
6238
+ // Include margin_mode if present
6239
+ ...order.margin_mode && { margin_mode: order.margin_mode }
6065
6240
  });
6066
6241
  default:
6067
6242
  return doUpdateOrder({ ...order, order_id: orderId });
@@ -6256,7 +6431,14 @@ function formatPortfolio(inputs) {
6256
6431
  if (!holding || !positions3 || !Array.isArray(positions3.rows) || !markPrices || !indexPrices || !accountInfo || symbolsInfo?.isNil) {
6257
6432
  return null;
6258
6433
  }
6259
- const unsettledPnL = ramda.pathOr(0, ["total_unsettled_pnl"])(positions3);
6434
+ const totallCrossUnsettledPnL = positions3.rows.reduce(
6435
+ (sum, pos) => pos.margin_mode === types.MarginMode.ISOLATED ? sum : sum + (pos.unsettled_pnl ?? 0),
6436
+ 0
6437
+ );
6438
+ const totalUnsettlementPnL = positions3.rows.reduce(
6439
+ (sum, pos) => sum + (pos.unsettled_pnl ?? 0),
6440
+ 0
6441
+ );
6260
6442
  const unrealizedPnL = ramda.pathOr(0, ["total_unreal_pnl"])(positions3);
6261
6443
  const [USDC_holding, nonUSDC] = parseHolding(
6262
6444
  holding,
@@ -6267,29 +6449,51 @@ function formatPortfolio(inputs) {
6267
6449
  const totalCollateral = perp.account.totalCollateral({
6268
6450
  USDCHolding: USDC_holding,
6269
6451
  nonUSDCHolding: nonUSDC,
6270
- unsettlementPnL: unsettledPnL
6452
+ unsettlementPnL: totallCrossUnsettledPnL,
6453
+ usdcBalancePendingShortQty: usdc?.pending_short ?? 0,
6454
+ usdcBalanceIsolatedOrderFrozen: usdc?.isolated_order_frozen ?? 0
6271
6455
  });
6456
+ const sumIsolatedMargin = positions3.rows.reduce((acc, curr) => {
6457
+ if (curr.margin_mode !== types.MarginMode.ISOLATED) {
6458
+ return acc;
6459
+ }
6460
+ return acc.add(curr.margin ?? 0);
6461
+ }, utils.zero);
6272
6462
  const totalValue = perp.account.totalValue({
6273
- totalUnsettlementPnL: unsettledPnL,
6463
+ totalUnsettlementPnL,
6274
6464
  USDCHolding: USDC_holding,
6275
- nonUSDCHolding: nonUSDC
6465
+ nonUSDCHolding: nonUSDC,
6466
+ totalIsolatedPositionMargin: sumIsolatedMargin.toNumber()
6276
6467
  });
6277
6468
  const totalUnrealizedROI = perp.account.totalUnrealizedROI({
6278
6469
  totalUnrealizedPnL: unrealizedPnL,
6279
6470
  totalValue: totalValue.toNumber()
6280
6471
  });
6472
+ const maxLeverageBySymbol = positions3.rows.reduce(
6473
+ (acc, position) => {
6474
+ if (position.margin_mode !== types.MarginMode.ISOLATED && position.leverage && !acc[position.symbol]) {
6475
+ acc[position.symbol] = position.leverage;
6476
+ }
6477
+ return acc;
6478
+ },
6479
+ {}
6480
+ );
6281
6481
  const totalInitialMarginWithOrders = perp.account.totalInitialMarginWithQty({
6282
6482
  positions: positions3.rows,
6483
+ orders: [],
6283
6484
  markPrices,
6284
6485
  IMR_Factors: accountInfo.imr_factor,
6285
- // Not used
6286
- maxLeverage: accountInfo.max_leverage,
6287
- symbolInfo: symbolsInfo
6486
+ maxLeverageBySymbol,
6487
+ symbolInfo: createGetter({ ...symbolsInfo })
6288
6488
  });
6289
6489
  const freeCollateral = perp.account.freeCollateral({
6290
6490
  totalCollateral,
6291
6491
  totalInitialMarginWithOrders
6292
6492
  });
6493
+ const freeCollateralUSDCOnly = perp.account.freeCollateralUSDCOnly({
6494
+ freeCollateral,
6495
+ nonUSDCHolding: nonUSDC
6496
+ });
6293
6497
  const availableBalance = perp.account.availableBalance({
6294
6498
  USDCHolding: usdc?.holding ?? 0,
6295
6499
  unsettlementPnL: positions3.total_unsettled_pnl ?? 0
@@ -6300,8 +6504,9 @@ function formatPortfolio(inputs) {
6300
6504
  totalUnrealizedROI,
6301
6505
  freeCollateral,
6302
6506
  availableBalance,
6303
- unsettledPnL,
6304
- holding
6507
+ unsettledPnL: totalUnsettlementPnL,
6508
+ holding,
6509
+ freeCollateralUSDCOnly
6305
6510
  };
6306
6511
  }
6307
6512
  function formatPositions(data, accountInfo, symbolsInfo, fundingRates) {
@@ -6821,7 +7026,9 @@ var useSubAccountAlgoOrderStream = (params, options) => {
6821
7026
  // trailing stop order fields
6822
7027
  activated_price: order.activated_price,
6823
7028
  callback_value: order.callback_value,
6824
- callback_rate: order.callback_rate
7029
+ callback_rate: order.callback_rate,
7030
+ // include margin_mode if present (align with useOrderStream)
7031
+ ...order.margin_mode && { margin_mode: order.margin_mode }
6825
7032
  });
6826
7033
  default:
6827
7034
  return doUpdateOrder({ ...order, order_id: orderId });
@@ -7008,120 +7215,122 @@ var useCollateral = (options = { dp: 6 }) => {
7008
7215
  totalCollateral,
7009
7216
  totalValue,
7010
7217
  freeCollateral,
7218
+ freeCollateralUSDCOnly,
7011
7219
  availableBalance,
7012
7220
  unsettledPnL,
7013
- holding
7221
+ holding,
7222
+ usdcHolding
7014
7223
  } = useAppStore((state) => state.portfolio);
7015
7224
  const accountInfo = useAppStore((state) => state.accountInfo);
7016
7225
  return {
7017
7226
  totalCollateral: totalCollateral.toDecimalPlaces(dp).toNumber(),
7018
7227
  freeCollateral: freeCollateral.toDecimalPlaces(dp).toNumber(),
7228
+ freeCollateralUSDCOnly: freeCollateralUSDCOnly.toDecimalPlaces(dp).toNumber(),
7019
7229
  totalValue: totalValue?.toDecimalPlaces(dp).toNumber() ?? null,
7020
7230
  availableBalance,
7021
7231
  unsettledPnL,
7022
7232
  accountInfo,
7023
- holding
7233
+ holding,
7234
+ usdcHolding
7024
7235
  // @hidden
7025
7236
  // positions: positionsPath(positions),
7026
7237
  };
7027
7238
  };
7028
- var useLeverageBySymbol = (symbol) => {
7029
- const { state } = useAccount();
7030
- const ws = useWS();
7031
- const { data } = usePrivateQuery(
7032
- symbol ? `/v1/client/leverage?symbol=${symbol}` : null,
7033
- {
7034
- revalidateOnFocus: false
7035
- }
7036
- );
7037
- React.useEffect(() => {
7038
- if (!state.accountId || !symbol) return;
7039
- const unsubscribe = ws.privateSubscribe("account", {
7040
- onMessage: (data2) => {
7041
- const res = data2?.accountDetail?.symbolLeverage || {};
7042
- if (res.symbol === symbol) {
7043
- const key = [`/v1/client/leverage?symbol=${symbol}`, state.accountId];
7044
- useSWR5.mutate(
7045
- key,
7046
- (prevData) => {
7047
- return {
7048
- ...prevData,
7049
- leverage: res.leverage
7050
- };
7051
- },
7052
- {
7053
- revalidate: false
7054
- }
7055
- );
7056
- }
7057
- }
7058
- });
7059
- return () => unsubscribe?.();
7060
- }, [symbol, state.accountId]);
7061
- return data?.leverage;
7239
+
7240
+ // src/orderly/useLeverageBySymbol.ts
7241
+ var useLeverageBySymbol = (symbol, marginMode) => {
7242
+ const { getSymbolLeverage } = useSymbolLeverageMap();
7243
+ return getSymbolLeverage(symbol, marginMode);
7062
7244
  };
7063
7245
 
7064
7246
  // src/orderly/useMaxQty.ts
7065
- var useMaxQty = (symbol, side, reduceOnly = false) => {
7247
+ function useMaxQty(symbol, side, reduceOnlyOrOptions, marginMode) {
7248
+ const reduceOnly = typeof reduceOnlyOrOptions === "object" && reduceOnlyOrOptions !== null ? reduceOnlyOrOptions.reduceOnly ?? false : reduceOnlyOrOptions ?? false;
7249
+ const finalMarginMode = typeof reduceOnlyOrOptions === "object" && reduceOnlyOrOptions !== null ? reduceOnlyOrOptions.marginMode ?? types.MarginMode.CROSS : marginMode ?? types.MarginMode.CROSS;
7066
7250
  const positions3 = usePositions();
7067
7251
  const accountInfo = useAccountInfo();
7068
7252
  const symbolInfo = useSymbolsInfo();
7069
- const { totalCollateral } = useCollateral();
7253
+ const { totalCollateral, freeCollateralUSDCOnly } = useCollateral();
7070
7254
  const { data: markPrices } = useMarkPricesStream();
7071
- const symbolLeverage = useLeverageBySymbol(symbol);
7255
+ const symbolLeverage = useLeverageBySymbol(symbol, finalMarginMode);
7072
7256
  const maxQty = React.useMemo(() => {
7073
7257
  if (!symbol) return 0;
7074
- const positionQty = perp.account.getQtyFromPositions(
7075
- positions3 === null ? [] : positions3,
7076
- symbol
7258
+ if (!markPrices || !markPrices[symbol] || !accountInfo || !positions3) {
7259
+ return 0;
7260
+ }
7261
+ const positionsArray = (positions3 === null ? [] : positions3).filter(
7262
+ (position) => position.margin_mode === finalMarginMode
7077
7263
  );
7264
+ const positionQty = perp.account.getQtyFromPositions(positionsArray, symbol);
7078
7265
  if (reduceOnly) {
7079
- if (positionQty > 0) {
7080
- if (side === types.OrderSide.BUY) {
7081
- return 0;
7082
- } else {
7083
- return Math.abs(positionQty);
7084
- }
7085
- }
7086
- if (positionQty < 0) {
7087
- if (side === types.OrderSide.BUY) {
7088
- return Math.abs(positionQty);
7089
- } else {
7090
- return 0;
7091
- }
7092
- }
7093
- return 0;
7266
+ if (positionQty === 0) return 0;
7267
+ return side === types.OrderSide.BUY ? positionQty < 0 ? Math.abs(positionQty) : 0 : positionQty > 0 ? positionQty : 0;
7094
7268
  }
7095
- if (!markPrices || !markPrices[symbol] || !accountInfo || !positions3)
7096
- return 0;
7097
7269
  const getSymbolInfo = symbolInfo[symbol];
7098
- const currentSymbolPosition = positions3.find(
7099
- (item) => item.symbol === symbol
7100
- );
7270
+ let currentSymbolPosition;
7271
+ const otherPositions = [];
7272
+ for (const position of positionsArray) {
7273
+ if (position.symbol === symbol) {
7274
+ currentSymbolPosition = position;
7275
+ } else {
7276
+ otherPositions.push(position);
7277
+ }
7278
+ }
7279
+ const markPrice = markPrices[symbol];
7280
+ const baseIMR = getSymbolInfo("base_imr") ?? 0;
7281
+ const IMR_Factor = accountInfo.imr_factor[symbol] ?? 0;
7282
+ const leverage = symbolLeverage || currentSymbolPosition?.leverage || 1;
7101
7283
  const buyOrdersQty = currentSymbolPosition?.pending_long_qty ?? 0;
7102
7284
  const sellOrdersQty = currentSymbolPosition?.pending_short_qty ?? 0;
7103
- const otherPositions = !Array.isArray(positions3) ? [] : positions3.filter((item) => item.symbol !== symbol);
7285
+ if (finalMarginMode === types.MarginMode.ISOLATED) {
7286
+ const availableBalance = freeCollateralUSDCOnly;
7287
+ const pendingLongOrders = buyOrdersQty > 0 ? [{ referencePrice: markPrice, quantity: buyOrdersQty }] : [];
7288
+ const pendingSellOrders = sellOrdersQty > 0 ? [{ referencePrice: markPrice, quantity: sellOrdersQty }] : [];
7289
+ const markPriceDecimal = new utils.Decimal(markPrice);
7290
+ const leverageDecimal = new utils.Decimal(leverage);
7291
+ const isoOrderFrozenLong = buyOrdersQty > 0 ? markPriceDecimal.mul(buyOrdersQty).div(leverageDecimal).toNumber() : 0;
7292
+ const isoOrderFrozenShort = sellOrdersQty > 0 ? markPriceDecimal.mul(sellOrdersQty).div(leverageDecimal).toNumber() : 0;
7293
+ const symbolMaxNotional = accountInfo.max_notional?.[symbol] ?? perp.positions.maxPositionNotional({
7294
+ leverage,
7295
+ IMRFactor: IMR_Factor
7296
+ });
7297
+ const currentOrderReferencePrice = typeof reduceOnlyOrOptions === "object" && reduceOnlyOrOptions !== null && typeof reduceOnlyOrOptions.currentOrderReferencePrice === "number" && reduceOnlyOrOptions.currentOrderReferencePrice > 0 ? reduceOnlyOrOptions.currentOrderReferencePrice : markPrice;
7298
+ return perp.account.maxQtyForIsolatedMargin({
7299
+ symbol,
7300
+ orderSide: side,
7301
+ currentOrderReferencePrice,
7302
+ availableBalance,
7303
+ leverage,
7304
+ baseIMR,
7305
+ IMR_Factor,
7306
+ markPrice,
7307
+ positionQty,
7308
+ pendingLongOrders,
7309
+ pendingSellOrders,
7310
+ isoOrderFrozenLong,
7311
+ isoOrderFrozenShort,
7312
+ symbolMaxNotional
7313
+ });
7314
+ }
7104
7315
  const otherIMs = perp.account.otherIMs({
7105
7316
  positions: otherPositions,
7106
7317
  symbolInfo,
7107
7318
  markPrices,
7108
- IMR_Factors: accountInfo.imr_factor,
7109
- // Not used
7110
- maxLeverage: accountInfo.max_leverage
7319
+ IMR_Factors: accountInfo.imr_factor
7111
7320
  });
7112
7321
  return perp.account.maxQty(side, {
7113
- markPrice: markPrices[symbol],
7322
+ markPrice,
7114
7323
  symbol,
7115
7324
  baseMaxQty: getSymbolInfo("base_max"),
7116
7325
  totalCollateral,
7117
- maxLeverage: symbolLeverage || currentSymbolPosition?.leverage || 1,
7326
+ maxLeverage: leverage,
7118
7327
  takerFeeRate: accountInfo.futures_taker_fee_rate,
7119
- baseIMR: getSymbolInfo("base_imr"),
7328
+ baseIMR,
7120
7329
  otherIMs,
7121
7330
  positionQty,
7122
7331
  buyOrdersQty,
7123
7332
  sellOrdersQty,
7124
- IMR_Factor: accountInfo.imr_factor[symbol]
7333
+ IMR_Factor
7125
7334
  });
7126
7335
  }, [
7127
7336
  symbol,
@@ -7131,10 +7340,12 @@ var useMaxQty = (symbol, side, reduceOnly = false) => {
7131
7340
  accountInfo,
7132
7341
  symbolInfo,
7133
7342
  side,
7134
- totalCollateral
7343
+ totalCollateral,
7344
+ finalMarginMode,
7345
+ symbolLeverage
7135
7346
  ]);
7136
7347
  return Math.max(maxQty, 0);
7137
- };
7348
+ }
7138
7349
  var useMarginRatio = () => {
7139
7350
  const positions3 = usePositionStore((state2) => state2.positions.all);
7140
7351
  const { rows, notional } = positions3;
@@ -8440,54 +8651,92 @@ var usePrivateDataObserver = (options) => {
8440
8651
  }, [state.accountId, subOrder]);
8441
8652
  React.useEffect(() => {
8442
8653
  if (!state.accountId) return;
8443
- const key = ["/v1/positions", state.accountId];
8654
+ const positionsKey = ["/v1/positions", state.accountId];
8655
+ const leveragesKey = ["/v1/client/leverages", state.accountId];
8444
8656
  const unsubscribe = ws.privateSubscribe("account", {
8445
8657
  onMessage: (data) => {
8446
- const { symbol, leverage } = data?.accountDetail?.symbolLeverage || {};
8447
- if (symbol && leverage) {
8448
- useSWR5.mutate(
8449
- key,
8450
- (prevPositions) => {
8451
- if (prevPositions?.rows?.length) {
8452
- return {
8453
- ...prevPositions,
8454
- rows: prevPositions.rows.map((row) => {
8455
- return row.symbol === symbol ? { ...row, leverage } : row;
8456
- })
8457
- };
8458
- }
8459
- return prevPositions;
8460
- },
8461
- {
8462
- revalidate: false
8463
- }
8464
- );
8658
+ const { symbol, leverage, marginMode } = data?.accountDetail?.symbolLeverage || {};
8659
+ if (!symbol || leverage === void 0) {
8660
+ return;
8465
8661
  }
8466
- }
8467
- });
8468
- return () => unsubscribe?.();
8469
- }, [state.accountId]);
8470
- React.useEffect(() => {
8471
- if (!state.accountId) {
8472
- return;
8473
- }
8474
- const key = ["/v1/positions", state.accountId];
8475
- const unsubscribe = ws.privateSubscribe("position", {
8476
- onMessage: (data) => {
8477
- const { positions: nextPositions } = data;
8478
8662
  useSWR5.mutate(
8479
- key,
8663
+ positionsKey,
8480
8664
  (prevPositions) => {
8481
- if (!!prevPositions) {
8482
- const newPositions = {
8665
+ if (prevPositions?.rows?.length) {
8666
+ return {
8483
8667
  ...prevPositions,
8484
8668
  rows: prevPositions.rows.map((row) => {
8485
- const itemIndex = nextPositions.findIndex(
8486
- (item) => item.symbol === row.symbol
8487
- );
8488
- if (itemIndex >= 0) {
8489
- const itemArr = nextPositions.splice(itemIndex, 1);
8490
- const item = itemArr[0];
8669
+ return row.symbol === symbol && row.margin_mode === marginMode ? { ...row, leverage } : row;
8670
+ })
8671
+ };
8672
+ }
8673
+ return prevPositions;
8674
+ },
8675
+ {
8676
+ revalidate: false
8677
+ }
8678
+ );
8679
+ useSWR5.mutate(
8680
+ leveragesKey,
8681
+ (prev) => {
8682
+ if (!prev) {
8683
+ return [
8684
+ {
8685
+ symbol,
8686
+ leverage,
8687
+ margin_mode: marginMode
8688
+ }
8689
+ ];
8690
+ }
8691
+ const index = prev.findIndex(
8692
+ (item) => item.symbol === symbol && (item.margin_mode ?? types.MarginMode.CROSS) === (marginMode ?? types.MarginMode.CROSS)
8693
+ );
8694
+ if (index === -1) {
8695
+ return [
8696
+ ...prev,
8697
+ {
8698
+ symbol,
8699
+ leverage,
8700
+ margin_mode: marginMode
8701
+ }
8702
+ ];
8703
+ }
8704
+ const next = [...prev];
8705
+ next[index] = {
8706
+ ...next[index],
8707
+ leverage
8708
+ };
8709
+ return next;
8710
+ },
8711
+ {
8712
+ revalidate: false
8713
+ }
8714
+ );
8715
+ }
8716
+ });
8717
+ return () => unsubscribe?.();
8718
+ }, [state.accountId]);
8719
+ React.useEffect(() => {
8720
+ if (!state.accountId) {
8721
+ return;
8722
+ }
8723
+ const key = ["/v1/positions", state.accountId];
8724
+ const unsubscribe = ws.privateSubscribe("position", {
8725
+ onMessage: (data) => {
8726
+ const { positions: nextPositions } = data;
8727
+ useSWR5.mutate(
8728
+ key,
8729
+ (prevPositions) => {
8730
+ if (!!prevPositions) {
8731
+ const newPositions = {
8732
+ ...prevPositions,
8733
+ rows: prevPositions.rows.map((row) => {
8734
+ const itemIndex = nextPositions.findIndex(
8735
+ (item) => item.symbol === row.symbol && item.marginMode === row.margin_mode
8736
+ );
8737
+ if (itemIndex >= 0) {
8738
+ const itemArr = nextPositions.splice(itemIndex, 1);
8739
+ const item = itemArr[0];
8491
8740
  if (item.averageOpenPrice === 0 && item.positionQty !== 0) {
8492
8741
  return row;
8493
8742
  }
@@ -8666,6 +8915,61 @@ var OrderValidation = class {
8666
8915
 
8667
8916
  // src/services/orderCreator/baseCreator.ts
8668
8917
  var BaseOrderCreator = class {
8918
+ /**
8919
+ * Template method for order creation
8920
+ * Defines the algorithm structure with hooks for subclasses
8921
+ */
8922
+ create(values, config) {
8923
+ this.beforeCreate(values, config);
8924
+ const order = this.buildOrder(values, config);
8925
+ return this.afterCreate(order, config);
8926
+ }
8927
+ /**
8928
+ * Template method for order validation
8929
+ * Defines the algorithm structure with hooks for subclasses
8930
+ */
8931
+ validate(values, config) {
8932
+ this.beforeValidate(values, config);
8933
+ const errors = this.runValidations(values, config);
8934
+ return Promise.resolve(this.afterValidate(errors, values, config));
8935
+ }
8936
+ /**
8937
+ * Hook method called before order creation
8938
+ * Subclasses can override to perform pre-creation setup
8939
+ * @param values - Order values
8940
+ * @param config - Configuration
8941
+ */
8942
+ beforeCreate(values, config) {
8943
+ }
8944
+ /**
8945
+ * Hook method called after order creation
8946
+ * Subclasses can override to perform post-creation processing
8947
+ * @param order - The created order
8948
+ * @param config - Configuration
8949
+ * @returns The final order (possibly modified)
8950
+ */
8951
+ afterCreate(order, config) {
8952
+ return order;
8953
+ }
8954
+ /**
8955
+ * Hook method called before validation
8956
+ * Subclasses can override to perform pre-validation setup
8957
+ * @param values - Order values to validate
8958
+ * @param config - Configuration
8959
+ */
8960
+ beforeValidate(values, config) {
8961
+ }
8962
+ /**
8963
+ * Hook method called after validation
8964
+ * Subclasses can override to perform post-validation processing
8965
+ * @param errors - Validation errors found
8966
+ * @param values - Original order values
8967
+ * @param config - Configuration
8968
+ * @returns Final validation result (possibly modified)
8969
+ */
8970
+ afterValidate(errors, values, config) {
8971
+ return errors;
8972
+ }
8669
8973
  baseOrder(data) {
8670
8974
  const order = {
8671
8975
  symbol: data.symbol,
@@ -8673,7 +8977,8 @@ var BaseOrderCreator = class {
8673
8977
  side: data.side,
8674
8978
  reduce_only: data.reduce_only,
8675
8979
  order_quantity: data.order_quantity,
8676
- total: data.total
8980
+ total: data.total,
8981
+ margin_mode: data.margin_mode || types.MarginMode.CROSS
8677
8982
  // slippage: data.slippage,
8678
8983
  };
8679
8984
  if (data.order_type === types.OrderType.MARKET && !!data.slippage) {
@@ -8692,10 +8997,21 @@ var BaseOrderCreator = class {
8692
8997
  child_orders: [bracketOrder]
8693
8998
  };
8694
8999
  }
9000
+ /**
9001
+ * Base validation method that can be called by subclasses
9002
+ * Validates common order properties like quantity and min notional
9003
+ * @param values - Order values to validate
9004
+ * @param configs - Configuration
9005
+ * @returns Validation result (synchronous, not a Promise)
9006
+ */
8695
9007
  baseValidate(values, configs) {
8696
9008
  const errors = {};
8697
9009
  const { maxQty, symbol, markPrice } = configs;
8698
- let { order_quantity, total, order_price, reduce_only, order_type } = values;
9010
+ let order_quantity = values.order_quantity;
9011
+ const total = values.total;
9012
+ const order_price = values.order_price;
9013
+ const reduce_only = values.reduce_only;
9014
+ const order_type = values.order_type;
8699
9015
  const { min_notional, base_tick, quote_dp, quote_tick, base_dp } = symbol || {};
8700
9016
  if (!order_quantity) {
8701
9017
  if (total && order_price) {
@@ -8740,7 +9056,7 @@ var BaseOrderCreator = class {
8740
9056
  };
8741
9057
  }
8742
9058
  this.validateBracketOrder(values, configs, errors);
8743
- return Promise.resolve(errors);
9059
+ return errors;
8744
9060
  }
8745
9061
  totalToQuantity(order, config) {
8746
9062
  if (!order.order_quantity && order.total && order.order_price) {
@@ -8889,7 +9205,11 @@ var BBOOrderCreator = class extends BaseOrderCreator {
8889
9205
  super(...arguments);
8890
9206
  this.orderType = types.OrderType.LIMIT;
8891
9207
  }
8892
- create(values) {
9208
+ /**
9209
+ * Builds the BBO order
9210
+ * Implements template method hook
9211
+ */
9212
+ buildOrder(values) {
8893
9213
  const order = {
8894
9214
  ...this.baseOrder(values),
8895
9215
  level: values.level
@@ -8902,15 +9222,18 @@ var BBOOrderCreator = class extends BaseOrderCreator {
8902
9222
  "reduce_only",
8903
9223
  "side",
8904
9224
  "order_type",
9225
+ "margin_mode",
8905
9226
  "level"
8906
9227
  ],
8907
9228
  order
8908
9229
  );
8909
9230
  }
8910
- async validate(values, configs) {
8911
- return this.baseValidate(values, configs).then((errors) => {
8912
- return errors;
8913
- });
9231
+ /**
9232
+ * Runs base validations
9233
+ * Implements template method hook
9234
+ */
9235
+ runValidations(values, configs) {
9236
+ return this.baseValidate(values, configs);
8914
9237
  }
8915
9238
  };
8916
9239
  function getOrderPrice(order, askAndBid) {
@@ -8937,6 +9260,24 @@ function getOrderPrice(order, askAndBid) {
8937
9260
  }
8938
9261
  }
8939
9262
  }
9263
+ perp.order.getOrderReferencePrice;
9264
+ function getOrderReferencePriceFromOrder(order, askAndBid) {
9265
+ if (!askAndBid || askAndBid.length < 2) return null;
9266
+ if (!order.order_type || !order.side) {
9267
+ return null;
9268
+ }
9269
+ return perp.order.getOrderReferencePrice(
9270
+ {
9271
+ orderType: order.order_type,
9272
+ orderTypeExt: order.order_type_ext,
9273
+ side: order.side,
9274
+ limitPrice: order.order_price ? Number(order.order_price) : void 0,
9275
+ triggerPrice: order.trigger_price ? Number(order.trigger_price) : void 0
9276
+ },
9277
+ askAndBid[0],
9278
+ askAndBid[1]
9279
+ );
9280
+ }
8940
9281
  function getPriceRange(inputs) {
8941
9282
  const { basePrice, side, symbolInfo } = inputs;
8942
9283
  const { price_range, price_scope, quote_min, quote_max } = symbolInfo;
@@ -8950,97 +9291,170 @@ function getPriceRange(inputs) {
8950
9291
  min: minPriceNumber,
8951
9292
  max: scopePriceNumber
8952
9293
  };
8953
- const minPrice3 = Math.max(quote_min, priceRange?.min);
8954
- const maxPrice3 = Math.min(quote_max, priceRange?.max);
9294
+ const minPrice = Math.max(quote_min, priceRange?.min);
9295
+ const maxPrice = Math.min(quote_max, priceRange?.max);
8955
9296
  return {
8956
- minPrice: minPrice3,
8957
- maxPrice: maxPrice3
9297
+ minPrice,
9298
+ maxPrice
8958
9299
  };
8959
9300
  }
8960
9301
 
8961
- // src/services/orderCreator/baseBracketOrderCreator.ts
9302
+ // src/services/orderCreator/validators/TPSLValidationStrategy.ts
8962
9303
  var formatPrice = (price, quote_dp) => {
8963
9304
  return new utils.Decimal(price).toDecimalPlaces(quote_dp).toNumber();
8964
9305
  };
8965
- async function bracketOrderValidator(values, config) {
8966
- const result = /* @__PURE__ */ Object.create(null);
8967
- await Promise.resolve();
8968
- const {
8969
- // tp_enable,
8970
- // sl_enable,
8971
- tp_trigger_price,
8972
- tp_order_price,
8973
- tp_order_type,
8974
- sl_trigger_price,
8975
- sl_order_price,
8976
- sl_order_type,
8977
- side
8978
- } = values;
8979
- const qty = Number(values.quantity);
8980
- const maxQty = config.maxQty;
8981
- const type = values.order_type;
8982
- const { quote_max, quote_min, quote_dp } = config.symbol ?? {};
8983
- const mark_price = type === types.OrderType.MARKET ? config.markPrice : values.order_price ? Number(values.order_price) : void 0;
8984
- const tpslSide = side === types.OrderSide.BUY ? types.OrderSide.SELL : types.OrderSide.BUY;
8985
- if (!isNaN(qty) && qty > maxQty) {
8986
- result.quantity = OrderValidation.max("quantity", config.maxQty);
8987
- }
8988
- if (Number(tp_trigger_price) < 0) {
8989
- result.tp_trigger_price = OrderValidation.min("tp_trigger_price", 0);
8990
- }
8991
- if (Number(sl_trigger_price) < 0) {
8992
- result.sl_trigger_price = OrderValidation.min("sl_trigger_price", 0);
8993
- }
8994
- if (tp_order_type === types.OrderType.LIMIT && !tp_order_price) {
8995
- result.tp_order_price = OrderValidation.required("tp_order_price");
8996
- }
8997
- if (sl_order_type === types.OrderType.LIMIT && !sl_order_price) {
8998
- result.sl_order_price = OrderValidation.required("sl_order_price");
8999
- }
9000
- if (side === types.OrderSide.BUY && mark_price) {
9001
- if (!!sl_trigger_price && Number(sl_trigger_price) < quote_min) {
9002
- result.sl_trigger_price = OrderValidation.min(
9003
- "sl_trigger_price",
9004
- formatPrice(quote_min, quote_dp)
9306
+ var TPSLValidationStrategy = class {
9307
+ /**
9308
+ * Validates TP/SL order values
9309
+ * @param values - TP/SL order values including trigger prices, order prices, etc.
9310
+ * @param config - Configuration with symbol info and mark price
9311
+ * @returns Validation result object with any errors found
9312
+ */
9313
+ validate(values, config) {
9314
+ const result = /* @__PURE__ */ Object.create(null);
9315
+ const {
9316
+ tp_trigger_price,
9317
+ tp_order_price,
9318
+ tp_order_type,
9319
+ sl_trigger_price,
9320
+ sl_order_price,
9321
+ sl_order_type,
9322
+ side,
9323
+ quantity,
9324
+ order_type,
9325
+ order_price
9326
+ } = values;
9327
+ const qty = Number(quantity);
9328
+ const maxQty = config.maxQty;
9329
+ const { quote_max, quote_min, quote_dp, base_min } = config.symbol ?? {};
9330
+ const mark_price = order_type === types.OrderType.MARKET || order_type == null ? config.markPrice : order_price ? Number(order_price) : void 0;
9331
+ const tpslSide = side === types.OrderSide.BUY ? types.OrderSide.SELL : types.OrderSide.BUY;
9332
+ if (!isNaN(qty) && qty > maxQty) {
9333
+ result.quantity = OrderValidation.max("quantity", config.maxQty);
9334
+ }
9335
+ if (!isNaN(qty) && qty < (base_min ?? 0)) {
9336
+ result.quantity = OrderValidation.min("quantity", base_min ?? 0);
9337
+ }
9338
+ if (tp_trigger_price !== void 0 && tp_trigger_price !== "" && tp_trigger_price !== null && Number(tp_trigger_price) < 0) {
9339
+ result.tp_trigger_price = OrderValidation.min("tp_trigger_price", 0);
9340
+ }
9341
+ if (sl_trigger_price !== void 0 && sl_trigger_price !== "" && sl_trigger_price !== null && Number(sl_trigger_price) < 0) {
9342
+ result.sl_trigger_price = OrderValidation.min("sl_trigger_price", 0);
9343
+ }
9344
+ if (tp_order_type === types.OrderType.LIMIT && !tp_order_price) {
9345
+ result.tp_order_price = OrderValidation.required("tp_order_price");
9346
+ }
9347
+ if (sl_order_type === types.OrderType.LIMIT && !sl_order_price) {
9348
+ result.sl_order_price = OrderValidation.required("sl_order_price");
9349
+ }
9350
+ if (side === types.OrderSide.BUY && mark_price) {
9351
+ this.validateBuySide(
9352
+ {
9353
+ tp_trigger_price,
9354
+ tp_order_price,
9355
+ sl_trigger_price,
9356
+ sl_order_price
9357
+ },
9358
+ {
9359
+ mark_price,
9360
+ quote_min: quote_min ?? 0,
9361
+ quote_max: quote_max ?? 0,
9362
+ quote_dp: quote_dp ?? 0,
9363
+ tpslSide,
9364
+ symbol: config.symbol
9365
+ },
9366
+ result
9005
9367
  );
9006
- }
9007
- if (!!sl_trigger_price && Number(sl_trigger_price) > mark_price) {
9008
- result.sl_trigger_price = OrderValidation.max(
9009
- "sl_trigger_price",
9010
- formatPrice(mark_price, quote_dp)
9368
+ } else if (side === types.OrderSide.SELL && mark_price) {
9369
+ this.validateSellSide(
9370
+ {
9371
+ tp_trigger_price,
9372
+ tp_order_price,
9373
+ sl_trigger_price,
9374
+ sl_order_price
9375
+ },
9376
+ {
9377
+ mark_price,
9378
+ quote_min: quote_min ?? 0,
9379
+ quote_max: quote_max ?? 0,
9380
+ quote_dp: quote_dp ?? 0,
9381
+ tpslSide,
9382
+ symbol: config.symbol
9383
+ },
9384
+ result
9011
9385
  );
9012
9386
  }
9013
- if (!!tp_trigger_price && Number(tp_trigger_price) <= mark_price) {
9014
- result.tp_trigger_price = OrderValidation.min(
9015
- "tp_trigger_price",
9016
- formatPrice(mark_price, quote_dp)
9017
- );
9387
+ return Object.keys(result).length > 0 ? result : null;
9388
+ }
9389
+ /**
9390
+ * Validates TP/SL for BUY orders
9391
+ * For BUY orders:
9392
+ * - SL trigger price must be < mark price
9393
+ * - TP trigger price must be > mark price
9394
+ */
9395
+ validateBuySide(prices, config, result) {
9396
+ const {
9397
+ tp_trigger_price,
9398
+ tp_order_price,
9399
+ sl_trigger_price,
9400
+ sl_order_price
9401
+ } = prices;
9402
+ const { mark_price, quote_min, quote_max, quote_dp, tpslSide, symbol } = config;
9403
+ if (sl_trigger_price !== void 0 && sl_trigger_price !== "" && sl_trigger_price !== null) {
9404
+ const slTrigger = Number(sl_trigger_price);
9405
+ if (!isNaN(slTrigger)) {
9406
+ if (quote_min > 0 && slTrigger < quote_min) {
9407
+ result.sl_trigger_price = OrderValidation.min(
9408
+ "sl_trigger_price",
9409
+ formatPrice(quote_min, quote_dp)
9410
+ );
9411
+ }
9412
+ if (slTrigger >= mark_price) {
9413
+ result.sl_trigger_price = OrderValidation.max(
9414
+ "sl_trigger_price",
9415
+ formatPrice(mark_price, quote_dp)
9416
+ );
9417
+ }
9418
+ }
9018
9419
  }
9019
- if (!!tp_trigger_price && Number(tp_trigger_price) > quote_max) {
9020
- result.tp_trigger_price = OrderValidation.max(
9021
- "tp_trigger_price",
9022
- formatPrice(quote_max, quote_dp)
9023
- );
9420
+ if (tp_trigger_price !== void 0 && tp_trigger_price !== "" && tp_trigger_price !== null) {
9421
+ const tpTrigger = Number(tp_trigger_price);
9422
+ if (!isNaN(tpTrigger)) {
9423
+ if (tpTrigger <= mark_price) {
9424
+ result.tp_trigger_price = OrderValidation.min(
9425
+ "tp_trigger_price",
9426
+ formatPrice(mark_price, quote_dp)
9427
+ );
9428
+ }
9429
+ if (quote_max > 0 && tpTrigger > quote_max) {
9430
+ result.tp_trigger_price = OrderValidation.max(
9431
+ "tp_trigger_price",
9432
+ formatPrice(quote_max, quote_dp)
9433
+ );
9434
+ }
9435
+ }
9024
9436
  }
9025
9437
  if (sl_trigger_price && sl_order_price) {
9026
9438
  const priceRange = getPriceRange({
9027
9439
  side: tpslSide,
9028
9440
  basePrice: Number(sl_trigger_price),
9029
- symbolInfo: config.symbol
9441
+ symbolInfo: symbol
9030
9442
  });
9031
- if (Number(sl_order_price) < priceRange.minPrice) {
9443
+ const slOrderPrice = Number(sl_order_price);
9444
+ const slTrigger = Number(sl_trigger_price);
9445
+ if (slOrderPrice < priceRange.minPrice) {
9032
9446
  result.sl_order_price = OrderValidation.min(
9033
9447
  "sl_order_price",
9034
9448
  formatPrice(priceRange.minPrice, quote_dp)
9035
9449
  );
9036
9450
  }
9037
- if (Number(sl_order_price) > priceRange.maxPrice) {
9451
+ if (slOrderPrice > priceRange.maxPrice) {
9038
9452
  result.sl_order_price = OrderValidation.max(
9039
9453
  "sl_order_price",
9040
9454
  formatPrice(priceRange.maxPrice, quote_dp)
9041
9455
  );
9042
9456
  }
9043
- if (Number(sl_trigger_price) < Number(sl_order_price)) {
9457
+ if (slTrigger < slOrderPrice) {
9044
9458
  result.sl_trigger_price = OrderValidation.priceErrorMax("sl_trigger_price");
9045
9459
  }
9046
9460
  }
@@ -9048,69 +9462,96 @@ async function bracketOrderValidator(values, config) {
9048
9462
  const priceRange = getPriceRange({
9049
9463
  side: tpslSide,
9050
9464
  basePrice: Number(tp_trigger_price),
9051
- symbolInfo: config.symbol
9465
+ symbolInfo: symbol
9052
9466
  });
9053
- if (Number(tp_order_price) > priceRange.maxPrice) {
9467
+ const tpOrderPrice = Number(tp_order_price);
9468
+ const tpTrigger = Number(tp_trigger_price);
9469
+ if (tpOrderPrice > priceRange.maxPrice) {
9054
9470
  result.tp_order_price = OrderValidation.max(
9055
9471
  "tp_order_price",
9056
9472
  formatPrice(priceRange.maxPrice, quote_dp)
9057
9473
  );
9058
9474
  }
9059
- if (Number(tp_order_price) < priceRange.minPrice) {
9475
+ if (tpOrderPrice < priceRange.minPrice) {
9060
9476
  result.tp_order_price = OrderValidation.min(
9061
9477
  "tp_order_price",
9062
9478
  formatPrice(priceRange.minPrice, quote_dp)
9063
9479
  );
9064
9480
  }
9065
- if (Number(tp_trigger_price) > Number(tp_order_price)) {
9481
+ if (tpTrigger > tpOrderPrice) {
9066
9482
  result.tp_trigger_price = OrderValidation.priceErrorMax("tp_trigger_price");
9067
9483
  }
9068
9484
  }
9069
9485
  }
9070
- if (side === types.OrderSide.SELL && mark_price) {
9071
- if (!!sl_trigger_price && Number(sl_trigger_price) > quote_max) {
9072
- result.sl_trigger_price = OrderValidation.max(
9073
- "sl_trigger_price",
9074
- formatPrice(quote_max, quote_dp)
9075
- );
9076
- }
9077
- if (!!sl_trigger_price && Number(sl_trigger_price) < mark_price) {
9078
- result.sl_trigger_price = OrderValidation.min(
9079
- "sl_trigger_price",
9080
- formatPrice(mark_price, quote_dp)
9081
- );
9082
- }
9083
- if (!!tp_trigger_price && Number(tp_trigger_price) >= mark_price) {
9084
- result.tp_trigger_price = OrderValidation.max(
9085
- "tp_trigger_price",
9086
- formatPrice(mark_price, quote_dp)
9087
- );
9486
+ /**
9487
+ * Validates TP/SL for SELL orders
9488
+ * For SELL orders:
9489
+ * - SL trigger price must be > mark price
9490
+ * - TP trigger price must be < mark price
9491
+ */
9492
+ validateSellSide(prices, config, result) {
9493
+ const {
9494
+ tp_trigger_price,
9495
+ tp_order_price,
9496
+ sl_trigger_price,
9497
+ sl_order_price
9498
+ } = prices;
9499
+ const { mark_price, quote_min, quote_max, quote_dp, tpslSide, symbol } = config;
9500
+ if (sl_trigger_price !== void 0 && sl_trigger_price !== "" && sl_trigger_price !== null) {
9501
+ const slTrigger = Number(sl_trigger_price);
9502
+ if (!isNaN(slTrigger)) {
9503
+ if (quote_max > 0 && slTrigger > quote_max) {
9504
+ result.sl_trigger_price = OrderValidation.max(
9505
+ "sl_trigger_price",
9506
+ formatPrice(quote_max, quote_dp)
9507
+ );
9508
+ }
9509
+ if (slTrigger <= mark_price) {
9510
+ result.sl_trigger_price = OrderValidation.min(
9511
+ "sl_trigger_price",
9512
+ formatPrice(mark_price, quote_dp)
9513
+ );
9514
+ }
9515
+ }
9088
9516
  }
9089
- if (!!tp_trigger_price && Number(tp_trigger_price) < quote_min) {
9090
- result.tp_trigger_price = OrderValidation.min(
9091
- "tp_trigger_price",
9092
- formatPrice(quote_min, quote_dp)
9093
- );
9517
+ if (tp_trigger_price !== void 0 && tp_trigger_price !== "" && tp_trigger_price !== null) {
9518
+ const tpTrigger = Number(tp_trigger_price);
9519
+ if (!isNaN(tpTrigger)) {
9520
+ if (tpTrigger >= mark_price) {
9521
+ result.tp_trigger_price = OrderValidation.max(
9522
+ "tp_trigger_price",
9523
+ formatPrice(mark_price, quote_dp)
9524
+ );
9525
+ }
9526
+ if (quote_min > 0 && tpTrigger < quote_min) {
9527
+ result.tp_trigger_price = OrderValidation.min(
9528
+ "tp_trigger_price",
9529
+ formatPrice(quote_min, quote_dp)
9530
+ );
9531
+ }
9532
+ }
9094
9533
  }
9095
9534
  if (sl_trigger_price && sl_order_price) {
9096
9535
  const priceRange = getPriceRange({
9097
9536
  side: tpslSide,
9098
9537
  basePrice: Number(sl_trigger_price),
9099
- symbolInfo: config.symbol
9538
+ symbolInfo: symbol
9100
9539
  });
9101
- if (Number(sl_order_price) < priceRange.minPrice) {
9540
+ const slOrderPrice = Number(sl_order_price);
9541
+ const slTrigger = Number(sl_trigger_price);
9542
+ if (slOrderPrice < priceRange.minPrice) {
9102
9543
  result.sl_order_price = OrderValidation.min(
9103
9544
  "sl_order_price",
9104
9545
  formatPrice(priceRange.minPrice, quote_dp)
9105
9546
  );
9106
9547
  }
9107
- if (Number(sl_order_price) > priceRange.maxPrice) {
9548
+ if (slOrderPrice > priceRange.maxPrice) {
9108
9549
  result.sl_order_price = OrderValidation.max(
9109
9550
  "sl_order_price",
9110
9551
  formatPrice(priceRange.maxPrice, quote_dp)
9111
9552
  );
9112
9553
  }
9113
- if (Number(sl_trigger_price) > Number(sl_order_price)) {
9554
+ if (slTrigger > slOrderPrice) {
9114
9555
  result.sl_trigger_price = OrderValidation.priceErrorMin("sl_trigger_price");
9115
9556
  }
9116
9557
  }
@@ -9118,37 +9559,294 @@ async function bracketOrderValidator(values, config) {
9118
9559
  const priceRange = getPriceRange({
9119
9560
  side: tpslSide,
9120
9561
  basePrice: Number(tp_trigger_price),
9121
- symbolInfo: config.symbol
9562
+ symbolInfo: symbol
9122
9563
  });
9123
- if (Number(tp_order_price) < priceRange.minPrice) {
9564
+ const tpOrderPrice = Number(tp_order_price);
9565
+ const tpTrigger = Number(tp_trigger_price);
9566
+ if (tpOrderPrice < priceRange.minPrice) {
9124
9567
  result.tp_order_price = OrderValidation.min(
9125
9568
  "tp_order_price",
9126
9569
  formatPrice(priceRange.minPrice, quote_dp)
9127
9570
  );
9128
9571
  }
9129
- if (Number(tp_order_price) > priceRange.maxPrice) {
9572
+ if (tpOrderPrice > priceRange.maxPrice) {
9130
9573
  result.tp_order_price = OrderValidation.max(
9131
9574
  "tp_order_price",
9132
9575
  formatPrice(priceRange.maxPrice, quote_dp)
9133
9576
  );
9134
9577
  }
9135
- if (Number(tp_trigger_price) < Number(tp_order_price)) {
9578
+ if (tpTrigger < tpOrderPrice) {
9136
9579
  result.tp_trigger_price = OrderValidation.priceErrorMax("tp_trigger_price");
9137
9580
  }
9138
9581
  }
9139
9582
  }
9140
- return Object.keys(result).length > 0 ? result : null;
9583
+ };
9584
+
9585
+ // src/services/orderCreator/baseBracketOrderCreator.ts
9586
+ async function bracketOrderValidator(values, config) {
9587
+ const strategy = new TPSLValidationStrategy();
9588
+ return strategy.validate(values, config);
9141
9589
  }
9142
- var { maxPrice, minPrice, scopePrice } = perp.order;
9590
+
9591
+ // src/services/orderCreator/validators/BaseValidator.ts
9592
+ var BaseValidator = class {
9593
+ /**
9594
+ * Sets the next validator in the chain
9595
+ * @param validator - The next validator to call
9596
+ * @returns The next validator for method chaining
9597
+ */
9598
+ setNext(validator) {
9599
+ this.next = validator;
9600
+ return validator;
9601
+ }
9602
+ /**
9603
+ * Validates values and passes to next validator in chain
9604
+ * @param values - The values to validate
9605
+ * @param config - Configuration for validation
9606
+ * @param errors - Accumulated validation errors
9607
+ * @returns Updated validation result
9608
+ */
9609
+ validate(values, config, errors) {
9610
+ const result = this.doValidate(values, config);
9611
+ if (result) {
9612
+ errors[this.getFieldName()] = result;
9613
+ }
9614
+ return this.next?.validate(values, config, errors) ?? errors;
9615
+ }
9616
+ };
9617
+ var PriceValidationStrategy = class {
9618
+ /**
9619
+ * Validates order price against symbol constraints and price range
9620
+ * @param values - Object containing order_price, side, and order_type
9621
+ * @param config - Configuration with symbol info and mark price
9622
+ * @returns Validation error if price is invalid, undefined otherwise
9623
+ */
9624
+ validate(values, config) {
9625
+ const { order_price, side } = values;
9626
+ if (!order_price) {
9627
+ return OrderValidation.required("order_price");
9628
+ }
9629
+ const price = new utils.Decimal(order_price);
9630
+ const { symbol } = config;
9631
+ const { quote_max, quote_min, quote_dp, price_range, price_scope } = symbol;
9632
+ const maxPriceNumber = perp.order.maxPrice(config.markPrice, price_range);
9633
+ const minPriceNumber = perp.order.minPrice(config.markPrice, price_range);
9634
+ const scopePriceNumber = perp.order.scopePrice(
9635
+ config.markPrice,
9636
+ price_scope,
9637
+ side
9638
+ );
9639
+ const priceRange = side === types.OrderSide.BUY ? {
9640
+ min: scopePriceNumber,
9641
+ max: maxPriceNumber
9642
+ } : {
9643
+ min: minPriceNumber,
9644
+ max: scopePriceNumber
9645
+ };
9646
+ if (price.gt(quote_max)) {
9647
+ return OrderValidation.max("order_price", quote_max);
9648
+ }
9649
+ if (price.lt(quote_min)) {
9650
+ return OrderValidation.min("order_price", quote_min);
9651
+ }
9652
+ if (price.gt(priceRange.max)) {
9653
+ return OrderValidation.max(
9654
+ "order_price",
9655
+ new utils.Decimal(priceRange.max).todp(quote_dp).toString()
9656
+ );
9657
+ }
9658
+ if (price.lt(priceRange.min)) {
9659
+ return OrderValidation.min(
9660
+ "order_price",
9661
+ new utils.Decimal(priceRange.min).todp(quote_dp).toString()
9662
+ );
9663
+ }
9664
+ return void 0;
9665
+ }
9666
+ };
9667
+ var TriggerPriceValidationStrategy = class {
9668
+ /**
9669
+ * Validates trigger price against symbol constraints
9670
+ * @param values - Object containing trigger_price
9671
+ * @param config - Configuration with symbol info
9672
+ * @returns Validation error if trigger price is invalid, undefined otherwise
9673
+ */
9674
+ validate(values, config) {
9675
+ const { trigger_price } = values;
9676
+ const { symbol } = config;
9677
+ const { quote_max, quote_min } = symbol;
9678
+ if (!trigger_price) {
9679
+ return OrderValidation.required("trigger_price");
9680
+ }
9681
+ const triggerPrice = Number(trigger_price);
9682
+ if (triggerPrice > quote_max) {
9683
+ return OrderValidation.max("trigger_price", quote_max);
9684
+ }
9685
+ if (triggerPrice < quote_min || triggerPrice === 0) {
9686
+ return OrderValidation.min("trigger_price", quote_min);
9687
+ }
9688
+ return void 0;
9689
+ }
9690
+ };
9691
+
9692
+ // src/services/orderCreator/validators/PriceValidator.ts
9693
+ var PriceValidator = class extends BaseValidator {
9694
+ constructor() {
9695
+ super();
9696
+ this.strategy = new PriceValidationStrategy();
9697
+ }
9698
+ doValidate(values, config) {
9699
+ return this.strategy.validate(
9700
+ {
9701
+ order_price: values.order_price,
9702
+ side: values.side,
9703
+ order_type: values.order_type
9704
+ },
9705
+ config
9706
+ );
9707
+ }
9708
+ getFieldName() {
9709
+ return "order_price";
9710
+ }
9711
+ };
9712
+ var QuantityValidationStrategy = class {
9713
+ /**
9714
+ * Validates order quantity against symbol constraints
9715
+ * Also handles conversion from total to quantity if needed
9716
+ * @param values - Object containing order_quantity, total, and order_price
9717
+ * @param config - Configuration with symbol info and max quantity
9718
+ * @returns Validation error if quantity is invalid, undefined otherwise
9719
+ */
9720
+ validate(values, config) {
9721
+ let { order_quantity, total, order_price } = values;
9722
+ const { maxQty, symbol } = config;
9723
+ const { base_min, base_dp, quote_dp } = symbol;
9724
+ if (!order_quantity && total && order_price) {
9725
+ const totalNumber = new utils.Decimal(total);
9726
+ const qty2 = totalNumber.dividedBy(order_price).toFixed(quote_dp);
9727
+ order_quantity = qty2;
9728
+ }
9729
+ if (!order_quantity) {
9730
+ return OrderValidation.required("order_quantity");
9731
+ }
9732
+ const qty = new utils.Decimal(order_quantity);
9733
+ if (qty.lt(base_min)) {
9734
+ return OrderValidation.min(
9735
+ "order_quantity",
9736
+ new utils.Decimal(base_min).todp(base_dp).toString()
9737
+ );
9738
+ }
9739
+ if (qty.gt(maxQty)) {
9740
+ return OrderValidation.max(
9741
+ "order_quantity",
9742
+ new utils.Decimal(maxQty).todp(base_dp).toString()
9743
+ );
9744
+ }
9745
+ return void 0;
9746
+ }
9747
+ };
9748
+
9749
+ // src/services/orderCreator/validators/QuantityValidator.ts
9750
+ var QuantityValidator = class extends BaseValidator {
9751
+ constructor() {
9752
+ super();
9753
+ this.strategy = new QuantityValidationStrategy();
9754
+ }
9755
+ doValidate(values, config) {
9756
+ return this.strategy.validate(
9757
+ {
9758
+ order_quantity: values.order_quantity,
9759
+ total: values.total,
9760
+ order_price: values.order_price
9761
+ },
9762
+ config
9763
+ );
9764
+ }
9765
+ getFieldName() {
9766
+ return "order_quantity";
9767
+ }
9768
+ };
9769
+
9770
+ // src/services/orderCreator/validators/ValidationChain.ts
9771
+ var ValidationChain = class {
9772
+ constructor() {
9773
+ this.validators = [];
9774
+ }
9775
+ /**
9776
+ * Adds a validator to the chain
9777
+ * @param validator - The validator to add
9778
+ * @returns This chain instance for method chaining
9779
+ */
9780
+ addValidator(validator) {
9781
+ this.validators.push(validator);
9782
+ if (!this.head) {
9783
+ this.head = validator;
9784
+ } else {
9785
+ let current = this.head;
9786
+ while (current && current.next) {
9787
+ current = current.next;
9788
+ }
9789
+ if (current) {
9790
+ current.setNext(validator);
9791
+ }
9792
+ }
9793
+ return this;
9794
+ }
9795
+ /**
9796
+ * Adds multiple validators to the chain
9797
+ * @param validators - Array of validators to add
9798
+ * @returns This chain instance for method chaining
9799
+ */
9800
+ addValidators(validators) {
9801
+ validators.forEach((validator) => this.addValidator(validator));
9802
+ return this;
9803
+ }
9804
+ /**
9805
+ * Validates values using all validators in the chain
9806
+ * @param values - The values to validate
9807
+ * @param config - Configuration for validation
9808
+ * @returns Validation result with all errors found
9809
+ */
9810
+ validate(values, config) {
9811
+ const errors = {};
9812
+ if (this.head) {
9813
+ return this.head.validate(values, config, errors);
9814
+ }
9815
+ return errors;
9816
+ }
9817
+ /**
9818
+ * Clears all validators from the chain
9819
+ */
9820
+ clear() {
9821
+ this.validators = [];
9822
+ this.head = void 0;
9823
+ }
9824
+ /**
9825
+ * Gets the number of validators in the chain
9826
+ * @returns The number of validators
9827
+ */
9828
+ get length() {
9829
+ return this.validators.length;
9830
+ }
9831
+ };
9832
+
9833
+ // src/services/orderCreator/limitOrderCreator.ts
9143
9834
  var LimitOrderCreator = class extends BaseOrderCreator {
9144
9835
  constructor() {
9145
9836
  super(...arguments);
9837
+ // private priceValidationStrategy = new PriceValidationStrategy();
9838
+ this.validationChain = new ValidationChain().addValidator(new QuantityValidator()).addValidator(new PriceValidator());
9146
9839
  this.orderType = types.OrderType.LIMIT;
9147
9840
  }
9148
- create(values, config) {
9841
+ /**
9842
+ * Builds the limit order
9843
+ * Implements template method hook
9844
+ */
9845
+ buildOrder(values, config) {
9846
+ const orderlyValues = values;
9149
9847
  const order = {
9150
- ...this.baseOrder(values),
9151
- order_price: values.order_price
9848
+ ...this.baseOrder(orderlyValues),
9849
+ order_price: orderlyValues.order_price
9152
9850
  };
9153
9851
  this.totalToQuantity(order, config);
9154
9852
  return ramda.pick(
@@ -9157,61 +9855,26 @@ var LimitOrderCreator = class extends BaseOrderCreator {
9157
9855
  "order_price",
9158
9856
  "order_quantity",
9159
9857
  "visible_quantity",
9160
- "reduce_only",
9161
- "side",
9162
- "order_type",
9163
- "algo_type",
9164
- "child_orders"
9165
- ],
9166
- order
9167
- );
9168
- }
9169
- validate(values, config) {
9170
- return this.baseValidate(values, config).then((errors) => {
9171
- const { order_price, side } = values;
9172
- if (!order_price) {
9173
- errors.order_price = OrderValidation.required("order_price");
9174
- } else {
9175
- const price = new utils.Decimal(order_price);
9176
- const { symbol } = config;
9177
- const { price_range, price_scope, quote_max, quote_min } = symbol;
9178
- const maxPriceNumber = maxPrice(config.markPrice, price_range);
9179
- const minPriceNumber = minPrice(config.markPrice, price_range);
9180
- const scopePriceNumber = scopePrice(
9181
- config.markPrice,
9182
- price_scope,
9183
- side
9184
- );
9185
- const priceRange = side === "BUY" ? {
9186
- min: scopePriceNumber,
9187
- max: maxPriceNumber
9188
- } : {
9189
- min: minPriceNumber,
9190
- max: scopePriceNumber
9191
- };
9192
- if (price.gt(quote_max)) {
9193
- errors.order_price = OrderValidation.max("order_price", quote_max);
9194
- } else {
9195
- if (price.gt(priceRange?.max)) {
9196
- errors.order_price = OrderValidation.max(
9197
- "order_price",
9198
- new utils.Decimal(priceRange.max).todp(symbol.quote_dp).toString()
9199
- );
9200
- }
9201
- }
9202
- if (price.lt(quote_min)) {
9203
- errors.order_price = OrderValidation.min("order_price", quote_min);
9204
- } else {
9205
- if (price.lt(priceRange?.min)) {
9206
- errors.order_price = OrderValidation.min(
9207
- "order_price",
9208
- new utils.Decimal(priceRange.min).todp(symbol.quote_dp).toString()
9209
- );
9210
- }
9211
- }
9212
- }
9213
- return errors;
9214
- });
9858
+ "reduce_only",
9859
+ "side",
9860
+ "order_type",
9861
+ "margin_mode",
9862
+ "algo_type",
9863
+ "child_orders"
9864
+ ],
9865
+ order
9866
+ );
9867
+ }
9868
+ /**
9869
+ * Runs validations using validation chain
9870
+ * Implements template method hook
9871
+ */
9872
+ runValidations(values, config) {
9873
+ const orderlyValues = values;
9874
+ const errors = this.baseValidate(orderlyValues, config);
9875
+ const chainErrors = this.validationChain.validate(orderlyValues, config);
9876
+ Object.assign(errors, chainErrors);
9877
+ return errors;
9215
9878
  }
9216
9879
  };
9217
9880
 
@@ -9234,34 +9897,81 @@ var BracketLimitOrderCreator = class extends LimitOrderCreator {
9234
9897
  }
9235
9898
  };
9236
9899
 
9900
+ // src/services/orderCreator/validators/SlippageValidationStrategy.ts
9901
+ var SlippageValidationStrategy = class {
9902
+ /**
9903
+ * Validates slippage against estimated slippage
9904
+ * @param values - Object containing slippage value
9905
+ * @param config - Configuration with estimated slippage
9906
+ * @returns Validation error if slippage exceeds estimated, undefined otherwise
9907
+ */
9908
+ validate(values, config) {
9909
+ const slippage = Number(values.slippage);
9910
+ const estSlippage = Number.isNaN(config.estSlippage) ? 0 : Number(config.estSlippage) * 100;
9911
+ if (!isNaN(slippage) && estSlippage > slippage) {
9912
+ return {
9913
+ type: "max",
9914
+ message: "Estimated slippage exceeds your maximum allowed slippage.",
9915
+ value: estSlippage
9916
+ };
9917
+ }
9918
+ return void 0;
9919
+ }
9920
+ };
9921
+
9922
+ // src/services/orderCreator/validators/SlippageValidator.ts
9923
+ var SlippageValidator = class extends BaseValidator {
9924
+ constructor() {
9925
+ super();
9926
+ this.strategy = new SlippageValidationStrategy();
9927
+ }
9928
+ doValidate(values, config) {
9929
+ return this.strategy.validate(
9930
+ {
9931
+ slippage: values.slippage
9932
+ },
9933
+ config
9934
+ );
9935
+ }
9936
+ getFieldName() {
9937
+ return "slippage";
9938
+ }
9939
+ };
9940
+
9237
9941
  // src/services/orderCreator/marketOrderCreator.ts
9238
9942
  var MarketOrderCreator = class extends BaseOrderCreator {
9239
- create(values) {
9240
- const data = this.baseOrder(values);
9241
- delete data["order_price"];
9242
- delete data["total"];
9243
- delete data["trigger_price"];
9244
- delete data["isStopOrder"];
9245
- return {
9246
- ...data
9247
- };
9943
+ constructor() {
9944
+ super(...arguments);
9945
+ this.slippageValidationStrategy = new SlippageValidationStrategy();
9946
+ this.validationChain = new ValidationChain().addValidator(new QuantityValidator()).addValidator(new SlippageValidator());
9947
+ this.orderType = types.OrderType.MARKET;
9248
9948
  }
9249
- validate(values, configs) {
9250
- return this.baseValidate(values, configs).then((result) => {
9251
- const slippage = Number(values.slippage);
9252
- const estSlippage = Number.isNaN(configs.estSlippage) ? 0 : Number(configs.estSlippage) * 100;
9253
- if (!isNaN(slippage) && estSlippage > slippage) {
9254
- return {
9255
- ...result,
9256
- slippage: {
9257
- type: "max",
9258
- message: "Estimated slippage exceeds your maximum allowed slippage.",
9259
- value: estSlippage
9260
- }
9261
- };
9262
- }
9263
- return result;
9264
- });
9949
+ /**
9950
+ * Builds the market order
9951
+ * Implements template method hook
9952
+ */
9953
+ buildOrder(values, config) {
9954
+ const orderlyValues = values;
9955
+ const data = this.baseOrder(orderlyValues);
9956
+ const result = { ...data };
9957
+ delete result.order_price;
9958
+ delete result.total;
9959
+ delete result.trigger_price;
9960
+ if ("isStopOrder" in result) {
9961
+ delete result.isStopOrder;
9962
+ }
9963
+ return result;
9964
+ }
9965
+ /**
9966
+ * Runs validations using validation chain
9967
+ * Implements template method hook
9968
+ */
9969
+ runValidations(values, configs) {
9970
+ const orderlyValues = values;
9971
+ const result = this.baseValidate(orderlyValues, configs);
9972
+ const chainErrors = this.validationChain.validate(orderlyValues, configs);
9973
+ Object.assign(result, chainErrors);
9974
+ return result;
9265
9975
  }
9266
9976
  };
9267
9977
 
@@ -9293,14 +10003,26 @@ var FOKOrderCreator = class extends LimitOrderCreator {
9293
10003
 
9294
10004
  // src/services/orderCreator/generalCreator.ts
9295
10005
  var GeneralOrderCreator = class extends BaseOrderCreator {
9296
- create(data) {
10006
+ constructor() {
10007
+ super(...arguments);
10008
+ this.orderType = void 0;
10009
+ }
10010
+ /**
10011
+ * Builds the general order
10012
+ * Implements template method hook
10013
+ */
10014
+ buildOrder(data) {
9297
10015
  return {
9298
10016
  ...this.baseOrder(data),
9299
10017
  order_price: data.order_price,
9300
10018
  order_quantity: data.order_quantity
9301
10019
  };
9302
10020
  }
9303
- validate(values, configs) {
10021
+ /**
10022
+ * Runs base validations
10023
+ * Implements template method hook
10024
+ */
10025
+ runValidations(values, configs) {
9304
10026
  return super.baseValidate(values, configs);
9305
10027
  }
9306
10028
  };
@@ -9409,7 +10131,8 @@ function calcScaledOrderBatchBody(order, symbolInfo) {
9409
10131
  distribution_type,
9410
10132
  skew,
9411
10133
  reduce_only,
9412
- visible_quantity
10134
+ visible_quantity,
10135
+ margin_mode
9413
10136
  } = order;
9414
10137
  const prices = calcScaledOrderPrices({
9415
10138
  start_price,
@@ -9435,6 +10158,8 @@ function calcScaledOrderBatchBody(order, symbolInfo) {
9435
10158
  order_quantity: qtys[index],
9436
10159
  order_price: price,
9437
10160
  reduce_only,
10161
+ margin_mode: margin_mode || types.MarginMode.CROSS,
10162
+ // Default to CROSS if not provided for backward compatibility
9438
10163
  // it will be used for identify the scaled order from ws
9439
10164
  client_order_id: `scaled_${index}_${now}`
9440
10165
  };
@@ -9538,7 +10263,11 @@ var ScaledOrderCreator = class extends BaseOrderCreator {
9538
10263
  super(...arguments);
9539
10264
  this.orderType = types.OrderType.SCALED;
9540
10265
  }
9541
- create(values, config) {
10266
+ /**
10267
+ * Builds the scaled order
10268
+ * Implements template method hook
10269
+ */
10270
+ buildOrder(values, config) {
9542
10271
  const orders = calcScaledOrderBatchBody(values, config.symbol);
9543
10272
  const { total_orders, distribution_type, skew } = values;
9544
10273
  const order = {
@@ -9556,6 +10285,7 @@ var ScaledOrderCreator = class extends BaseOrderCreator {
9556
10285
  "reduce_only",
9557
10286
  "side",
9558
10287
  "order_type",
10288
+ "margin_mode",
9559
10289
  "orders",
9560
10290
  "total_orders",
9561
10291
  "distribution_type",
@@ -9564,7 +10294,11 @@ var ScaledOrderCreator = class extends BaseOrderCreator {
9564
10294
  order
9565
10295
  );
9566
10296
  }
9567
- async validate(values, config) {
10297
+ /**
10298
+ * Runs validations for scaled order
10299
+ * Implements template method hook
10300
+ */
10301
+ runValidations(values, config) {
9568
10302
  const { maxQty, askAndBid, markPrice, symbol } = config;
9569
10303
  const { base_dp, quote_dp } = config.symbol;
9570
10304
  const { order_quantity, total, total_orders, distribution_type, skew } = values;
@@ -9633,22 +10367,22 @@ function validatePrice(values, config) {
9633
10367
  if (!config.markPrice) {
9634
10368
  return errors;
9635
10369
  }
9636
- const { minPrice: minPrice3, maxPrice: maxPrice3 } = getPriceRange({
10370
+ const { minPrice, maxPrice } = getPriceRange({
9637
10371
  side: values.side,
9638
10372
  basePrice: config.markPrice,
9639
10373
  symbolInfo: config.symbol
9640
10374
  });
9641
10375
  const comparePrice = (key, value) => {
9642
10376
  const price = new utils.Decimal(value || 0);
9643
- if (price.lt(minPrice3)) {
10377
+ if (price.lt(minPrice)) {
9644
10378
  errors[key] = OrderValidation.min(
9645
10379
  key,
9646
- new utils.Decimal(minPrice3).todp(quote_dp).toString()
10380
+ new utils.Decimal(minPrice).todp(quote_dp).toString()
9647
10381
  );
9648
- } else if (price.gt(maxPrice3)) {
10382
+ } else if (price.gt(maxPrice)) {
9649
10383
  errors[key] = OrderValidation.max(
9650
10384
  key,
9651
- new utils.Decimal(maxPrice3).todp(quote_dp).toString()
10385
+ new utils.Decimal(maxPrice).todp(quote_dp).toString()
9652
10386
  );
9653
10387
  }
9654
10388
  };
@@ -9656,13 +10390,40 @@ function validatePrice(values, config) {
9656
10390
  comparePrice("end_price", end_price);
9657
10391
  return errors;
9658
10392
  }
9659
- var { maxPrice: maxPrice2, minPrice: minPrice2, scopePrice: scopePrice2 } = perp.order;
10393
+
10394
+ // src/services/orderCreator/validators/TriggerPriceValidator.ts
10395
+ var TriggerPriceValidator = class extends BaseValidator {
10396
+ constructor() {
10397
+ super();
10398
+ this.strategy = new TriggerPriceValidationStrategy();
10399
+ }
10400
+ doValidate(values, config) {
10401
+ return this.strategy.validate(
10402
+ {
10403
+ trigger_price: values.trigger_price
10404
+ },
10405
+ config
10406
+ );
10407
+ }
10408
+ getFieldName() {
10409
+ return "trigger_price";
10410
+ }
10411
+ };
10412
+
10413
+ // src/services/orderCreator/stopLimitOrderCreator.ts
9660
10414
  var StopLimitOrderCreator = class extends BaseOrderCreator {
9661
10415
  constructor() {
9662
10416
  super(...arguments);
10417
+ this.priceValidationStrategy = new PriceValidationStrategy();
10418
+ this.triggerPriceValidationStrategy = new TriggerPriceValidationStrategy();
10419
+ this.validationChain = new ValidationChain().addValidator(new QuantityValidator()).addValidator(new TriggerPriceValidator()).addValidator(new PriceValidator());
9663
10420
  this.orderType = types.OrderType.STOP_LIMIT;
9664
10421
  }
9665
- create(values, config) {
10422
+ /**
10423
+ * Builds the stop-limit order
10424
+ * Implements template method hook
10425
+ */
10426
+ buildOrder(values, config) {
9666
10427
  this.totalToQuantity(values, config);
9667
10428
  const order = {
9668
10429
  ...this.baseOrder(values),
@@ -9684,84 +10445,82 @@ var StopLimitOrderCreator = class extends BaseOrderCreator {
9684
10445
  "trigger_price_type",
9685
10446
  "side",
9686
10447
  "reduce_only",
10448
+ "margin_mode",
9687
10449
  "visible_quantity"
9688
10450
  ],
9689
10451
  order
9690
10452
  );
9691
10453
  }
9692
- validate(values, config) {
9693
- return this.baseValidate(values, config).then((errors) => {
9694
- const { order_price, trigger_price, side } = values;
9695
- const { symbol } = config;
9696
- const { price_range, price_scope, quote_max, quote_min } = symbol;
9697
- if (!order_price) {
9698
- errors.order_price = OrderValidation.required("order_price");
9699
- }
9700
- if (!trigger_price) {
9701
- errors.trigger_price = OrderValidation.required("trigger_price");
9702
- } else {
9703
- if (trigger_price > quote_max) {
9704
- errors.trigger_price = OrderValidation.max(
9705
- "trigger_price",
9706
- quote_max
9707
- );
9708
- } else if (trigger_price < quote_min || trigger_price == 0) {
9709
- errors.trigger_price = OrderValidation.min(
9710
- "trigger_price",
9711
- quote_min
9712
- );
9713
- } else if (order_price) {
9714
- const price = new utils.Decimal(order_price);
9715
- const maxPriceNumber = maxPrice2(trigger_price, price_range);
9716
- const minPriceNumber = minPrice2(trigger_price, price_range);
9717
- const scropePriceNumbere = scopePrice2(
9718
- trigger_price,
9719
- price_scope,
9720
- side
9721
- );
9722
- const priceRange = side === "BUY" ? {
9723
- min: scropePriceNumbere,
9724
- max: maxPriceNumber
9725
- } : {
9726
- min: minPriceNumber,
9727
- max: scropePriceNumbere
9728
- };
9729
- if (price.gt(quote_max)) {
9730
- errors.order_price = OrderValidation.max("order_price", quote_max);
9731
- } else {
9732
- if (price.gt(priceRange?.max)) {
9733
- errors.order_price = OrderValidation.max(
9734
- "order_price",
9735
- new utils.Decimal(priceRange.max).todp(symbol.quote_dp).toString()
9736
- );
9737
- }
9738
- }
9739
- if (price.lt(quote_min)) {
9740
- errors.order_price = OrderValidation.min("order_price", quote_min);
9741
- } else {
9742
- if (price.lt(priceRange?.min)) {
9743
- errors.order_price = OrderValidation.min(
9744
- "order_price",
9745
- new utils.Decimal(priceRange.min).todp(symbol.quote_dp).toString()
9746
- );
9747
- }
9748
- }
9749
- }
10454
+ /**
10455
+ * Runs validations using validation chain
10456
+ * Implements template method hook
10457
+ */
10458
+ runValidations(values, config) {
10459
+ const orderlyValues = values;
10460
+ const errors = this.baseValidate(orderlyValues, config);
10461
+ const triggerPrice = values.trigger_price;
10462
+ if (!triggerPrice || triggerPrice === 0) {
10463
+ errors.trigger_price = OrderValidation.required("trigger_price");
10464
+ } else {
10465
+ const triggerError = this.triggerPriceValidationStrategy.validate(
10466
+ { trigger_price: triggerPrice },
10467
+ config
10468
+ );
10469
+ if (triggerError) {
10470
+ errors.trigger_price = triggerError;
10471
+ }
10472
+ }
10473
+ const valuesWithFields = values;
10474
+ const orderPrice = valuesWithFields.order_price ?? valuesWithFields.price;
10475
+ const triggerPriceForPriceValidation = triggerPrice;
10476
+ const side = valuesWithFields.side ?? orderlyValues.side;
10477
+ if (!orderPrice) {
10478
+ errors.order_price = OrderValidation.required("order_price");
10479
+ } else if (orderPrice && triggerPriceForPriceValidation && side) {
10480
+ const modifiedConfig = {
10481
+ ...config,
10482
+ markPrice: Number(triggerPriceForPriceValidation)
10483
+ };
10484
+ const priceError = this.priceValidationStrategy.validate(
10485
+ {
10486
+ order_price: orderPrice,
10487
+ side,
10488
+ order_type: types.OrderType.LIMIT
10489
+ },
10490
+ modifiedConfig
10491
+ );
10492
+ if (priceError) {
10493
+ errors.order_price = priceError;
9750
10494
  }
9751
- return errors;
9752
- });
10495
+ } else if (orderPrice && triggerPriceForPriceValidation) {
10496
+ const { quote_max, quote_min } = config.symbol;
10497
+ const price = Number(orderPrice);
10498
+ if (quote_max && price > quote_max) {
10499
+ errors.order_price = OrderValidation.max("order_price", quote_max);
10500
+ } else if (quote_min && price < quote_min) {
10501
+ errors.order_price = OrderValidation.min("order_price", quote_min);
10502
+ }
10503
+ }
10504
+ return errors;
9753
10505
  }
9754
10506
  };
9755
10507
  var StopMarketOrderCreator = class extends BaseOrderCreator {
9756
- create(values) {
10508
+ constructor() {
10509
+ super(...arguments);
10510
+ this.triggerPriceValidationStrategy = new TriggerPriceValidationStrategy();
10511
+ this.validationChain = new ValidationChain().addValidator(new QuantityValidator()).addValidator(new TriggerPriceValidator());
10512
+ }
10513
+ /**
10514
+ * Builds the stop-market order
10515
+ * Implements template method hook
10516
+ */
10517
+ buildOrder(values) {
9757
10518
  const order = {
9758
10519
  ...this.baseOrder(values),
9759
- // order_price: values.order_price,
9760
10520
  trigger_price: values.trigger_price,
9761
10521
  algo_type: types.AlgoOrderRootType.STOP,
9762
10522
  type: types.OrderType.MARKET,
9763
10523
  quantity: values["order_quantity"],
9764
- // price: values["order_price"],
9765
10524
  trigger_price_type: types.TriggerPriceType.MARK_PRICE
9766
10525
  };
9767
10526
  return ramda.pick(
@@ -9771,225 +10530,40 @@ var StopMarketOrderCreator = class extends BaseOrderCreator {
9771
10530
  "algo_type",
9772
10531
  "type",
9773
10532
  "quantity",
9774
- // "price",
9775
10533
  "trigger_price_type",
9776
10534
  "side",
9777
10535
  "reduce_only",
10536
+ "margin_mode",
9778
10537
  "visible_quantity"
9779
10538
  ],
9780
10539
  order
9781
10540
  );
9782
10541
  }
9783
- validate(values, config) {
9784
- return this.baseValidate(values, config).then((errors) => {
9785
- const { trigger_price } = values;
9786
- const { symbol } = config;
9787
- const { quote_max, quote_min } = symbol;
9788
- if (!trigger_price) {
9789
- errors.trigger_price = OrderValidation.required("trigger_price");
9790
- } else if (trigger_price > quote_max) {
9791
- errors.trigger_price = OrderValidation.max("trigger_price", quote_max);
9792
- } else if (trigger_price < quote_min || trigger_price == 0) {
9793
- errors.trigger_price = OrderValidation.min("trigger_price", quote_min);
9794
- }
9795
- return errors;
9796
- });
10542
+ /**
10543
+ * Runs validations using validation chain
10544
+ * Implements template method hook
10545
+ */
10546
+ runValidations(values, config) {
10547
+ const errors = this.baseValidate(values, config);
10548
+ const chainErrors = this.validationChain.validate(values, config);
10549
+ Object.assign(errors, chainErrors);
10550
+ return errors;
9797
10551
  }
9798
10552
  };
9799
- var formatPrice2 = (price, quote_dp) => {
9800
- return new utils.Decimal(price).toDecimalPlaces(quote_dp).toNumber();
9801
- };
10553
+
10554
+ // src/services/orderCreator/baseAlgoCreator.ts
9802
10555
  var BaseAlgoOrderCreator = class {
10556
+ constructor() {
10557
+ this.tpslValidationStrategy = new TPSLValidationStrategy();
10558
+ }
9803
10559
  /**
9804
- * base validate
10560
+ * Validates TP/SL order using TPSLValidationStrategy
10561
+ * Consolidates validation logic from baseBracketOrderCreator
9805
10562
  */
9806
10563
  validate(values, config) {
9807
- const result = /* @__PURE__ */ Object.create(null);
9808
- return Promise.resolve().then(() => {
9809
- const {
9810
- tp_trigger_price,
9811
- sl_trigger_price,
9812
- side,
9813
- // tp_enable,
9814
- // sl_enable,
9815
- tp_order_type,
9816
- sl_order_type,
9817
- tp_order_price,
9818
- sl_order_price
9819
- } = values;
9820
- const qty = Number(values.quantity);
9821
- const maxQty = config.maxQty;
9822
- const orderType = values.order_type;
9823
- const {
9824
- quote_max,
9825
- quote_min,
9826
- price_scope,
9827
- quote_dp,
9828
- base_min,
9829
- min_notional
9830
- } = config.symbol ?? {};
9831
- if (!isNaN(qty) && qty > maxQty) {
9832
- result.quantity = OrderValidation.max("quantity", config.maxQty);
9833
- }
9834
- if (!isNaN(qty) && qty < base_min) {
9835
- result.quantity = OrderValidation.min("quantity", base_min);
9836
- }
9837
- if (Number(tp_trigger_price) < 0) {
9838
- result.tp_trigger_price = OrderValidation.min("tp_trigger_price", 0);
9839
- }
9840
- if (Number(sl_trigger_price) < 0) {
9841
- result.sl_trigger_price = OrderValidation.min("sl_trigger_price", 0);
9842
- }
9843
- if (tp_order_type === types.OrderType.LIMIT && !tp_order_price) {
9844
- result.tp_order_price = OrderValidation.required("tp_order_price");
9845
- }
9846
- if (sl_order_type === types.OrderType.LIMIT && !sl_order_price) {
9847
- result.sl_order_price = OrderValidation.required("sl_order_price");
9848
- }
9849
- const mark_price = orderType === types.OrderType.MARKET || orderType == null ? config.markPrice : values.order_price ? Number(values.order_price) : void 0;
9850
- const tpslSide = side === types.OrderSide.BUY ? types.OrderSide.SELL : types.OrderSide.BUY;
9851
- if (side === types.OrderSide.BUY && mark_price) {
9852
- if (!!sl_trigger_price && Number(sl_trigger_price) < quote_min) {
9853
- result.sl_trigger_price = OrderValidation.min(
9854
- "sl_trigger_price",
9855
- formatPrice2(quote_min, quote_dp)
9856
- );
9857
- }
9858
- if (!!sl_trigger_price && Number(sl_trigger_price) >= mark_price) {
9859
- result.sl_trigger_price = OrderValidation.max(
9860
- "sl_trigger_price",
9861
- formatPrice2(mark_price, quote_dp)
9862
- );
9863
- }
9864
- if (!!tp_trigger_price && Number(tp_trigger_price) <= mark_price) {
9865
- result.tp_trigger_price = OrderValidation.min(
9866
- "tp_trigger_price",
9867
- formatPrice2(mark_price, quote_dp)
9868
- );
9869
- }
9870
- if (!!tp_trigger_price && Number(tp_trigger_price) > quote_max) {
9871
- result.tp_trigger_price = OrderValidation.max(
9872
- "tp_trigger_price",
9873
- formatPrice2(quote_max, quote_dp)
9874
- );
9875
- }
9876
- if (sl_trigger_price && sl_order_price) {
9877
- const slOrderPriceRange = getPriceRange({
9878
- side: tpslSide,
9879
- basePrice: Number(sl_trigger_price),
9880
- symbolInfo: config.symbol
9881
- });
9882
- if (Number(sl_order_price) < slOrderPriceRange.minPrice) {
9883
- result.sl_order_price = OrderValidation.min(
9884
- "sl_order_price",
9885
- formatPrice2(slOrderPriceRange.minPrice, quote_dp)
9886
- );
9887
- }
9888
- if (Number(sl_order_price) > slOrderPriceRange.maxPrice) {
9889
- result.sl_order_price = OrderValidation.max(
9890
- "sl_order_price",
9891
- formatPrice2(slOrderPriceRange.maxPrice, quote_dp)
9892
- );
9893
- }
9894
- if (Number(sl_trigger_price) < Number(sl_order_price)) {
9895
- result.sl_trigger_price = OrderValidation.priceErrorMax("sl_trigger_price");
9896
- }
9897
- }
9898
- if (tp_trigger_price && tp_order_price) {
9899
- const tpOrderPriceRange = getPriceRange({
9900
- side: tpslSide,
9901
- basePrice: Number(tp_trigger_price),
9902
- symbolInfo: config.symbol
9903
- });
9904
- if (Number(tp_order_price) > tpOrderPriceRange.maxPrice) {
9905
- result.tp_order_price = OrderValidation.max(
9906
- "tp_order_price",
9907
- formatPrice2(tpOrderPriceRange.maxPrice, quote_dp)
9908
- );
9909
- }
9910
- if (Number(tp_order_price) < tpOrderPriceRange.minPrice) {
9911
- result.tp_order_price = OrderValidation.min(
9912
- "tp_order_price",
9913
- formatPrice2(tpOrderPriceRange.minPrice, quote_dp)
9914
- );
9915
- }
9916
- if (Number(tp_trigger_price) > Number(tp_order_price)) {
9917
- result.tp_trigger_price = OrderValidation.priceErrorMin("tp_trigger_price");
9918
- }
9919
- }
9920
- }
9921
- if (side === types.OrderSide.SELL && mark_price) {
9922
- if (!!sl_trigger_price && Number(sl_trigger_price) > quote_max) {
9923
- result.sl_trigger_price = OrderValidation.max(
9924
- "sl_trigger_price",
9925
- formatPrice2(quote_max, quote_dp)
9926
- );
9927
- }
9928
- if (!!sl_trigger_price && Number(sl_trigger_price) <= mark_price) {
9929
- result.sl_trigger_price = OrderValidation.min(
9930
- "sl_trigger_price",
9931
- formatPrice2(mark_price, quote_dp)
9932
- );
9933
- }
9934
- if (!!tp_trigger_price && Number(tp_trigger_price) >= mark_price) {
9935
- result.tp_trigger_price = OrderValidation.max(
9936
- "tp_trigger_price",
9937
- formatPrice2(mark_price, quote_dp)
9938
- );
9939
- }
9940
- if (!!tp_trigger_price && Number(tp_trigger_price) < quote_min) {
9941
- result.tp_trigger_price = OrderValidation.min(
9942
- "tp_trigger_price",
9943
- formatPrice2(quote_min, quote_dp)
9944
- );
9945
- }
9946
- if (sl_trigger_price && sl_order_price) {
9947
- const slOrderPriceRange = getPriceRange({
9948
- side: tpslSide,
9949
- basePrice: Number(sl_trigger_price),
9950
- symbolInfo: config.symbol
9951
- });
9952
- if (Number(sl_order_price) < slOrderPriceRange.minPrice) {
9953
- result.sl_order_price = OrderValidation.min(
9954
- "sl_order_price",
9955
- formatPrice2(slOrderPriceRange.minPrice, quote_dp)
9956
- );
9957
- }
9958
- if (Number(sl_order_price) > slOrderPriceRange.maxPrice) {
9959
- result.sl_order_price = OrderValidation.max(
9960
- "sl_order_price",
9961
- formatPrice2(slOrderPriceRange.maxPrice, quote_dp)
9962
- );
9963
- }
9964
- if (Number(sl_trigger_price) > Number(sl_order_price)) {
9965
- result.sl_trigger_price = OrderValidation.priceErrorMin("sl_trigger_price");
9966
- }
9967
- }
9968
- if (tp_trigger_price && tp_order_price) {
9969
- const tpOrderPriceRange = getPriceRange({
9970
- side: tpslSide,
9971
- basePrice: Number(tp_trigger_price),
9972
- symbolInfo: config.symbol
9973
- });
9974
- if (Number(tp_order_price) < tpOrderPriceRange.minPrice) {
9975
- result.tp_order_price = OrderValidation.min(
9976
- "tp_order_price",
9977
- formatPrice2(tpOrderPriceRange.minPrice, quote_dp)
9978
- );
9979
- }
9980
- if (Number(tp_order_price) > tpOrderPriceRange.maxPrice) {
9981
- result.tp_order_price = OrderValidation.max(
9982
- "tp_order_price",
9983
- formatPrice2(tpOrderPriceRange.maxPrice, quote_dp)
9984
- );
9985
- }
9986
- if (Number(tp_trigger_price) < Number(tp_order_price)) {
9987
- result.tp_trigger_price = OrderValidation.priceErrorMax("tp_trigger_price");
9988
- }
9989
- }
9990
- }
9991
- return Object.keys(result).length > 0 ? result : null;
9992
- });
10564
+ return Promise.resolve(
10565
+ this.tpslValidationStrategy.validate(values, config)
10566
+ );
9993
10567
  }
9994
10568
  };
9995
10569
 
@@ -10042,7 +10616,9 @@ var TPSLOrderCreator = class extends BaseAlgoOrderCreator {
10042
10616
  reduce_only: true,
10043
10617
  quantity: values.quantity,
10044
10618
  symbol: values.symbol,
10045
- child_orders
10619
+ child_orders,
10620
+ // Include margin_mode for isolated/cross margin support; default CROSS per order entry pattern
10621
+ margin_mode: values.margin_mode || types.MarginMode.CROSS
10046
10622
  };
10047
10623
  }
10048
10624
  crateUpdateOrder(values, oldValue, config) {
@@ -10144,7 +10720,9 @@ var TPSLPositionOrderCreator = class extends BaseAlgoOrderCreator {
10144
10720
  trigger_price_type: types.TriggerPriceType.MARK_PRICE,
10145
10721
  // reduce_only: true,
10146
10722
  symbol: values.symbol,
10147
- child_orders
10723
+ child_orders,
10724
+ // Include margin_mode for isolated/cross margin support; default CROSS per order entry pattern
10725
+ margin_mode: values.margin_mode || types.MarginMode.CROSS
10148
10726
  };
10149
10727
  }
10150
10728
  crateUpdateOrder(values, oldValue, config) {
@@ -10181,7 +10759,11 @@ var TrailingStopOrderCreator = class extends BaseOrderCreator {
10181
10759
  super(...arguments);
10182
10760
  this.orderType = types.OrderType.TRAILING_STOP;
10183
10761
  }
10184
- create(values, config) {
10762
+ /**
10763
+ * Builds the trailing stop order
10764
+ * Implements template method hook
10765
+ */
10766
+ buildOrder(values, config) {
10185
10767
  const { order_quantity, activated_price, callback_value, callback_rate } = values;
10186
10768
  const order = {
10187
10769
  ...this.baseOrder(values),
@@ -10202,6 +10784,7 @@ var TrailingStopOrderCreator = class extends BaseOrderCreator {
10202
10784
  "quantity",
10203
10785
  "side",
10204
10786
  "reduce_only",
10787
+ "margin_mode",
10205
10788
  "visible_quantity",
10206
10789
  "activated_price",
10207
10790
  "callback_value",
@@ -10210,28 +10793,34 @@ var TrailingStopOrderCreator = class extends BaseOrderCreator {
10210
10793
  order
10211
10794
  );
10212
10795
  }
10213
- async validate(values, config) {
10796
+ /**
10797
+ * Runs validations for trailing stop order
10798
+ * Implements template method hook
10799
+ */
10800
+ runValidations(values, config) {
10214
10801
  const { markPrice, symbol } = config;
10215
10802
  const { quote_dp } = config.symbol;
10216
10803
  const { side, activated_price, callback_value, callback_rate } = values;
10217
- const errors = await this.baseValidate(values, config);
10804
+ const errors = this.baseValidate(values, config);
10218
10805
  if (activated_price) {
10219
- const { minPrice: minPrice3, maxPrice: maxPrice3 } = getPriceRange2({
10806
+ const { minPrice, maxPrice } = getPriceRange({
10220
10807
  side,
10221
- markPrice,
10808
+ basePrice: markPrice,
10222
10809
  symbolInfo: symbol
10223
10810
  });
10224
- const activatedPrice = new utils.Decimal(activated_price);
10225
- if (activatedPrice.lt(minPrice3) || activatedPrice.equals(0)) {
10226
- errors.activated_price = OrderValidation.min(
10227
- "activated_price",
10228
- new utils.Decimal(minPrice3).todp(quote_dp).toString()
10229
- );
10230
- } else if (activatedPrice.gt(maxPrice3)) {
10231
- errors.activated_price = OrderValidation.max(
10232
- "activated_price",
10233
- new utils.Decimal(maxPrice3).todp(quote_dp).toString()
10234
- );
10811
+ if (!isNaN(minPrice) && !isNaN(maxPrice)) {
10812
+ const activatedPrice = new utils.Decimal(activated_price);
10813
+ if (activatedPrice.lt(minPrice) || activatedPrice.equals(0)) {
10814
+ errors.activated_price = OrderValidation.min(
10815
+ "activated_price",
10816
+ new utils.Decimal(minPrice).todp(quote_dp).toString()
10817
+ );
10818
+ } else if (activatedPrice.gt(maxPrice)) {
10819
+ errors.activated_price = OrderValidation.max(
10820
+ "activated_price",
10821
+ new utils.Decimal(maxPrice).todp(quote_dp).toString()
10822
+ );
10823
+ }
10235
10824
  }
10236
10825
  }
10237
10826
  if (!callback_value && !callback_rate) {
@@ -10263,23 +10852,6 @@ var TrailingStopOrderCreator = class extends BaseOrderCreator {
10263
10852
  return errors;
10264
10853
  }
10265
10854
  };
10266
- function getPriceRange2(inputs) {
10267
- const { markPrice, side, symbolInfo } = inputs;
10268
- const { quote_min, quote_max } = symbolInfo;
10269
- const priceRange = side === types.OrderSide.BUY ? {
10270
- min: quote_min,
10271
- max: markPrice
10272
- } : {
10273
- min: markPrice,
10274
- max: quote_max
10275
- };
10276
- const minPrice3 = Math.max(quote_min, priceRange?.min);
10277
- const maxPrice3 = Math.min(quote_max, priceRange?.max);
10278
- return {
10279
- minPrice: minPrice3,
10280
- maxPrice: maxPrice3
10281
- };
10282
- }
10283
10855
 
10284
10856
  // src/services/orderCreator/factory.ts
10285
10857
  var OrderFactory = class {
@@ -10402,27 +10974,63 @@ var calcEstLiqPrice = (order, askAndBid, inputs) => {
10402
10974
  markPrice,
10403
10975
  totalCollateral,
10404
10976
  futures_taker_fee_rate,
10405
- positions: positions3
10977
+ positions: positions3,
10978
+ // leverage,
10979
+ sumUnitaryFunding
10406
10980
  } = inputs;
10407
10981
  const orderFee = perp.order.orderFee({
10408
10982
  qty: quantity,
10409
10983
  price,
10410
10984
  futuresTakeFeeRate: Number(futures_taker_fee_rate) / 1e4
10411
10985
  });
10412
- const liqPrice = perp.order.estLiqPrice({
10413
- markPrice,
10414
- baseIMR: symbolInfo.base_imr,
10415
- baseMMR: symbolInfo.base_mmr,
10416
- totalCollateral,
10417
- positions: positions3 == null ? [] : positions3,
10418
- IMR_Factor: imr_factor,
10419
- orderFee,
10420
- newOrder: {
10421
- qty: quantity,
10422
- price,
10423
- symbol
10986
+ let liqPrice = 0;
10987
+ if (order.margin_mode === types.MarginMode.CROSS) {
10988
+ liqPrice = perp.order.estLiqPrice({
10989
+ markPrice,
10990
+ baseIMR: symbolInfo.base_imr,
10991
+ baseMMR: symbolInfo.base_mmr,
10992
+ totalCollateral,
10993
+ positions: positions3 == null ? [] : positions3,
10994
+ IMR_Factor: imr_factor,
10995
+ orderFee,
10996
+ newOrder: {
10997
+ qty: quantity,
10998
+ price,
10999
+ symbol
11000
+ }
11001
+ });
11002
+ } else {
11003
+ let isolatedPositionMargin = 0, costPosition = 0, positionQty = 0, lastSumUnitaryFunding = 0, leverage = 1;
11004
+ if (positions3) {
11005
+ const position = positions3.find(
11006
+ (p) => p.symbol === symbol && p.margin_mode === types.MarginMode.ISOLATED
11007
+ );
11008
+ if (position) {
11009
+ isolatedPositionMargin = position.margin ?? 0;
11010
+ costPosition = position.cost_position ?? 0;
11011
+ positionQty = position.position_qty ?? 0;
11012
+ lastSumUnitaryFunding = position.last_sum_unitary_funding ?? 0;
11013
+ leverage = position.leverage ? Number(position.leverage) : 1;
11014
+ }
10424
11015
  }
10425
- });
11016
+ liqPrice = perp.order.estLiqPriceIsolated({
11017
+ isolatedPositionMargin,
11018
+ costPosition,
11019
+ positionQty,
11020
+ sumUnitaryFunding,
11021
+ lastSumUnitaryFunding,
11022
+ markPrice,
11023
+ baseIMR: symbolInfo.base_imr,
11024
+ baseMMR: symbolInfo.base_mmr,
11025
+ IMR_Factor: imr_factor,
11026
+ leverage,
11027
+ newOrder: {
11028
+ symbol,
11029
+ qty: quantity,
11030
+ price
11031
+ }
11032
+ });
11033
+ }
10426
11034
  if (liqPrice <= 0) return null;
10427
11035
  return liqPrice;
10428
11036
  };
@@ -10480,7 +11088,9 @@ var useTaskProfitAndStopLossInternal = (position, options) => {
10480
11088
  // sl_enable: isEditing
10481
11089
  // ? checkIsEnableTpSL(options?.defaultOrder).sl_enable
10482
11090
  // : options?.tpslEnable?.sl_enable,
10483
- position_type: options?.positionType
11091
+ position_type: options?.positionType,
11092
+ // Use defaultOrder.margin_mode when editing; otherwise position.margin_mode; default CROSS for backward compatibility
11093
+ margin_mode: options?.defaultOrder?.margin_mode ?? position?.margin_mode ?? types.MarginMode.CROSS
10484
11094
  });
10485
11095
  const symbolInfo = useSymbolsInfo()[position.symbol]();
10486
11096
  const { data: markPrice } = useMarkPrice(order.symbol);
@@ -10783,11 +11393,53 @@ var useMaxLeverage = (symbol) => {
10783
11393
  };
10784
11394
  var useSymbolLeverage = (symbol) => {
10785
11395
  const symbolInfo = useSymbolInfo(symbol);
10786
- const [update, { isMutating }] = useMutation("/v1/client/leverage");
11396
+ const { state } = useAccount();
11397
+ const [updateMutation, { isMutating }] = useMutation("/v1/client/leverage");
10787
11398
  const maxLeverage = React.useMemo(() => {
10788
11399
  const baseIMR = symbolInfo?.("base_imr");
10789
11400
  return baseIMR ? 1 / baseIMR : 1;
10790
11401
  }, [symbolInfo]);
11402
+ const update = async (data) => {
11403
+ const result = await updateMutation(data);
11404
+ if (result?.success && data.symbol && state.accountId) {
11405
+ const key = ["/v1/client/leverages", state.accountId];
11406
+ useSWR5.mutate(
11407
+ key,
11408
+ (prev) => {
11409
+ if (!prev) {
11410
+ return [
11411
+ {
11412
+ symbol: data.symbol,
11413
+ leverage: data.leverage,
11414
+ margin_mode: data.margin_mode
11415
+ }
11416
+ ];
11417
+ }
11418
+ const index = prev.findIndex(
11419
+ (item) => item.symbol === data.symbol && (item.margin_mode ?? types.MarginMode.CROSS) === (data.margin_mode ?? types.MarginMode.CROSS)
11420
+ );
11421
+ if (index === -1) {
11422
+ return [
11423
+ ...prev,
11424
+ {
11425
+ symbol: data.symbol,
11426
+ leverage: data.leverage,
11427
+ margin_mode: data.margin_mode
11428
+ }
11429
+ ];
11430
+ }
11431
+ const next = [...prev];
11432
+ next[index] = {
11433
+ ...next[index],
11434
+ leverage: data.leverage
11435
+ };
11436
+ return next;
11437
+ },
11438
+ { revalidate: false }
11439
+ );
11440
+ }
11441
+ return result;
11442
+ };
10791
11443
  return {
10792
11444
  maxLeverage,
10793
11445
  update,
@@ -11524,8 +12176,8 @@ function useOrderEntry(symbolOrOrder, sideOrOptions, reduceOnly, options) {
11524
12176
  const keys = Object.keys(current);
11525
12177
  for (let i = 0; i < keys.length; i++) {
11526
12178
  const k = keys[i];
11527
- let preveValue = prev[k];
11528
- let currentValue = current[k];
12179
+ const preveValue = prev[k];
12180
+ const currentValue = current[k];
11529
12181
  if (typeof preveValue === "undefined" && typeof currentValue === "undefined")
11530
12182
  continue;
11531
12183
  if (preveValue !== currentValue) {
@@ -11538,7 +12190,12 @@ function useOrderEntry(symbolOrOrder, sideOrOptions, reduceOnly, options) {
11538
12190
  if (!key) return null;
11539
12191
  return { key, value, preValue };
11540
12192
  };
11541
- const maxQty = useMaxQty(symbol, sideValue, isReduceOnly);
12193
+ const { marginMode: symbolMarginMode } = useMarginModeBySymbol(symbol);
12194
+ const marginMode = typeof symbolOrOrder === "object" && symbolOrOrder.margin_mode ? symbolOrOrder.margin_mode : symbolMarginMode;
12195
+ const maxQty = useMaxQty(symbol, sideValue, {
12196
+ reduceOnly: isReduceOnly,
12197
+ marginMode: marginMode ?? types.MarginMode.CROSS
12198
+ });
11542
12199
  const parseString2Number = (order, key, dp) => {
11543
12200
  if (typeof order[key] !== "string") return;
11544
12201
  if (order[key] && order[key].startsWith(".")) {
@@ -12089,7 +12746,7 @@ var DataPaint = class extends BasePaint {
12089
12746
  );
12090
12747
  const { position, fontSize = 14 } = layout;
12091
12748
  let left = this._ratio(position.left);
12092
- let top = layout.position.top + offsetTop + this.transformTop;
12749
+ const top = layout.position.top + offsetTop + this.transformTop;
12093
12750
  let prevElementBoundingBox = {};
12094
12751
  if (typeof options.data?.position.side !== "undefined") {
12095
12752
  prevElementBoundingBox = this._drawText(options.data.position.side, {
@@ -12120,6 +12777,28 @@ var DataPaint = class extends BasePaint {
12120
12777
  fontFamily: options.fontFamily
12121
12778
  });
12122
12779
  }
12780
+ const marginMode = options.data?.position.marginMode;
12781
+ if (marginMode) {
12782
+ left += (prevElementBoundingBox.width ?? 0) + this._ratio(7);
12783
+ if (prevElementBoundingBox.width) {
12784
+ prevElementBoundingBox = this._drawText("|", {
12785
+ color: "rgba(255,255,255,0.2)",
12786
+ left,
12787
+ top: this._ratio(top),
12788
+ fontSize: this._ratio(fontSize),
12789
+ fontFamily: options.fontFamily
12790
+ });
12791
+ }
12792
+ left += (prevElementBoundingBox.width ?? 0) + this._ratio(7);
12793
+ const marginModeText = marginMode.charAt(0).toUpperCase() + marginMode.slice(1);
12794
+ prevElementBoundingBox = this._drawText(marginModeText, {
12795
+ color: layout.color,
12796
+ left,
12797
+ top: this._ratio(top),
12798
+ fontSize: this._ratio(fontSize),
12799
+ fontFamily: options.fontFamily
12800
+ });
12801
+ }
12123
12802
  if (typeof options.data?.position.leverage !== "undefined") {
12124
12803
  left += (prevElementBoundingBox.width ?? 0) + this._ratio(7);
12125
12804
  if (prevElementBoundingBox.width) {
@@ -12200,8 +12879,8 @@ var DataPaint = class extends BasePaint {
12200
12879
  (options.data?.position.informations.length ?? 0) === 2;
12201
12880
  const col = informations.length > 4 ? 3 : 2;
12202
12881
  informations.forEach((info, index) => {
12203
- let left = position.left + index % col * this.positionInfoCellWidth;
12204
- let top = position.top + Math.floor(index / col) * 38 + this.transformTop;
12882
+ const left = position.left + index % col * this.positionInfoCellWidth;
12883
+ const top = position.top + Math.floor(index / col) * 38 + this.transformTop;
12205
12884
  this._drawText(info.title, {
12206
12885
  left: this._ratio(left),
12207
12886
  top: this._ratio(top),
@@ -17743,95 +18422,111 @@ var initialOrderState = {
17743
18422
  trigger_price: "",
17744
18423
  tp_trigger_price: "",
17745
18424
  sl_trigger_price: "",
17746
- tp_order_type: types.OrderType.MARKET,
17747
- tp_pnl: "",
17748
- sl_pnl: "",
17749
- tp_offset_percentage: "",
17750
- sl_offset_percentage: "",
17751
- tp_offset: "",
17752
- sl_offset: "",
17753
- sl_order_type: types.OrderType.MARKET,
17754
18425
  total: "",
17755
- // scaled order
17756
- start_price: "",
17757
- end_price: "",
17758
- totalOrders: "",
17759
- distribution_type: "",
17760
- skew: "",
17761
- // symbol: "",
17762
- // trailing stop order
17763
- activated_price: "",
17764
- callback_value: "",
17765
- callback_rate: ""
18426
+ symbol: ""
17766
18427
  };
17767
- var useOrderStore = (initialOrder) => {
17768
- const [entry, setEntry] = React.useState(initialOrder);
17769
- const [estLeverage, setEstLeverage] = React.useState(null);
17770
- const [estLiquidationPrice, setEstLiquidationPrice] = React.useState(
17771
- null
17772
- );
17773
- const [errors, setErrors] = React.useState({});
17774
- const updateOrder = (order) => {
17775
- setEntry(
17776
- // if use {...draft, ...order} will cause extra updated when object it not changed
17777
- immer$1.produce((draft) => {
17778
- Object.assign(draft, order);
17779
- })
17780
- // (prev) => ({ ...prev, ...order })
17781
- );
17782
- };
17783
- const updateOrderByKey = (key, value) => {
17784
- setEntry(
17785
- immer$1.produce((draft) => {
17786
- draft[key] = value;
17787
- })
17788
- );
17789
- };
17790
- const restoreOrder = (order) => {
17791
- setEntry(immer$1.produce((draft) => order));
17792
- };
17793
- const updateOrderComputed = (data) => {
17794
- setEstLeverage(data.estLeverage);
17795
- setEstLiquidationPrice(data.estLiquidationPrice);
17796
- };
17797
- const resetOrder = (order) => {
17798
- setEntry(
17799
- immer$1.produce((draft) => ({
17800
- ...draft,
17801
- ...order ?? initialOrderState
17802
- }))
17803
- );
17804
- };
17805
- const hasTP_SL = () => {
17806
- return typeof entry.tp_trigger_price !== "undefined" || typeof entry.sl_trigger_price !== "undefined";
17807
- };
17808
- return {
17809
- entry,
17810
- estLeverage,
17811
- estLiquidationPrice,
17812
- errors,
18428
+ var useOrderStore = zustand.create()(
18429
+ immer.immer((set, get3) => ({
18430
+ entry: {
18431
+ side: types.OrderSide.BUY,
18432
+ order_type: types.OrderType.LIMIT,
18433
+ ...initialOrderState
18434
+ },
18435
+ estLeverage: null,
18436
+ estLiquidationPrice: null,
18437
+ errors: {},
17813
18438
  actions: {
17814
- updateOrder,
17815
- updateOrderByKey,
17816
- restoreOrder,
17817
- updateOrderComputed,
17818
- resetOrder,
17819
- hasTP_SL
18439
+ initOrder: (symbol, options) => {
18440
+ set((state) => {
18441
+ state.entry = {
18442
+ ...initialOrderState,
18443
+ symbol,
18444
+ side: options?.side ?? types.OrderSide.BUY,
18445
+ order_type: options?.order_type ?? types.OrderType.LIMIT,
18446
+ margin_mode: options?.margin_mode ?? types.MarginMode.CROSS
18447
+ };
18448
+ state.estLeverage = null;
18449
+ state.estLiquidationPrice = null;
18450
+ state.errors = {};
18451
+ });
18452
+ },
18453
+ hasTP_SL: () => {
18454
+ const order = get3().entry;
18455
+ return typeof order.tp_trigger_price !== "undefined" || typeof order.sl_trigger_price !== "undefined";
18456
+ },
18457
+ updateOrderComputed: (data) => {
18458
+ set(
18459
+ (state) => {
18460
+ state.estLeverage = data.estLeverage;
18461
+ state.estLiquidationPrice = data.estLiquidationPrice;
18462
+ },
18463
+ false
18464
+ // "updateOrderComputed"
18465
+ );
18466
+ },
18467
+ updateOrder: (order) => {
18468
+ set(
18469
+ (state) => {
18470
+ state.entry = {
18471
+ ...state.entry,
18472
+ ...order
18473
+ };
18474
+ },
18475
+ false
18476
+ // "updateOrder"
18477
+ );
18478
+ },
18479
+ updateOrderByKey: (key, value) => {
18480
+ set(
18481
+ (state) => {
18482
+ state.entry[key] = value;
18483
+ },
18484
+ false
18485
+ // "updateOrderByKey"
18486
+ );
18487
+ },
18488
+ restoreOrder: (order) => {
18489
+ set(
18490
+ (state) => {
18491
+ state.entry = order;
18492
+ },
18493
+ false
18494
+ // "restoreOrder"
18495
+ );
18496
+ },
18497
+ resetOrder: (_order) => {
18498
+ set(
18499
+ (state) => {
18500
+ state.entry.order_price = "";
18501
+ state.entry.order_quantity = "";
18502
+ state.entry.trigger_price = "";
18503
+ state.entry.total = "";
18504
+ state.entry.tp_trigger_price = "";
18505
+ state.entry.tp_pnl = "";
18506
+ state.entry.tp_offset = "";
18507
+ state.entry.tp_offset_percentage = "";
18508
+ state.entry.sl_trigger_price = "";
18509
+ state.entry.sl_pnl = "";
18510
+ state.entry.sl_offset = "";
18511
+ state.entry.sl_offset_percentage = "";
18512
+ },
18513
+ true
18514
+ // "resetOrder"
18515
+ );
18516
+ }
17820
18517
  }
17821
- };
17822
- };
17823
-
17824
- // src/next/useOrderEntry/useOrderEntry.internal.ts
18518
+ }))
18519
+ );
17825
18520
  var useOrderEntryNextInternal = (symbol, options = {}) => {
17826
18521
  const { symbolInfo, symbolLeverage } = options;
17827
- const initialOrder = {
17828
- side: types.OrderSide.BUY,
17829
- order_type: types.OrderType.LIMIT,
17830
- order_price: "",
17831
- symbol,
17832
- ...options.initialOrder
17833
- };
17834
- const { actions: orderEntryActions, entry: orderEntity } = useOrderStore(initialOrder);
18522
+ const orderEntity = useOrderStore((state) => state.entry);
18523
+ const orderEntryActions = useOrderStore((state) => state.actions);
18524
+ React.useEffect(() => {
18525
+ orderEntryActions.initOrder(symbol, options.initialOrder);
18526
+ if (options.initialOrder) {
18527
+ orderEntryActions.updateOrder(options.initialOrder);
18528
+ }
18529
+ }, [symbol]);
17835
18530
  const calculate2 = React.useCallback(
17836
18531
  (values, fieldName, value, markPrice, config) => {
17837
18532
  const fieldHandler = getCalculateHandler(fieldName);
@@ -17845,17 +18540,15 @@ var useOrderEntryNextInternal = (symbol, options = {}) => {
17845
18540
  },
17846
18541
  []
17847
18542
  );
17848
- React.useEffect(() => {
17849
- orderEntryActions.updateOrderByKey("symbol", symbol);
17850
- }, [orderEntryActions, symbol]);
17851
18543
  const setValue = (key, value, additional) => {
17852
18544
  if (!symbolInfo) {
17853
18545
  orderEntryActions.updateOrderByKey(key, value);
17854
18546
  return;
17855
18547
  }
18548
+ const currentEntry = useOrderStore.getState().entry;
17856
18549
  const { markPrice } = additional ?? { markPrice: 0 };
17857
18550
  let newValues = calculate2(
17858
- { ...orderEntity },
18551
+ { ...currentEntry },
17859
18552
  key,
17860
18553
  value,
17861
18554
  markPrice,
@@ -17936,7 +18629,8 @@ var useOrderEntryNextInternal = (symbol, options = {}) => {
17936
18629
  orderEntryActions.updateOrder(values);
17937
18630
  return;
17938
18631
  }
17939
- let newValues = { ...orderEntity };
18632
+ const currentEntry = useOrderStore.getState().entry;
18633
+ let newValues = { ...currentEntry };
17940
18634
  Object.keys(values).forEach((key) => {
17941
18635
  newValues = calculate2(
17942
18636
  newValues,
@@ -17952,10 +18646,11 @@ var useOrderEntryNextInternal = (symbol, options = {}) => {
17952
18646
  const onMarkPriceUpdated = React.useCallback(
17953
18647
  (markPrice, baseOn = []) => {
17954
18648
  if (!options.symbolInfo) return;
17955
- let newValues = { ...orderEntity };
18649
+ const currentEntry = useOrderStore.getState().entry;
18650
+ let newValues = { ...currentEntry };
17956
18651
  if (baseOn.length === 0) {
17957
18652
  newValues = calculate2(
17958
- { ...orderEntity },
18653
+ { ...currentEntry },
17959
18654
  "order_price",
17960
18655
  markPrice,
17961
18656
  markPrice,
@@ -17966,7 +18661,7 @@ var useOrderEntryNextInternal = (symbol, options = {}) => {
17966
18661
  newValues = calculate2(
17967
18662
  { ...newValues },
17968
18663
  key,
17969
- orderEntity[key],
18664
+ currentEntry[key],
17970
18665
  markPrice,
17971
18666
  options.symbolInfo
17972
18667
  );
@@ -17987,7 +18682,7 @@ var useOrderEntryNextInternal = (symbol, options = {}) => {
17987
18682
  }
17988
18683
  orderEntryActions.updateOrder(newValues);
17989
18684
  },
17990
- [calculate2, options.symbolInfo, orderEntity, orderEntryActions]
18685
+ [calculate2, options.symbolInfo, orderEntryActions]
17991
18686
  );
17992
18687
  const validate = (order, creator, options2) => {
17993
18688
  return creator?.validate(order, {
@@ -18036,6 +18731,7 @@ var useOrderEntry2 = (symbol, options = {}) => {
18036
18731
  const lastChangedField = React.useRef();
18037
18732
  const lastOrderTypeExt = React.useRef();
18038
18733
  const lastLevel = React.useRef();
18734
+ const fundingRates = useFundingRatesStore();
18039
18735
  const calculateTPSL_baseOn = React.useRef({
18040
18736
  tp: "",
18041
18737
  sl: ""
@@ -18044,7 +18740,9 @@ var useOrderEntry2 = (symbol, options = {}) => {
18044
18740
  const symbolConfig = useSymbolsInfo();
18045
18741
  const accountInfo = useAccountInfo();
18046
18742
  const positions3 = usePositions();
18047
- const symbolLeverage = useLeverageBySymbol(symbol);
18743
+ const entry = useOrderStore((s) => s.entry);
18744
+ const effectiveMarginMode = options?.initialOrder?.margin_mode ?? entry?.margin_mode ?? types.MarginMode.CROSS;
18745
+ const symbolLeverage = useLeverageBySymbol(symbol, effectiveMarginMode);
18048
18746
  const symbolInfo = symbolConfig[symbol]();
18049
18747
  const markPrice = actions.getMarkPriceBySymbol(symbol);
18050
18748
  const { orderMetadata } = useOrderlyContext();
@@ -18066,12 +18764,39 @@ var useOrderEntry2 = (symbol, options = {}) => {
18066
18764
  const [doCreateOrder, { isMutating }] = useMutation(
18067
18765
  getCreateOrderUrl(formattedOrder)
18068
18766
  );
18069
- const maxQtyValue = useMaxQty(
18070
- symbol,
18071
- formattedOrder.side,
18072
- formattedOrder.reduce_only
18073
- );
18767
+ const bestAskBid = askAndBid.current?.[0] || [];
18768
+ const referencePriceFromOrder = bestAskBid.length >= 2 && formattedOrder.order_type && formattedOrder.side ? getOrderReferencePriceFromOrder(formattedOrder, bestAskBid) : null;
18769
+ const maxBuyQtyValue = useMaxQty(symbol, types.OrderSide.BUY, {
18770
+ reduceOnly: formattedOrder.reduce_only,
18771
+ marginMode: effectiveMarginMode,
18772
+ currentOrderReferencePrice: referencePriceFromOrder && referencePriceFromOrder > 0 ? referencePriceFromOrder : void 0
18773
+ });
18774
+ const maxSellQtyValue = useMaxQty(symbol, types.OrderSide.SELL, {
18775
+ reduceOnly: formattedOrder.reduce_only,
18776
+ marginMode: effectiveMarginMode,
18777
+ currentOrderReferencePrice: referencePriceFromOrder && referencePriceFromOrder > 0 ? referencePriceFromOrder : void 0
18778
+ });
18779
+ const maxQtyValue = formattedOrder.side === types.OrderSide.BUY ? maxBuyQtyValue : maxSellQtyValue;
18074
18780
  const maxQty = options.maxQty ?? maxQtyValue;
18781
+ const maxQtys = React.useMemo(
18782
+ () => ({
18783
+ maxBuy: formattedOrder.side === types.OrderSide.BUY ? (
18784
+ // @ts-ignore
18785
+ options.maxQty ?? maxBuyQtyValue
18786
+ ) : maxBuyQtyValue,
18787
+ maxSell: formattedOrder.side === types.OrderSide.SELL ? (
18788
+ // @ts-ignore
18789
+ options.maxQty ?? maxSellQtyValue
18790
+ ) : maxSellQtyValue
18791
+ }),
18792
+ [
18793
+ formattedOrder.side,
18794
+ maxBuyQtyValue,
18795
+ maxSellQtyValue,
18796
+ // @ts-ignore
18797
+ options.maxQty
18798
+ ]
18799
+ );
18075
18800
  const updateOrderPrice = () => {
18076
18801
  const order_type = formattedOrder.order_type;
18077
18802
  const order_type_ext = formattedOrder.order_type_ext ?? lastOrderTypeExt.current;
@@ -18160,6 +18885,9 @@ var useOrderEntry2 = (symbol, options = {}) => {
18160
18885
  };
18161
18886
  }, []);
18162
18887
  React.useEffect(() => {
18888
+ if (formattedOrder.symbol !== symbol) {
18889
+ return;
18890
+ }
18163
18891
  if ((formattedOrder.order_type === types.OrderType.MARKET || formattedOrder.order_type === types.OrderType.STOP_MARKET) && markPrice) {
18164
18892
  const baseOn = /* @__PURE__ */ new Set();
18165
18893
  if (lastChangedField.current) {
@@ -18173,7 +18901,7 @@ var useOrderEntry2 = (symbol, options = {}) => {
18173
18901
  }
18174
18902
  orderEntryActions.onMarkPriceChange(markPrice, Array.from(baseOn));
18175
18903
  }
18176
- }, [markPrice, formattedOrder.order_type]);
18904
+ }, [markPrice, formattedOrder.order_type, formattedOrder.symbol, symbol]);
18177
18905
  const prepareData = React.useCallback(() => {
18178
18906
  return {
18179
18907
  markPrice: actions.getMarkPriceBySymbol(symbol),
@@ -18282,7 +19010,7 @@ var useOrderEntry2 = (symbol, options = {}) => {
18282
19010
  }
18283
19011
  );
18284
19012
  };
18285
- const { freeCollateral, totalCollateral } = useCollateral();
19013
+ const { freeCollateral, freeCollateralUSDCOnly, totalCollateral } = useCollateral();
18286
19014
  const currentPosition = React.useMemo(() => {
18287
19015
  const rows = positions3 ?? [];
18288
19016
  const p = Array.isArray(rows) ? rows.find(
@@ -18295,6 +19023,7 @@ var useOrderEntry2 = (symbol, options = {}) => {
18295
19023
  if (!markPrice2 || !accountInfo || !symbolInfo) {
18296
19024
  return null;
18297
19025
  }
19026
+ const sumUnitaryFunding = fundingRates[symbol]?.sum_unitary_funding ?? 0;
18298
19027
  const estLiqPrice2 = calcEstLiqPrice(formattedOrder, askAndBid.current[0], {
18299
19028
  markPrice: markPrice2,
18300
19029
  totalCollateral,
@@ -18302,7 +19031,8 @@ var useOrderEntry2 = (symbol, options = {}) => {
18302
19031
  imr_factor: accountInfo.imr_factor[symbol],
18303
19032
  symbol,
18304
19033
  positions: positions3,
18305
- symbolInfo
19034
+ symbolInfo,
19035
+ sumUnitaryFunding
18306
19036
  });
18307
19037
  return estLiqPrice2;
18308
19038
  }, [
@@ -18312,7 +19042,8 @@ var useOrderEntry2 = (symbol, options = {}) => {
18312
19042
  totalCollateral,
18313
19043
  symbol,
18314
19044
  maxQty,
18315
- symbolInfo
19045
+ symbolInfo,
19046
+ fundingRates
18316
19047
  ]);
18317
19048
  const estLiqPriceDistance = React.useMemo(() => {
18318
19049
  if (!estLiqPrice) {
@@ -18435,6 +19166,7 @@ var useOrderEntry2 = (symbol, options = {}) => {
18435
19166
  resetMetaState,
18436
19167
  formattedOrder,
18437
19168
  maxQty,
19169
+ maxQtys,
18438
19170
  estLiqPrice,
18439
19171
  estLiqPriceDistance,
18440
19172
  currentPosition,
@@ -18447,7 +19179,7 @@ var useOrderEntry2 = (symbol, options = {}) => {
18447
19179
  validator: validateOrder,
18448
19180
  validate: validateOrder
18449
19181
  },
18450
- freeCollateral,
19182
+ freeCollateral: effectiveMarginMode === types.MarginMode.ISOLATED ? freeCollateralUSDCOnly : freeCollateral,
18451
19183
  setValue: useMemoizedFn(setValue),
18452
19184
  setValues: useMemoizedFn(setValues),
18453
19185
  symbolInfo: symbolInfo || types.EMPTY_OBJECT,
@@ -18457,93 +19189,6 @@ var useOrderEntry2 = (symbol, options = {}) => {
18457
19189
  symbolLeverage
18458
19190
  };
18459
19191
  };
18460
- var initialOrderState2 = {
18461
- order_price: "",
18462
- order_quantity: "",
18463
- trigger_price: "",
18464
- tp_trigger_price: "",
18465
- sl_trigger_price: "",
18466
- total: "",
18467
- symbol: ""
18468
- };
18469
- var useOrderStore2 = zustand.create()(
18470
- immer.immer((set, get3) => ({
18471
- entry: {
18472
- side: types.OrderSide.BUY,
18473
- order_type: types.OrderType.LIMIT,
18474
- ...initialOrderState2
18475
- },
18476
- estLeverage: null,
18477
- estLiquidationPrice: null,
18478
- errors: {},
18479
- actions: {
18480
- hasTP_SL: () => {
18481
- const order = get3().entry;
18482
- return typeof order.tp_trigger_price !== "undefined" || typeof order.sl_trigger_price !== "undefined";
18483
- },
18484
- updateOrderComputed: (data) => {
18485
- set(
18486
- (state) => {
18487
- state.estLeverage = data.estLeverage;
18488
- state.estLiquidationPrice = data.estLiquidationPrice;
18489
- },
18490
- false
18491
- // "updateOrderComputed"
18492
- );
18493
- },
18494
- updateOrder: (order) => {
18495
- set(
18496
- (state) => {
18497
- state.entry = {
18498
- ...state.entry,
18499
- ...order
18500
- };
18501
- },
18502
- false
18503
- // "updateOrder"
18504
- );
18505
- },
18506
- updateOrderByKey: (key, value) => {
18507
- set(
18508
- (state) => {
18509
- state.entry[key] = value;
18510
- },
18511
- false
18512
- // "updateOrderByKey"
18513
- );
18514
- },
18515
- restoreOrder: (order) => {
18516
- set(
18517
- (state) => {
18518
- state.entry = order;
18519
- },
18520
- false
18521
- // "restoreOrder"
18522
- );
18523
- },
18524
- resetOrder: (order) => {
18525
- set(
18526
- (state) => {
18527
- state.entry.order_price = "";
18528
- state.entry.order_quantity = "";
18529
- state.entry.trigger_price = "";
18530
- state.entry.total = "";
18531
- state.entry.tp_trigger_price = "";
18532
- state.entry.tp_pnl = "";
18533
- state.entry.tp_offset = "";
18534
- state.entry.tp_offset_percentage = "";
18535
- state.entry.sl_trigger_price = "";
18536
- state.entry.sl_pnl = "";
18537
- state.entry.sl_offset = "";
18538
- state.entry.sl_offset_percentage = "";
18539
- },
18540
- true
18541
- // "resetOrder"
18542
- );
18543
- }
18544
- }
18545
- }))
18546
- );
18547
19192
  var useOrderEntity = (order, options) => {
18548
19193
  const { symbol } = order;
18549
19194
  const { maxQty } = options || {};
@@ -18701,13 +19346,15 @@ var usePositionClose = (options) => {
18701
19346
  symbol,
18702
19347
  order_type: type,
18703
19348
  side,
18704
- reduce_only: true
19349
+ reduce_only: true,
19350
+ // Use position's margin_mode or default to CROSS for backward compatibility
19351
+ margin_mode: position.margin_mode || types.MarginMode.CROSS
18705
19352
  };
18706
19353
  if (type === types.OrderType.LIMIT) {
18707
19354
  data.order_price = price;
18708
19355
  }
18709
19356
  return data;
18710
- }, [symbol, price, type, quantity]);
19357
+ }, [symbol, price, type, quantity, position.margin_mode]);
18711
19358
  const maxQty = React.useMemo(() => {
18712
19359
  if (!position) {
18713
19360
  return 0;
@@ -18909,9 +19556,11 @@ var useTpslPriceChecker = (params) => {
18909
19556
  prevResultRef.current = currentResult;
18910
19557
  return currentResult;
18911
19558
  };
18912
- var useEstLiqPriceBySymbol = (symbol) => {
19559
+ var useEstLiqPriceBySymbol = (symbol, marginMode) => {
18913
19560
  const [data] = usePositionStream(symbol);
18914
- const position = data?.rows?.find((row) => row.symbol === symbol);
19561
+ const position = data?.rows?.find(
19562
+ (row) => row.symbol === symbol && row.margin_mode === marginMode
19563
+ );
18915
19564
  return React.useMemo(() => {
18916
19565
  return position?.est_liq_price ?? void 0;
18917
19566
  }, [position]);
@@ -18932,6 +19581,62 @@ var useGetEstLiqPrice = (props) => {
18932
19581
  return estLiqPrice;
18933
19582
  }, [estLiqPrice, markPrice, side]);
18934
19583
  };
19584
+ var useFeatureFlag = (key) => {
19585
+ const { data: publicFlags, isLoading: publicLoading } = useQuery("/v1/public/feature_flags", {});
19586
+ const publicFlag = React.useMemo(() => {
19587
+ if (!publicFlags || publicLoading) {
19588
+ return void 0;
19589
+ }
19590
+ return publicFlags.find((flag) => flag.key === key);
19591
+ }, [publicFlags, publicLoading, key]);
19592
+ const shouldQueryPrivate = React.useMemo(() => {
19593
+ return publicFlag !== void 0;
19594
+ }, [publicFlag]);
19595
+ const { data: privateFlags, isLoading: privateLoading } = usePrivateQuery(shouldQueryPrivate ? "/v1/feature_flags" : null, {});
19596
+ const privateFlag = React.useMemo(() => {
19597
+ if (!shouldQueryPrivate || !privateFlags || privateLoading) {
19598
+ return void 0;
19599
+ }
19600
+ return privateFlags.find((flag) => flag.key === key);
19601
+ }, [shouldQueryPrivate, privateFlags, privateLoading, key]);
19602
+ return React.useMemo(() => {
19603
+ if (publicLoading || shouldQueryPrivate && privateLoading) {
19604
+ return {
19605
+ enabled: false,
19606
+ data: void 0
19607
+ };
19608
+ }
19609
+ if (publicFlag === void 0) {
19610
+ return {
19611
+ enabled: true,
19612
+ data: void 0
19613
+ };
19614
+ }
19615
+ if (privateFlag === void 0) {
19616
+ return {
19617
+ enabled: false,
19618
+ data: void 0
19619
+ };
19620
+ }
19621
+ return {
19622
+ enabled: true,
19623
+ data: privateFlag
19624
+ };
19625
+ }, [
19626
+ publicFlag,
19627
+ privateFlag,
19628
+ publicLoading,
19629
+ shouldQueryPrivate,
19630
+ privateLoading,
19631
+ key
19632
+ ]);
19633
+ };
19634
+
19635
+ // src/feature-flag/flagKeys.ts
19636
+ var FlagKeys = /* @__PURE__ */ ((FlagKeys2) => {
19637
+ FlagKeys2["IsolatedMargin"] = "isolated-margin";
19638
+ return FlagKeys2;
19639
+ })(FlagKeys || {});
18935
19640
 
18936
19641
  exports.swr = useSWR5__namespace;
18937
19642
  Object.defineProperty(exports, "unstable_serialize", {
@@ -18956,6 +19661,7 @@ exports.ENVType = ENVType2;
18956
19661
  exports.ERROR_MSG_CODES = ERROR_MSG_CODES;
18957
19662
  exports.EpochStatus = EpochStatus;
18958
19663
  exports.ExtendedConfigStore = ExtendedConfigStore;
19664
+ exports.FlagKeys = FlagKeys;
18959
19665
  exports.MaintenanceStatus = MaintenanceStatus;
18960
19666
  exports.MarketsStorageKey = MarketsStorageKey;
18961
19667
  exports.MarketsType = MarketsType;
@@ -19013,6 +19719,7 @@ exports.useDistributionHistory = useDistributionHistory;
19013
19719
  exports.useEpochInfo = useEpochInfo;
19014
19720
  exports.useEstLiqPriceBySymbol = useEstLiqPriceBySymbol;
19015
19721
  exports.useEventEmitter = useEventEmitter;
19722
+ exports.useFeatureFlag = useFeatureFlag;
19016
19723
  exports.useFeeState = useFeeState;
19017
19724
  exports.useFundingDetails = useFundingDetails;
19018
19725
  exports.useFundingFeeHistory = useFundingFeeHistory;
@@ -19043,6 +19750,8 @@ exports.useLocalStorage = useLocalStorage;
19043
19750
  exports.useMainTokenStore = useMainTokenStore;
19044
19751
  exports.useMainnetChainsStore = useMainnetChainsStore;
19045
19752
  exports.useMaintenanceStatus = useMaintenanceStatus;
19753
+ exports.useMarginModeBySymbol = useMarginModeBySymbol;
19754
+ exports.useMarginModes = useMarginModes;
19046
19755
  exports.useMarginRatio = useMarginRatio;
19047
19756
  exports.useMarkPrice = useMarkPrice;
19048
19757
  exports.useMarkPriceBySymbol = useMarkPriceBySymbol;
@@ -19065,7 +19774,7 @@ exports.useOdosQuote = useOdosQuote;
19065
19774
  exports.useOrderEntity = useOrderEntity;
19066
19775
  exports.useOrderEntry = useOrderEntry2;
19067
19776
  exports.useOrderEntry_deprecated = useOrderEntry;
19068
- exports.useOrderStore = useOrderStore2;
19777
+ exports.useOrderStore = useOrderStore;
19069
19778
  exports.useOrderStream = useOrderStream;
19070
19779
  exports.useOrderbookStream = useOrderbookStream;
19071
19780
  exports.useOrderlyContext = useOrderlyContext;
@@ -19073,6 +19782,7 @@ exports.usePortfolio = usePortfolio;
19073
19782
  exports.usePositionActions = usePositionActions;
19074
19783
  exports.usePositionClose = usePositionClose;
19075
19784
  exports.usePositionStream = usePositionStream;
19785
+ exports.usePositions = usePositions;
19076
19786
  exports.usePoster = usePoster;
19077
19787
  exports.usePreLoadData = usePreLoadData;
19078
19788
  exports.usePrivateDataObserver = usePrivateDataObserver;
@@ -19102,6 +19812,7 @@ exports.useSubAccountWS = useSubAccountWS;
19102
19812
  exports.useSwapSupportStore = useSwapSupportStore;
19103
19813
  exports.useSymbolInfo = useSymbolInfo;
19104
19814
  exports.useSymbolLeverage = useSymbolLeverage;
19815
+ exports.useSymbolLeverageMap = useSymbolLeverageMap;
19105
19816
  exports.useSymbolPriceRange = useSymbolPriceRange;
19106
19817
  exports.useSymbolsInfo = useSymbolsInfo;
19107
19818
  exports.useSymbolsInfoStore = useSymbolsInfoStore;