@orderly.network/hooks 2.10.2-alpha.0 → 2.11.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -64,9 +64,9 @@ var __export = (target, all) => {
64
64
  // src/version.ts
65
65
  if (typeof window !== "undefined") {
66
66
  window.__ORDERLY_VERSION__ = window.__ORDERLY_VERSION__ || {};
67
- window.__ORDERLY_VERSION__["@orderly.network/hooks"] = "2.10.2-alpha.0";
67
+ window.__ORDERLY_VERSION__["@orderly.network/hooks"] = "2.11.0-alpha.0";
68
68
  }
69
- var version_default = "2.10.2-alpha.0";
69
+ var version_default = "2.11.0-alpha.0";
70
70
  var fetcher = (url, init2 = {}, queryOptions) => net.get(url, init2, queryOptions?.formatter);
71
71
  var noCacheConfig = {
72
72
  dedupingInterval: 0,
@@ -1110,12 +1110,12 @@ var findTPSLOrderPriceFromOrder = (order) => {
1110
1110
  sl_order_price
1111
1111
  };
1112
1112
  };
1113
- var findPositionTPSLFromOrders = (orders, symbol) => {
1113
+ var findPositionTPSLFromOrders = (orders, symbol, marginMode = types.MarginMode.CROSS) => {
1114
1114
  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);
1115
+ 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
1116
  });
1117
1117
  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);
1118
+ 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
1119
  }).sort((a, b) => {
1120
1120
  return b.created_time - a.created_time;
1121
1121
  });
@@ -2140,9 +2140,11 @@ var useAppStore = zustand.create()(
2140
2140
  totalCollateral: utils.zero,
2141
2141
  totalValue: null,
2142
2142
  freeCollateral: utils.zero,
2143
+ freeCollateralUSDCOnly: utils.zero,
2143
2144
  availableBalance: 0,
2144
2145
  unsettledPnL: 0,
2145
- totalUnrealizedROI: 0
2146
+ totalUnrealizedROI: 0,
2147
+ usdcHolding: 0
2146
2148
  },
2147
2149
  appState: {
2148
2150
  positionsLoading: false,
@@ -2163,9 +2165,11 @@ var useAppStore = zustand.create()(
2163
2165
  totalCollateral: utils.zero,
2164
2166
  totalValue: null,
2165
2167
  freeCollateral: utils.zero,
2168
+ freeCollateralUSDCOnly: utils.zero,
2166
2169
  availableBalance: 0,
2167
2170
  unsettledPnL: 0,
2168
- totalUnrealizedROI: 0
2171
+ totalUnrealizedROI: 0,
2172
+ usdcHolding: 0
2169
2173
  };
2170
2174
  }, false);
2171
2175
  },
@@ -3961,25 +3965,27 @@ var OrderbookService = class _OrderbookService {
3961
3965
  };
3962
3966
  var orderBookService = OrderbookService.getInstance();
3963
3967
  var orderbook_service_default = orderBookService;
3968
+ var useMarkPriceStore = zustand.create((set, get3) => ({
3969
+ markPrices: {},
3970
+ // orderBook: {},
3971
+ // ask_bid: [],
3972
+ actions: {
3973
+ updateMarkPrice: (markPrice) => {
3974
+ set({
3975
+ markPrices: markPrice
3976
+ });
3977
+ },
3978
+ getMarkPriceBySymbol: (symbol) => {
3979
+ return get3().markPrices[symbol];
3980
+ }
3981
+ }
3982
+ }));
3983
+ var useMarkPriceBySymbol = (symbol) => useMarkPriceStore((state) => state.actions.getMarkPriceBySymbol(symbol));
3984
+ var useMarkPriceActions = () => useMarkPriceStore((state) => state.actions);
3985
+
3986
+ // src/orderly/useMarkPrice.ts
3964
3987
  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]);
3988
+ const price = useMarkPriceBySymbol(symbol);
3983
3989
  return { data: price };
3984
3990
  };
3985
3991
  var useIndexPrice = (symbol) => {
@@ -4002,6 +4008,12 @@ var useIndexPrice = (symbol) => {
4002
4008
  };
4003
4009
  });
4004
4010
  };
4011
+
4012
+ // src/orderly/useMarkPricesStream.ts
4013
+ var useMarkPricesStream = () => {
4014
+ const data = useMarkPriceStore((state) => state.markPrices);
4015
+ return { data };
4016
+ };
4005
4017
  var useOpenInterest = (symbol) => {
4006
4018
  const ws = useWS();
4007
4019
  const symbolRef = React.useRef(symbol);
@@ -4021,29 +4033,6 @@ var useOpenInterest = (symbol) => {
4021
4033
  };
4022
4034
  });
4023
4035
  };
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
4036
 
4048
4037
  // src/orderly/useTickerStream.ts
4049
4038
  var useTickerStream = (symbol) => {
@@ -4736,6 +4725,94 @@ var useLeverage = () => {
4736
4725
  maxLeverage: memoizedMaxLeverage
4737
4726
  };
4738
4727
  };
4728
+ var buildKey = (symbol, marginMode) => `${symbol}_${marginMode ?? types.MarginMode.CROSS}`;
4729
+ var useSymbolLeverageMap = () => {
4730
+ const { data, error, isLoading, mutate: mutate6 } = usePrivateQuery("/v1/client/leverages", {
4731
+ revalidateOnFocus: false,
4732
+ revalidateOnReconnect: false,
4733
+ errorRetryCount: 1
4734
+ });
4735
+ const leverages = React.useMemo(() => {
4736
+ if (!data || !Array.isArray(data)) return {};
4737
+ const map = {};
4738
+ for (const item of data) {
4739
+ const key = buildKey(item.symbol, item.margin_mode);
4740
+ map[key] = item.leverage;
4741
+ }
4742
+ return map;
4743
+ }, [data]);
4744
+ const getSymbolLeverage = (symbol, marginMode) => {
4745
+ if (!symbol) return void 0;
4746
+ const key = buildKey(symbol, marginMode);
4747
+ return leverages[key];
4748
+ };
4749
+ return {
4750
+ leverages,
4751
+ getSymbolLeverage,
4752
+ isLoading,
4753
+ error,
4754
+ refresh: mutate6
4755
+ };
4756
+ };
4757
+ var useMarginModes = () => {
4758
+ const { data, error, isLoading, mutate: mutate6 } = usePrivateQuery("/v1/client/margin_modes", {
4759
+ revalidateOnFocus: false,
4760
+ revalidateOnMount: true
4761
+ });
4762
+ const [setMarginModeInternal, { isMutating }] = useMutation(
4763
+ "/v1/client/margin_mode",
4764
+ "POST"
4765
+ );
4766
+ const marginModes = React.useMemo(() => {
4767
+ if (!data || !Array.isArray(data)) return {};
4768
+ const map = {};
4769
+ for (const item of data) {
4770
+ map[item.symbol] = item.default_margin_mode;
4771
+ }
4772
+ return map;
4773
+ }, [data]);
4774
+ const setMarginMode = (payload) => setMarginModeInternal(payload);
4775
+ const updateMarginMode = React.useCallback(
4776
+ async (payload) => {
4777
+ const result = await setMarginMode(payload);
4778
+ if (result.success) {
4779
+ await mutate6();
4780
+ return result;
4781
+ }
4782
+ throw new Error(result.message ?? "Failed to update margin mode");
4783
+ },
4784
+ [setMarginMode, mutate6]
4785
+ );
4786
+ return {
4787
+ marginModes,
4788
+ isLoading,
4789
+ error,
4790
+ refresh: mutate6,
4791
+ setMarginMode,
4792
+ updateMarginMode,
4793
+ isMutating
4794
+ };
4795
+ };
4796
+ var useMarginModeBySymbol = (symbol, fallback = types.MarginMode.CROSS) => {
4797
+ const { marginModes, isLoading, error, refresh, updateMarginMode } = useMarginModes();
4798
+ const marginMode = fallback === null ? marginModes[symbol] : marginModes[symbol] ?? fallback;
4799
+ const update = React.useCallback(
4800
+ async (mode) => {
4801
+ return updateMarginMode({
4802
+ symbol_list: [symbol],
4803
+ default_margin_mode: mode
4804
+ });
4805
+ },
4806
+ [symbol, updateMarginMode]
4807
+ );
4808
+ return {
4809
+ marginMode,
4810
+ isLoading,
4811
+ error,
4812
+ refresh,
4813
+ update
4814
+ };
4815
+ };
4739
4816
 
4740
4817
  // src/orderly/useOdosQuote.ts
4741
4818
  var useOdosQuote = () => {
@@ -5093,10 +5170,13 @@ var CalculatorService = class {
5093
5170
  // this.pendingCalc = [];
5094
5171
  // }
5095
5172
  async handleCalcQueue(context) {
5096
- const first = this.calcQueue.shift();
5097
- if (first) {
5173
+ const batchCollector = /* @__PURE__ */ new Map();
5174
+ let currentContext = context;
5175
+ while (this.calcQueue.length > 0) {
5176
+ const first = this.calcQueue.shift();
5177
+ if (!first) break;
5098
5178
  const { scope, data, options } = first;
5099
- const ctx = context || CalculatorContext.create(scope, data);
5179
+ const ctx = currentContext || CalculatorContext.create(scope, data);
5100
5180
  const calculators = this.calculators.get(scope);
5101
5181
  if (Array.isArray(calculators) && calculators.length) {
5102
5182
  try {
@@ -5104,13 +5184,46 @@ var CalculatorService = class {
5104
5184
  } catch (e) {
5105
5185
  }
5106
5186
  if (!options?.skipUpdate) {
5107
- this.scheduler.update(scope, calculators, ctx.outputToValue());
5187
+ this.collectUpdates(
5188
+ batchCollector,
5189
+ scope,
5190
+ calculators,
5191
+ ctx.outputToValue()
5192
+ );
5108
5193
  }
5109
5194
  }
5110
- if (this.calcQueue.length) {
5111
- this.handleCalcQueue(ctx);
5195
+ currentContext = ctx;
5196
+ }
5197
+ await this.commitBatchUpdates(batchCollector);
5198
+ this.ctx = currentContext;
5199
+ }
5200
+ collectUpdates(collector, scope, calculators, data) {
5201
+ if (!collector.has(scope)) {
5202
+ collector.set(scope, /* @__PURE__ */ new Map());
5203
+ }
5204
+ const scopeCollector = collector.get(scope);
5205
+ for (const calculator of calculators) {
5206
+ const item = data[calculator.name];
5207
+ if (item !== void 0 && item !== null) {
5208
+ scopeCollector.set(calculator.name, item);
5209
+ }
5210
+ }
5211
+ }
5212
+ async commitBatchUpdates(collector) {
5213
+ if (collector.size === 0) return;
5214
+ for (const [scope, updateMap] of collector.entries()) {
5215
+ const calculators = this.calculators.get(scope);
5216
+ if (!Array.isArray(calculators)) continue;
5217
+ const batchData = {};
5218
+ for (const [calculatorName, data] of updateMap.entries()) {
5219
+ batchData[calculatorName] = data;
5220
+ }
5221
+ try {
5222
+ this.scheduler.update(scope, calculators, batchData);
5223
+ } catch (e) {
5112
5224
  }
5113
5225
  }
5226
+ collector.clear();
5114
5227
  }
5115
5228
  stop() {
5116
5229
  this.calcQueue = [];
@@ -5141,6 +5254,18 @@ var cancelIdleCallbackPolyfill = (id) => {
5141
5254
  var safeRequestIdleCallback = typeof window !== "undefined" && window.requestIdleCallback ? window.requestIdleCallback.bind(window) : requestIdleCallbackPolyfill;
5142
5255
  typeof window !== "undefined" && window.cancelIdleCallback ? window.cancelIdleCallback.bind(window) : cancelIdleCallbackPolyfill;
5143
5256
  var ShardingScheduler = class {
5257
+ constructor() {
5258
+ /**
5259
+ * Maximum continuous execution time per frame (in milliseconds)
5260
+ * Prevents blocking the main thread for too long
5261
+ */
5262
+ this.MAX_CONTINUOUS_MS = 5;
5263
+ /**
5264
+ * Minimum remaining idle time threshold (in milliseconds)
5265
+ * Ensures the browser has enough idle time for other tasks
5266
+ */
5267
+ this.MIN_IDLE_REMAINING = 2;
5268
+ }
5144
5269
  // run(calculators: Calculator[]) {}
5145
5270
  calc(scope, calculators, data, ctx) {
5146
5271
  return new Promise((resolve, reject) => {
@@ -5181,28 +5306,27 @@ var ShardingScheduler = class {
5181
5306
  computation(data, processor, onComplete) {
5182
5307
  let index = 0;
5183
5308
  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);
5309
+ const MAX_CONTINUOUS_MS = this.MAX_CONTINUOUS_MS;
5310
+ const MIN_IDLE_REMAINING = this.MIN_IDLE_REMAINING;
5311
+ const processNextShard = (deadline) => {
5312
+ const frameStart = performance.now();
5313
+ while (index < data.length) {
5314
+ const elapsed = performance.now() - frameStart;
5315
+ const remaining = deadline.timeRemaining();
5316
+ if (elapsed > MAX_CONTINUOUS_MS || remaining < MIN_IDLE_REMAINING) {
5317
+ safeRequestIdleCallback(processNextShard, {
5318
+ timeout: 1e3
5319
+ });
5320
+ return;
5196
5321
  }
5322
+ const result = processor([data[index]]);
5323
+ if (result && result.length > 0) {
5324
+ results.push(...result);
5325
+ }
5326
+ index++;
5197
5327
  }
5198
- if (index < data.length) {
5199
- safeRequestIdleCallback(processNextShard, {
5200
- timeout: 1e3
5201
- });
5202
- } else {
5203
- onComplete(results.flat());
5204
- }
5205
- }
5328
+ onComplete(results);
5329
+ };
5206
5330
  safeRequestIdleCallback(processNextShard, {
5207
5331
  timeout: 1e3
5208
5332
  });
@@ -5415,21 +5539,38 @@ var PositionCalculator = class extends BaseCalculator {
5415
5539
  const unsettlementPnL = unsettlementPnL_total.toNumber();
5416
5540
  let totalUnrealizedROI = 0, totalUnrealizedROI_index = 0;
5417
5541
  if (portfolio) {
5418
- const { totalValue, totalCollateral } = portfolio;
5542
+ const { totalValue, totalCollateral: crossMarginCollateral } = portfolio;
5419
5543
  rows = rows.map((item) => {
5420
5544
  const info = symbolsInfo[item.symbol];
5421
- const est_liq_price = perp.positions.liqPrice({
5422
- symbol: item.symbol,
5423
- markPrice: item.mark_price,
5424
- totalCollateral: totalCollateral.toNumber(),
5425
- positionQty: item.position_qty,
5426
- positions: rows,
5427
- MMR: item.mmr,
5428
- baseMMR: info?.["base_mmr"],
5429
- baseIMR: info?.["base_imr"],
5430
- IMRFactor: accountInfo.imr_factor[item.symbol],
5431
- costPosition: item.cost_position
5432
- });
5545
+ const totalCollateral = item.margin_mode === types.MarginMode.ISOLATED ? new utils.Decimal(item.margin ?? 0).add(item.unsettlement_pnl ?? 0).toNumber() : crossMarginCollateral.toNumber();
5546
+ let est_liq_price;
5547
+ if (item.margin_mode === types.MarginMode.ISOLATED) {
5548
+ est_liq_price = perp.positions.liquidationPriceIsolated({
5549
+ isolatedPositionMargin: item.margin ?? 0,
5550
+ costPosition: item.cost_position ?? 0,
5551
+ positionQty: item.position_qty ?? 0,
5552
+ sumUnitaryFunding: fundingRates?.[item.symbol]?.["sum_unitary_funding"] ?? 0,
5553
+ lastSumUnitaryFunding: item.last_sum_unitary_funding ?? 0,
5554
+ baseMMR: info?.["base_mmr"] ?? 0,
5555
+ baseIMR: info?.["base_imr"] ?? 0,
5556
+ IMRFactor: accountInfo.imr_factor[item.symbol],
5557
+ referencePrice: item.mark_price,
5558
+ leverage: item.leverage ?? 0
5559
+ });
5560
+ } else {
5561
+ est_liq_price = perp.positions.liqPrice({
5562
+ symbol: item.symbol,
5563
+ markPrice: item.mark_price,
5564
+ totalCollateral,
5565
+ positionQty: item.position_qty,
5566
+ positions: rows,
5567
+ MMR: item.mmr,
5568
+ baseMMR: info?.["base_mmr"],
5569
+ baseIMR: info?.["base_imr"],
5570
+ IMRFactor: accountInfo.imr_factor[item.symbol],
5571
+ costPosition: item.cost_position
5572
+ });
5573
+ }
5433
5574
  return {
5434
5575
  ...item,
5435
5576
  est_liq_price
@@ -5580,7 +5721,9 @@ var PortfolioCalculator = class extends BaseCalculator {
5580
5721
  return {
5581
5722
  ...item,
5582
5723
  holding: data.holding[item.token].holding,
5583
- frozen: data.holding[item.token].frozen
5724
+ frozen: data.holding[item.token].frozen,
5725
+ isolatedMargin: data.holding[item.token].isolatedMargin,
5726
+ isolatedOrderFrozen: data.holding[item.token].isolatedOrderFrozen
5584
5727
  };
5585
5728
  }
5586
5729
  return item;
@@ -5616,7 +5759,14 @@ var PortfolioCalculator = class extends BaseCalculator {
5616
5759
  if (!holding || !positions3 || !Array.isArray(positions3.rows) || !markPrices || !indexPrices || !accountInfo) {
5617
5760
  return null;
5618
5761
  }
5619
- const unsettledPnL = ramda.pathOr(0, ["total_unsettled_pnl"])(positions3);
5762
+ const totallCrossUnsettledPnL = positions3.rows.reduce(
5763
+ (sum, pos) => pos.margin_mode === types.MarginMode.ISOLATED ? sum : sum + (pos.unsettled_pnl ?? 0),
5764
+ 0
5765
+ );
5766
+ const totalUnsettlementPnL = positions3.rows.reduce(
5767
+ (sum, pos) => sum + (pos.unsettled_pnl ?? 0),
5768
+ 0
5769
+ );
5620
5770
  const unrealizedPnL = ramda.pathOr(0, ["total_unreal_pnl"])(positions3);
5621
5771
  const [USDC_holding, nonUSDC] = parseHolding(
5622
5772
  holding,
@@ -5627,28 +5777,51 @@ var PortfolioCalculator = class extends BaseCalculator {
5627
5777
  const totalCollateral = perp.account.totalCollateral({
5628
5778
  USDCHolding: USDC_holding,
5629
5779
  nonUSDCHolding: nonUSDC,
5630
- unsettlementPnL: unsettledPnL
5780
+ unsettlementPnL: totallCrossUnsettledPnL,
5781
+ usdcBalancePendingShortQty: usdc?.pending_short ?? 0,
5782
+ usdcBalanceIsolatedOrderFrozen: usdc?.isolated_order_frozen ?? 0
5631
5783
  });
5784
+ const sumIsolatedMargin = positions3.rows.reduce((acc, curr) => {
5785
+ if (curr.margin_mode !== types.MarginMode.ISOLATED) {
5786
+ return acc;
5787
+ }
5788
+ return acc.add(curr.margin ?? 0);
5789
+ }, utils.zero);
5632
5790
  const totalValue = perp.account.totalValue({
5633
- totalUnsettlementPnL: unsettledPnL,
5791
+ totalUnsettlementPnL,
5634
5792
  USDCHolding: USDC_holding,
5635
- nonUSDCHolding: nonUSDC
5793
+ nonUSDCHolding: nonUSDC,
5794
+ totalIsolatedPositionMargin: sumIsolatedMargin.toNumber()
5636
5795
  });
5637
5796
  const totalUnrealizedROI = perp.account.totalUnrealizedROI({
5638
5797
  totalUnrealizedPnL: unrealizedPnL,
5639
5798
  totalValue: totalValue.toNumber()
5640
5799
  });
5800
+ const maxLeverageBySymbol = positions3.rows.reduce(
5801
+ (acc, position) => {
5802
+ if (position.margin_mode !== types.MarginMode.ISOLATED && position.leverage && !acc[position.symbol]) {
5803
+ acc[position.symbol] = position.leverage;
5804
+ }
5805
+ return acc;
5806
+ },
5807
+ {}
5808
+ );
5641
5809
  const totalInitialMarginWithOrders = perp.account.totalInitialMarginWithQty({
5642
5810
  positions: positions3.rows,
5811
+ orders: [],
5643
5812
  markPrices,
5644
5813
  IMR_Factors: accountInfo.imr_factor,
5645
- maxLeverage: accountInfo.max_leverage,
5814
+ maxLeverageBySymbol,
5646
5815
  symbolInfo: createGetter({ ...symbolsInfo })
5647
5816
  });
5648
5817
  const freeCollateral = perp.account.freeCollateral({
5649
5818
  totalCollateral,
5650
5819
  totalInitialMarginWithOrders
5651
5820
  });
5821
+ const freeCollateralUSDCOnly = perp.account.freeCollateralUSDCOnly({
5822
+ freeCollateral,
5823
+ nonUSDCHolding: nonUSDC
5824
+ });
5652
5825
  const availableBalance = perp.account.availableBalance({
5653
5826
  USDCHolding: usdc?.holding ?? 0,
5654
5827
  unsettlementPnL: positions3.total_unsettled_pnl ?? 0
@@ -5659,8 +5832,10 @@ var PortfolioCalculator = class extends BaseCalculator {
5659
5832
  totalUnrealizedROI,
5660
5833
  freeCollateral,
5661
5834
  availableBalance,
5662
- unsettledPnL,
5663
- holding
5835
+ unsettledPnL: totalUnsettlementPnL,
5836
+ holding,
5837
+ usdcHolding: USDC_holding,
5838
+ freeCollateralUSDCOnly
5664
5839
  };
5665
5840
  }
5666
5841
  update(data, scope) {
@@ -5669,10 +5844,12 @@ var PortfolioCalculator = class extends BaseCalculator {
5669
5844
  totalCollateral: data.totalCollateral,
5670
5845
  totalValue: data.totalValue,
5671
5846
  freeCollateral: data.freeCollateral,
5847
+ freeCollateralUSDCOnly: data.freeCollateralUSDCOnly,
5672
5848
  availableBalance: data.availableBalance,
5673
5849
  totalUnrealizedROI: data.totalUnrealizedROI,
5674
5850
  unsettledPnL: data.unsettledPnL,
5675
- holding: Array.isArray(data.holding) ? data.holding : []
5851
+ holding: Array.isArray(data.holding) ? data.holding : [],
5852
+ usdcHolding: typeof data.usdcHolding === "number" ? data.usdcHolding : data.usdcHolding.toNumber()
5676
5853
  });
5677
5854
  }
5678
5855
  }
@@ -5803,7 +5980,7 @@ var usePositionStream = (symbol = "all", options) => {
5803
5980
  }
5804
5981
  if (Array.isArray(tpslOrders) && tpslOrders.length) {
5805
5982
  rows = rows.map((item) => {
5806
- const { fullPositionOrder, partialPositionOrders } = findPositionTPSLFromOrders(tpslOrders, item.symbol);
5983
+ const { fullPositionOrder, partialPositionOrders } = findPositionTPSLFromOrders(tpslOrders, item.symbol, item.margin_mode);
5807
5984
  const full_tp_sl = fullPositionOrder ? findTPSLFromOrder(fullPositionOrder) : void 0;
5808
5985
  const partialPossitionOrder = partialPositionOrders && partialPositionOrders.length ? partialPositionOrders[0] : void 0;
5809
5986
  const partial_tp_sl = partialPossitionOrder ? findTPSLFromOrder(partialPossitionOrder) : void 0;
@@ -5935,15 +6112,21 @@ var useOrderStream = (params, options) => {
5935
6112
  }
5936
6113
  };
5937
6114
  }, [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
- });
6115
+ const normalOrdersResponse = usePrivateInfiniteQuery(
6116
+ normalOrderKeyFn,
6117
+ {
6118
+ initialSize: 1,
6119
+ formatter: (data) => data,
6120
+ revalidateOnFocus: false
6121
+ }
6122
+ );
6123
+ const algoOrdersResponse = usePrivateInfiniteQuery(
6124
+ algoOrderKeyFn,
6125
+ {
6126
+ formatter: (data) => data,
6127
+ revalidateOnFocus: false
6128
+ }
6129
+ );
5947
6130
  const flattenOrders = React.useMemo(() => {
5948
6131
  if (!normalOrdersResponse.data || !algoOrdersResponse.data && !sourceTypeAll) {
5949
6132
  return null;
@@ -6061,7 +6244,9 @@ var useOrderStream = (params, options) => {
6061
6244
  // trailing stop order fields
6062
6245
  activated_price: order.activated_price,
6063
6246
  callback_value: order.callback_value,
6064
- callback_rate: order.callback_rate
6247
+ callback_rate: order.callback_rate,
6248
+ // Include margin_mode if present
6249
+ ...order.margin_mode && { margin_mode: order.margin_mode }
6065
6250
  });
6066
6251
  default:
6067
6252
  return doUpdateOrder({ ...order, order_id: orderId });
@@ -6256,7 +6441,14 @@ function formatPortfolio(inputs) {
6256
6441
  if (!holding || !positions3 || !Array.isArray(positions3.rows) || !markPrices || !indexPrices || !accountInfo || symbolsInfo?.isNil) {
6257
6442
  return null;
6258
6443
  }
6259
- const unsettledPnL = ramda.pathOr(0, ["total_unsettled_pnl"])(positions3);
6444
+ const totallCrossUnsettledPnL = positions3.rows.reduce(
6445
+ (sum, pos) => pos.margin_mode === types.MarginMode.ISOLATED ? sum : sum + (pos.unsettled_pnl ?? 0),
6446
+ 0
6447
+ );
6448
+ const totalUnsettlementPnL = positions3.rows.reduce(
6449
+ (sum, pos) => sum + (pos.unsettled_pnl ?? 0),
6450
+ 0
6451
+ );
6260
6452
  const unrealizedPnL = ramda.pathOr(0, ["total_unreal_pnl"])(positions3);
6261
6453
  const [USDC_holding, nonUSDC] = parseHolding(
6262
6454
  holding,
@@ -6267,29 +6459,51 @@ function formatPortfolio(inputs) {
6267
6459
  const totalCollateral = perp.account.totalCollateral({
6268
6460
  USDCHolding: USDC_holding,
6269
6461
  nonUSDCHolding: nonUSDC,
6270
- unsettlementPnL: unsettledPnL
6462
+ unsettlementPnL: totallCrossUnsettledPnL,
6463
+ usdcBalancePendingShortQty: usdc?.pending_short ?? 0,
6464
+ usdcBalanceIsolatedOrderFrozen: usdc?.isolated_order_frozen ?? 0
6271
6465
  });
6466
+ const sumIsolatedMargin = positions3.rows.reduce((acc, curr) => {
6467
+ if (curr.margin_mode !== types.MarginMode.ISOLATED) {
6468
+ return acc;
6469
+ }
6470
+ return acc.add(curr.margin ?? 0);
6471
+ }, utils.zero);
6272
6472
  const totalValue = perp.account.totalValue({
6273
- totalUnsettlementPnL: unsettledPnL,
6473
+ totalUnsettlementPnL,
6274
6474
  USDCHolding: USDC_holding,
6275
- nonUSDCHolding: nonUSDC
6475
+ nonUSDCHolding: nonUSDC,
6476
+ totalIsolatedPositionMargin: sumIsolatedMargin.toNumber()
6276
6477
  });
6277
6478
  const totalUnrealizedROI = perp.account.totalUnrealizedROI({
6278
6479
  totalUnrealizedPnL: unrealizedPnL,
6279
6480
  totalValue: totalValue.toNumber()
6280
6481
  });
6482
+ const maxLeverageBySymbol = positions3.rows.reduce(
6483
+ (acc, position) => {
6484
+ if (position.margin_mode !== types.MarginMode.ISOLATED && position.leverage && !acc[position.symbol]) {
6485
+ acc[position.symbol] = position.leverage;
6486
+ }
6487
+ return acc;
6488
+ },
6489
+ {}
6490
+ );
6281
6491
  const totalInitialMarginWithOrders = perp.account.totalInitialMarginWithQty({
6282
6492
  positions: positions3.rows,
6493
+ orders: [],
6283
6494
  markPrices,
6284
6495
  IMR_Factors: accountInfo.imr_factor,
6285
- // Not used
6286
- maxLeverage: accountInfo.max_leverage,
6287
- symbolInfo: symbolsInfo
6496
+ maxLeverageBySymbol,
6497
+ symbolInfo: createGetter({ ...symbolsInfo })
6288
6498
  });
6289
6499
  const freeCollateral = perp.account.freeCollateral({
6290
6500
  totalCollateral,
6291
6501
  totalInitialMarginWithOrders
6292
6502
  });
6503
+ const freeCollateralUSDCOnly = perp.account.freeCollateralUSDCOnly({
6504
+ freeCollateral,
6505
+ nonUSDCHolding: nonUSDC
6506
+ });
6293
6507
  const availableBalance = perp.account.availableBalance({
6294
6508
  USDCHolding: usdc?.holding ?? 0,
6295
6509
  unsettlementPnL: positions3.total_unsettled_pnl ?? 0
@@ -6300,8 +6514,9 @@ function formatPortfolio(inputs) {
6300
6514
  totalUnrealizedROI,
6301
6515
  freeCollateral,
6302
6516
  availableBalance,
6303
- unsettledPnL,
6304
- holding
6517
+ unsettledPnL: totalUnsettlementPnL,
6518
+ holding,
6519
+ freeCollateralUSDCOnly
6305
6520
  };
6306
6521
  }
6307
6522
  function formatPositions(data, accountInfo, symbolsInfo, fundingRates) {
@@ -6821,7 +7036,9 @@ var useSubAccountAlgoOrderStream = (params, options) => {
6821
7036
  // trailing stop order fields
6822
7037
  activated_price: order.activated_price,
6823
7038
  callback_value: order.callback_value,
6824
- callback_rate: order.callback_rate
7039
+ callback_rate: order.callback_rate,
7040
+ // include margin_mode if present (align with useOrderStream)
7041
+ ...order.margin_mode && { margin_mode: order.margin_mode }
6825
7042
  });
6826
7043
  default:
6827
7044
  return doUpdateOrder({ ...order, order_id: orderId });
@@ -7008,120 +7225,122 @@ var useCollateral = (options = { dp: 6 }) => {
7008
7225
  totalCollateral,
7009
7226
  totalValue,
7010
7227
  freeCollateral,
7228
+ freeCollateralUSDCOnly,
7011
7229
  availableBalance,
7012
7230
  unsettledPnL,
7013
- holding
7231
+ holding,
7232
+ usdcHolding
7014
7233
  } = useAppStore((state) => state.portfolio);
7015
7234
  const accountInfo = useAppStore((state) => state.accountInfo);
7016
7235
  return {
7017
7236
  totalCollateral: totalCollateral.toDecimalPlaces(dp).toNumber(),
7018
7237
  freeCollateral: freeCollateral.toDecimalPlaces(dp).toNumber(),
7238
+ freeCollateralUSDCOnly: freeCollateralUSDCOnly.toDecimalPlaces(dp).toNumber(),
7019
7239
  totalValue: totalValue?.toDecimalPlaces(dp).toNumber() ?? null,
7020
7240
  availableBalance,
7021
7241
  unsettledPnL,
7022
7242
  accountInfo,
7023
- holding
7243
+ holding,
7244
+ usdcHolding
7024
7245
  // @hidden
7025
7246
  // positions: positionsPath(positions),
7026
7247
  };
7027
7248
  };
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;
7249
+
7250
+ // src/orderly/useLeverageBySymbol.ts
7251
+ var useLeverageBySymbol = (symbol, marginMode) => {
7252
+ const { getSymbolLeverage } = useSymbolLeverageMap();
7253
+ return getSymbolLeverage(symbol, marginMode);
7062
7254
  };
7063
7255
 
7064
7256
  // src/orderly/useMaxQty.ts
7065
- var useMaxQty = (symbol, side, reduceOnly = false) => {
7257
+ function useMaxQty(symbol, side, reduceOnlyOrOptions, marginMode) {
7258
+ const reduceOnly = typeof reduceOnlyOrOptions === "object" && reduceOnlyOrOptions !== null ? reduceOnlyOrOptions.reduceOnly ?? false : reduceOnlyOrOptions ?? false;
7259
+ const finalMarginMode = typeof reduceOnlyOrOptions === "object" && reduceOnlyOrOptions !== null ? reduceOnlyOrOptions.marginMode ?? types.MarginMode.CROSS : marginMode ?? types.MarginMode.CROSS;
7066
7260
  const positions3 = usePositions();
7067
7261
  const accountInfo = useAccountInfo();
7068
7262
  const symbolInfo = useSymbolsInfo();
7069
- const { totalCollateral } = useCollateral();
7263
+ const { totalCollateral, freeCollateralUSDCOnly } = useCollateral();
7070
7264
  const { data: markPrices } = useMarkPricesStream();
7071
- const symbolLeverage = useLeverageBySymbol(symbol);
7265
+ const symbolLeverage = useLeverageBySymbol(symbol, finalMarginMode);
7072
7266
  const maxQty = React.useMemo(() => {
7073
7267
  if (!symbol) return 0;
7074
- const positionQty = perp.account.getQtyFromPositions(
7075
- positions3 === null ? [] : positions3,
7076
- symbol
7268
+ if (!markPrices || !markPrices[symbol] || !accountInfo || !positions3) {
7269
+ return 0;
7270
+ }
7271
+ const positionsArray = (positions3 === null ? [] : positions3).filter(
7272
+ (position) => position.margin_mode === finalMarginMode
7077
7273
  );
7274
+ const positionQty = perp.account.getQtyFromPositions(positionsArray, symbol);
7078
7275
  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;
7276
+ if (positionQty === 0) return 0;
7277
+ return side === types.OrderSide.BUY ? positionQty < 0 ? Math.abs(positionQty) : 0 : positionQty > 0 ? positionQty : 0;
7094
7278
  }
7095
- if (!markPrices || !markPrices[symbol] || !accountInfo || !positions3)
7096
- return 0;
7097
7279
  const getSymbolInfo = symbolInfo[symbol];
7098
- const currentSymbolPosition = positions3.find(
7099
- (item) => item.symbol === symbol
7100
- );
7280
+ let currentSymbolPosition;
7281
+ const otherPositions = [];
7282
+ for (const position of positionsArray) {
7283
+ if (position.symbol === symbol) {
7284
+ currentSymbolPosition = position;
7285
+ } else {
7286
+ otherPositions.push(position);
7287
+ }
7288
+ }
7289
+ const markPrice = markPrices[symbol];
7290
+ const baseIMR = getSymbolInfo("base_imr") ?? 0;
7291
+ const IMR_Factor = accountInfo.imr_factor[symbol] ?? 0;
7292
+ const leverage = symbolLeverage || currentSymbolPosition?.leverage || 1;
7101
7293
  const buyOrdersQty = currentSymbolPosition?.pending_long_qty ?? 0;
7102
7294
  const sellOrdersQty = currentSymbolPosition?.pending_short_qty ?? 0;
7103
- const otherPositions = !Array.isArray(positions3) ? [] : positions3.filter((item) => item.symbol !== symbol);
7295
+ if (finalMarginMode === types.MarginMode.ISOLATED) {
7296
+ const availableBalance = freeCollateralUSDCOnly;
7297
+ const pendingLongOrders = buyOrdersQty > 0 ? [{ referencePrice: markPrice, quantity: buyOrdersQty }] : [];
7298
+ const pendingSellOrders = sellOrdersQty > 0 ? [{ referencePrice: markPrice, quantity: sellOrdersQty }] : [];
7299
+ const markPriceDecimal = new utils.Decimal(markPrice);
7300
+ const leverageDecimal = new utils.Decimal(leverage);
7301
+ const isoOrderFrozenLong = buyOrdersQty > 0 ? markPriceDecimal.mul(buyOrdersQty).div(leverageDecimal).toNumber() : 0;
7302
+ const isoOrderFrozenShort = sellOrdersQty > 0 ? markPriceDecimal.mul(sellOrdersQty).div(leverageDecimal).toNumber() : 0;
7303
+ const symbolMaxNotional = accountInfo.max_notional?.[symbol] ?? perp.positions.maxPositionNotional({
7304
+ leverage,
7305
+ IMRFactor: IMR_Factor
7306
+ });
7307
+ const currentOrderReferencePrice = typeof reduceOnlyOrOptions === "object" && reduceOnlyOrOptions !== null && typeof reduceOnlyOrOptions.currentOrderReferencePrice === "number" && reduceOnlyOrOptions.currentOrderReferencePrice > 0 ? reduceOnlyOrOptions.currentOrderReferencePrice : markPrice;
7308
+ return perp.account.maxQtyForIsolatedMargin({
7309
+ symbol,
7310
+ orderSide: side,
7311
+ currentOrderReferencePrice,
7312
+ availableBalance,
7313
+ leverage,
7314
+ baseIMR,
7315
+ IMR_Factor,
7316
+ markPrice,
7317
+ positionQty,
7318
+ pendingLongOrders,
7319
+ pendingSellOrders,
7320
+ isoOrderFrozenLong,
7321
+ isoOrderFrozenShort,
7322
+ symbolMaxNotional
7323
+ });
7324
+ }
7104
7325
  const otherIMs = perp.account.otherIMs({
7105
7326
  positions: otherPositions,
7106
7327
  symbolInfo,
7107
7328
  markPrices,
7108
- IMR_Factors: accountInfo.imr_factor,
7109
- // Not used
7110
- maxLeverage: accountInfo.max_leverage
7329
+ IMR_Factors: accountInfo.imr_factor
7111
7330
  });
7112
7331
  return perp.account.maxQty(side, {
7113
- markPrice: markPrices[symbol],
7332
+ markPrice,
7114
7333
  symbol,
7115
7334
  baseMaxQty: getSymbolInfo("base_max"),
7116
7335
  totalCollateral,
7117
- maxLeverage: symbolLeverage || currentSymbolPosition?.leverage || 1,
7336
+ maxLeverage: leverage,
7118
7337
  takerFeeRate: accountInfo.futures_taker_fee_rate,
7119
- baseIMR: getSymbolInfo("base_imr"),
7338
+ baseIMR,
7120
7339
  otherIMs,
7121
7340
  positionQty,
7122
7341
  buyOrdersQty,
7123
7342
  sellOrdersQty,
7124
- IMR_Factor: accountInfo.imr_factor[symbol]
7343
+ IMR_Factor
7125
7344
  });
7126
7345
  }, [
7127
7346
  symbol,
@@ -7131,10 +7350,12 @@ var useMaxQty = (symbol, side, reduceOnly = false) => {
7131
7350
  accountInfo,
7132
7351
  symbolInfo,
7133
7352
  side,
7134
- totalCollateral
7353
+ totalCollateral,
7354
+ finalMarginMode,
7355
+ symbolLeverage
7135
7356
  ]);
7136
7357
  return Math.max(maxQty, 0);
7137
- };
7358
+ }
7138
7359
  var useMarginRatio = () => {
7139
7360
  const positions3 = usePositionStore((state2) => state2.positions.all);
7140
7361
  const { rows, notional } = positions3;
@@ -8440,29 +8661,67 @@ var usePrivateDataObserver = (options) => {
8440
8661
  }, [state.accountId, subOrder]);
8441
8662
  React.useEffect(() => {
8442
8663
  if (!state.accountId) return;
8443
- const key = ["/v1/positions", state.accountId];
8664
+ const positionsKey = ["/v1/positions", state.accountId];
8665
+ const leveragesKey = ["/v1/client/leverages", state.accountId];
8444
8666
  const unsubscribe = ws.privateSubscribe("account", {
8445
8667
  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
- );
8668
+ const { symbol, leverage, marginMode } = data?.accountDetail?.symbolLeverage || {};
8669
+ if (!symbol || leverage === void 0) {
8670
+ return;
8465
8671
  }
8672
+ useSWR5.mutate(
8673
+ positionsKey,
8674
+ (prevPositions) => {
8675
+ if (prevPositions?.rows?.length) {
8676
+ return {
8677
+ ...prevPositions,
8678
+ rows: prevPositions.rows.map((row) => {
8679
+ return row.symbol === symbol && row.margin_mode === marginMode ? { ...row, leverage } : row;
8680
+ })
8681
+ };
8682
+ }
8683
+ return prevPositions;
8684
+ },
8685
+ {
8686
+ revalidate: false
8687
+ }
8688
+ );
8689
+ useSWR5.mutate(
8690
+ leveragesKey,
8691
+ (prev) => {
8692
+ if (!prev) {
8693
+ return [
8694
+ {
8695
+ symbol,
8696
+ leverage,
8697
+ margin_mode: marginMode
8698
+ }
8699
+ ];
8700
+ }
8701
+ const index = prev.findIndex(
8702
+ (item) => item.symbol === symbol && (item.margin_mode ?? types.MarginMode.CROSS) === (marginMode ?? types.MarginMode.CROSS)
8703
+ );
8704
+ if (index === -1) {
8705
+ return [
8706
+ ...prev,
8707
+ {
8708
+ symbol,
8709
+ leverage,
8710
+ margin_mode: marginMode
8711
+ }
8712
+ ];
8713
+ }
8714
+ const next = [...prev];
8715
+ next[index] = {
8716
+ ...next[index],
8717
+ leverage
8718
+ };
8719
+ return next;
8720
+ },
8721
+ {
8722
+ revalidate: false
8723
+ }
8724
+ );
8466
8725
  }
8467
8726
  });
8468
8727
  return () => unsubscribe?.();
@@ -8483,7 +8742,7 @@ var usePrivateDataObserver = (options) => {
8483
8742
  ...prevPositions,
8484
8743
  rows: prevPositions.rows.map((row) => {
8485
8744
  const itemIndex = nextPositions.findIndex(
8486
- (item) => item.symbol === row.symbol
8745
+ (item) => item.symbol === row.symbol && item.marginMode === row.margin_mode
8487
8746
  );
8488
8747
  if (itemIndex >= 0) {
8489
8748
  const itemArr = nextPositions.splice(itemIndex, 1);
@@ -8666,14 +8925,70 @@ var OrderValidation = class {
8666
8925
 
8667
8926
  // src/services/orderCreator/baseCreator.ts
8668
8927
  var BaseOrderCreator = class {
8669
- baseOrder(data) {
8928
+ /**
8929
+ * Template method for order creation
8930
+ * Defines the algorithm structure with hooks for subclasses
8931
+ */
8932
+ create(values, config) {
8933
+ this.beforeCreate(values, config);
8934
+ const order = this.buildOrder(values, config);
8935
+ return this.afterCreate(order, config);
8936
+ }
8937
+ /**
8938
+ * Template method for order validation
8939
+ * Defines the algorithm structure with hooks for subclasses
8940
+ */
8941
+ validate(values, config) {
8942
+ this.beforeValidate(values, config);
8943
+ const errors = this.runValidations(values, config);
8944
+ return Promise.resolve(this.afterValidate(errors, values, config));
8945
+ }
8946
+ /**
8947
+ * Hook method called before order creation
8948
+ * Subclasses can override to perform pre-creation setup
8949
+ * @param values - Order values
8950
+ * @param config - Configuration
8951
+ */
8952
+ beforeCreate(values, config) {
8953
+ }
8954
+ /**
8955
+ * Hook method called after order creation
8956
+ * Subclasses can override to perform post-creation processing
8957
+ * @param order - The created order
8958
+ * @param config - Configuration
8959
+ * @returns The final order (possibly modified)
8960
+ */
8961
+ afterCreate(order, config) {
8962
+ return order;
8963
+ }
8964
+ /**
8965
+ * Hook method called before validation
8966
+ * Subclasses can override to perform pre-validation setup
8967
+ * @param values - Order values to validate
8968
+ * @param config - Configuration
8969
+ */
8970
+ beforeValidate(values, config) {
8971
+ }
8972
+ /**
8973
+ * Hook method called after validation
8974
+ * Subclasses can override to perform post-validation processing
8975
+ * @param errors - Validation errors found
8976
+ * @param values - Original order values
8977
+ * @param config - Configuration
8978
+ * @returns Final validation result (possibly modified)
8979
+ */
8980
+ afterValidate(errors, values, config) {
8981
+ return errors;
8982
+ }
8983
+ baseOrder(data) {
8670
8984
  const order = {
8671
8985
  symbol: data.symbol,
8672
8986
  order_type: data.order_type === types.OrderType.LIMIT ? !!data.order_type_ext ? data.order_type_ext : data.order_type : data.order_type,
8673
8987
  side: data.side,
8674
8988
  reduce_only: data.reduce_only,
8675
8989
  order_quantity: data.order_quantity,
8676
- total: data.total
8990
+ total: data.total,
8991
+ margin_mode: data.margin_mode || types.MarginMode.CROSS
8677
8992
  // slippage: data.slippage,
8678
8993
  };
8679
8994
  if (data.order_type === types.OrderType.MARKET && !!data.slippage) {
@@ -8692,10 +9007,21 @@ var BaseOrderCreator = class {
8692
9007
  child_orders: [bracketOrder]
8693
9008
  };
8694
9009
  }
9010
+ /**
9011
+ * Base validation method that can be called by subclasses
9012
+ * Validates common order properties like quantity and min notional
9013
+ * @param values - Order values to validate
9014
+ * @param configs - Configuration
9015
+ * @returns Validation result (synchronous, not a Promise)
9016
+ */
8695
9017
  baseValidate(values, configs) {
8696
9018
  const errors = {};
8697
9019
  const { maxQty, symbol, markPrice } = configs;
8698
- let { order_quantity, total, order_price, reduce_only, order_type } = values;
9020
+ let order_quantity = values.order_quantity;
9021
+ const total = values.total;
9022
+ const order_price = values.order_price;
9023
+ const reduce_only = values.reduce_only;
9024
+ const order_type = values.order_type;
8699
9025
  const { min_notional, base_tick, quote_dp, quote_tick, base_dp } = symbol || {};
8700
9026
  if (!order_quantity) {
8701
9027
  if (total && order_price) {
@@ -8740,7 +9066,7 @@ var BaseOrderCreator = class {
8740
9066
  };
8741
9067
  }
8742
9068
  this.validateBracketOrder(values, configs, errors);
8743
- return Promise.resolve(errors);
9069
+ return errors;
8744
9070
  }
8745
9071
  totalToQuantity(order, config) {
8746
9072
  if (!order.order_quantity && order.total && order.order_price) {
@@ -8889,7 +9215,11 @@ var BBOOrderCreator = class extends BaseOrderCreator {
8889
9215
  super(...arguments);
8890
9216
  this.orderType = types.OrderType.LIMIT;
8891
9217
  }
8892
- create(values) {
9218
+ /**
9219
+ * Builds the BBO order
9220
+ * Implements template method hook
9221
+ */
9222
+ buildOrder(values) {
8893
9223
  const order = {
8894
9224
  ...this.baseOrder(values),
8895
9225
  level: values.level
@@ -8902,15 +9232,18 @@ var BBOOrderCreator = class extends BaseOrderCreator {
8902
9232
  "reduce_only",
8903
9233
  "side",
8904
9234
  "order_type",
9235
+ "margin_mode",
8905
9236
  "level"
8906
9237
  ],
8907
9238
  order
8908
9239
  );
8909
9240
  }
8910
- async validate(values, configs) {
8911
- return this.baseValidate(values, configs).then((errors) => {
8912
- return errors;
8913
- });
9241
+ /**
9242
+ * Runs base validations
9243
+ * Implements template method hook
9244
+ */
9245
+ runValidations(values, configs) {
9246
+ return this.baseValidate(values, configs);
8914
9247
  }
8915
9248
  };
8916
9249
  function getOrderPrice(order, askAndBid) {
@@ -8937,6 +9270,24 @@ function getOrderPrice(order, askAndBid) {
8937
9270
  }
8938
9271
  }
8939
9272
  }
9273
+ perp.order.getOrderReferencePrice;
9274
+ function getOrderReferencePriceFromOrder(order, askAndBid) {
9275
+ if (!askAndBid || askAndBid.length < 2) return null;
9276
+ if (!order.order_type || !order.side) {
9277
+ return null;
9278
+ }
9279
+ return perp.order.getOrderReferencePrice(
9280
+ {
9281
+ orderType: order.order_type,
9282
+ orderTypeExt: order.order_type_ext,
9283
+ side: order.side,
9284
+ limitPrice: order.order_price ? Number(order.order_price) : void 0,
9285
+ triggerPrice: order.trigger_price ? Number(order.trigger_price) : void 0
9286
+ },
9287
+ askAndBid[0],
9288
+ askAndBid[1]
9289
+ );
9290
+ }
8940
9291
  function getPriceRange(inputs) {
8941
9292
  const { basePrice, side, symbolInfo } = inputs;
8942
9293
  const { price_range, price_scope, quote_min, quote_max } = symbolInfo;
@@ -8950,97 +9301,170 @@ function getPriceRange(inputs) {
8950
9301
  min: minPriceNumber,
8951
9302
  max: scopePriceNumber
8952
9303
  };
8953
- const minPrice3 = Math.max(quote_min, priceRange?.min);
8954
- const maxPrice3 = Math.min(quote_max, priceRange?.max);
9304
+ const minPrice = Math.max(quote_min, priceRange?.min);
9305
+ const maxPrice = Math.min(quote_max, priceRange?.max);
8955
9306
  return {
8956
- minPrice: minPrice3,
8957
- maxPrice: maxPrice3
9307
+ minPrice,
9308
+ maxPrice
8958
9309
  };
8959
9310
  }
8960
9311
 
8961
- // src/services/orderCreator/baseBracketOrderCreator.ts
9312
+ // src/services/orderCreator/validators/TPSLValidationStrategy.ts
8962
9313
  var formatPrice = (price, quote_dp) => {
8963
9314
  return new utils.Decimal(price).toDecimalPlaces(quote_dp).toNumber();
8964
9315
  };
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)
9316
+ var TPSLValidationStrategy = class {
9317
+ /**
9318
+ * Validates TP/SL order values
9319
+ * @param values - TP/SL order values including trigger prices, order prices, etc.
9320
+ * @param config - Configuration with symbol info and mark price
9321
+ * @returns Validation result object with any errors found
9322
+ */
9323
+ validate(values, config) {
9324
+ const result = /* @__PURE__ */ Object.create(null);
9325
+ const {
9326
+ tp_trigger_price,
9327
+ tp_order_price,
9328
+ tp_order_type,
9329
+ sl_trigger_price,
9330
+ sl_order_price,
9331
+ sl_order_type,
9332
+ side,
9333
+ quantity,
9334
+ order_type,
9335
+ order_price
9336
+ } = values;
9337
+ const qty = Number(quantity);
9338
+ const maxQty = config.maxQty;
9339
+ const { quote_max, quote_min, quote_dp, base_min } = config.symbol ?? {};
9340
+ const mark_price = order_type === types.OrderType.MARKET || order_type == null ? config.markPrice : order_price ? Number(order_price) : void 0;
9341
+ const tpslSide = side === types.OrderSide.BUY ? types.OrderSide.SELL : types.OrderSide.BUY;
9342
+ if (!isNaN(qty) && qty > maxQty) {
9343
+ result.quantity = OrderValidation.max("quantity", config.maxQty);
9344
+ }
9345
+ if (!isNaN(qty) && qty < (base_min ?? 0)) {
9346
+ result.quantity = OrderValidation.min("quantity", base_min ?? 0);
9347
+ }
9348
+ if (tp_trigger_price !== void 0 && tp_trigger_price !== "" && tp_trigger_price !== null && Number(tp_trigger_price) < 0) {
9349
+ result.tp_trigger_price = OrderValidation.min("tp_trigger_price", 0);
9350
+ }
9351
+ if (sl_trigger_price !== void 0 && sl_trigger_price !== "" && sl_trigger_price !== null && Number(sl_trigger_price) < 0) {
9352
+ result.sl_trigger_price = OrderValidation.min("sl_trigger_price", 0);
9353
+ }
9354
+ if (tp_order_type === types.OrderType.LIMIT && !tp_order_price) {
9355
+ result.tp_order_price = OrderValidation.required("tp_order_price");
9356
+ }
9357
+ if (sl_order_type === types.OrderType.LIMIT && !sl_order_price) {
9358
+ result.sl_order_price = OrderValidation.required("sl_order_price");
9359
+ }
9360
+ if (side === types.OrderSide.BUY && mark_price) {
9361
+ this.validateBuySide(
9362
+ {
9363
+ tp_trigger_price,
9364
+ tp_order_price,
9365
+ sl_trigger_price,
9366
+ sl_order_price
9367
+ },
9368
+ {
9369
+ mark_price,
9370
+ quote_min: quote_min ?? 0,
9371
+ quote_max: quote_max ?? 0,
9372
+ quote_dp: quote_dp ?? 0,
9373
+ tpslSide,
9374
+ symbol: config.symbol
9375
+ },
9376
+ result
9005
9377
  );
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)
9378
+ } else if (side === types.OrderSide.SELL && mark_price) {
9379
+ this.validateSellSide(
9380
+ {
9381
+ tp_trigger_price,
9382
+ tp_order_price,
9383
+ sl_trigger_price,
9384
+ sl_order_price
9385
+ },
9386
+ {
9387
+ mark_price,
9388
+ quote_min: quote_min ?? 0,
9389
+ quote_max: quote_max ?? 0,
9390
+ quote_dp: quote_dp ?? 0,
9391
+ tpslSide,
9392
+ symbol: config.symbol
9393
+ },
9394
+ result
9011
9395
  );
9012
9396
  }
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
- );
9397
+ return Object.keys(result).length > 0 ? result : null;
9398
+ }
9399
+ /**
9400
+ * Validates TP/SL for BUY orders
9401
+ * For BUY orders:
9402
+ * - SL trigger price must be < mark price
9403
+ * - TP trigger price must be > mark price
9404
+ */
9405
+ validateBuySide(prices, config, result) {
9406
+ const {
9407
+ tp_trigger_price,
9408
+ tp_order_price,
9409
+ sl_trigger_price,
9410
+ sl_order_price
9411
+ } = prices;
9412
+ const { mark_price, quote_min, quote_max, quote_dp, tpslSide, symbol } = config;
9413
+ if (sl_trigger_price !== void 0 && sl_trigger_price !== "" && sl_trigger_price !== null) {
9414
+ const slTrigger = Number(sl_trigger_price);
9415
+ if (!isNaN(slTrigger)) {
9416
+ if (quote_min > 0 && slTrigger < quote_min) {
9417
+ result.sl_trigger_price = OrderValidation.min(
9418
+ "sl_trigger_price",
9419
+ formatPrice(quote_min, quote_dp)
9420
+ );
9421
+ }
9422
+ if (slTrigger >= mark_price) {
9423
+ result.sl_trigger_price = OrderValidation.max(
9424
+ "sl_trigger_price",
9425
+ formatPrice(mark_price, quote_dp)
9426
+ );
9427
+ }
9428
+ }
9018
9429
  }
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
- );
9430
+ if (tp_trigger_price !== void 0 && tp_trigger_price !== "" && tp_trigger_price !== null) {
9431
+ const tpTrigger = Number(tp_trigger_price);
9432
+ if (!isNaN(tpTrigger)) {
9433
+ if (tpTrigger <= mark_price) {
9434
+ result.tp_trigger_price = OrderValidation.min(
9435
+ "tp_trigger_price",
9436
+ formatPrice(mark_price, quote_dp)
9437
+ );
9438
+ }
9439
+ if (quote_max > 0 && tpTrigger > quote_max) {
9440
+ result.tp_trigger_price = OrderValidation.max(
9441
+ "tp_trigger_price",
9442
+ formatPrice(quote_max, quote_dp)
9443
+ );
9444
+ }
9445
+ }
9024
9446
  }
9025
9447
  if (sl_trigger_price && sl_order_price) {
9026
9448
  const priceRange = getPriceRange({
9027
9449
  side: tpslSide,
9028
9450
  basePrice: Number(sl_trigger_price),
9029
- symbolInfo: config.symbol
9451
+ symbolInfo: symbol
9030
9452
  });
9031
- if (Number(sl_order_price) < priceRange.minPrice) {
9453
+ const slOrderPrice = Number(sl_order_price);
9454
+ const slTrigger = Number(sl_trigger_price);
9455
+ if (slOrderPrice < priceRange.minPrice) {
9032
9456
  result.sl_order_price = OrderValidation.min(
9033
9457
  "sl_order_price",
9034
9458
  formatPrice(priceRange.minPrice, quote_dp)
9035
9459
  );
9036
9460
  }
9037
- if (Number(sl_order_price) > priceRange.maxPrice) {
9461
+ if (slOrderPrice > priceRange.maxPrice) {
9038
9462
  result.sl_order_price = OrderValidation.max(
9039
9463
  "sl_order_price",
9040
9464
  formatPrice(priceRange.maxPrice, quote_dp)
9041
9465
  );
9042
9466
  }
9043
- if (Number(sl_trigger_price) < Number(sl_order_price)) {
9467
+ if (slTrigger < slOrderPrice) {
9044
9468
  result.sl_trigger_price = OrderValidation.priceErrorMax("sl_trigger_price");
9045
9469
  }
9046
9470
  }
@@ -9048,69 +9472,96 @@ async function bracketOrderValidator(values, config) {
9048
9472
  const priceRange = getPriceRange({
9049
9473
  side: tpslSide,
9050
9474
  basePrice: Number(tp_trigger_price),
9051
- symbolInfo: config.symbol
9475
+ symbolInfo: symbol
9052
9476
  });
9053
- if (Number(tp_order_price) > priceRange.maxPrice) {
9477
+ const tpOrderPrice = Number(tp_order_price);
9478
+ const tpTrigger = Number(tp_trigger_price);
9479
+ if (tpOrderPrice > priceRange.maxPrice) {
9054
9480
  result.tp_order_price = OrderValidation.max(
9055
9481
  "tp_order_price",
9056
9482
  formatPrice(priceRange.maxPrice, quote_dp)
9057
9483
  );
9058
9484
  }
9059
- if (Number(tp_order_price) < priceRange.minPrice) {
9485
+ if (tpOrderPrice < priceRange.minPrice) {
9060
9486
  result.tp_order_price = OrderValidation.min(
9061
9487
  "tp_order_price",
9062
9488
  formatPrice(priceRange.minPrice, quote_dp)
9063
9489
  );
9064
9490
  }
9065
- if (Number(tp_trigger_price) > Number(tp_order_price)) {
9491
+ if (tpTrigger > tpOrderPrice) {
9066
9492
  result.tp_trigger_price = OrderValidation.priceErrorMax("tp_trigger_price");
9067
9493
  }
9068
9494
  }
9069
9495
  }
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
- );
9496
+ /**
9497
+ * Validates TP/SL for SELL orders
9498
+ * For SELL orders:
9499
+ * - SL trigger price must be > mark price
9500
+ * - TP trigger price must be < mark price
9501
+ */
9502
+ validateSellSide(prices, config, result) {
9503
+ const {
9504
+ tp_trigger_price,
9505
+ tp_order_price,
9506
+ sl_trigger_price,
9507
+ sl_order_price
9508
+ } = prices;
9509
+ const { mark_price, quote_min, quote_max, quote_dp, tpslSide, symbol } = config;
9510
+ if (sl_trigger_price !== void 0 && sl_trigger_price !== "" && sl_trigger_price !== null) {
9511
+ const slTrigger = Number(sl_trigger_price);
9512
+ if (!isNaN(slTrigger)) {
9513
+ if (quote_max > 0 && slTrigger > quote_max) {
9514
+ result.sl_trigger_price = OrderValidation.max(
9515
+ "sl_trigger_price",
9516
+ formatPrice(quote_max, quote_dp)
9517
+ );
9518
+ }
9519
+ if (slTrigger <= mark_price) {
9520
+ result.sl_trigger_price = OrderValidation.min(
9521
+ "sl_trigger_price",
9522
+ formatPrice(mark_price, quote_dp)
9523
+ );
9524
+ }
9525
+ }
9088
9526
  }
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
- );
9527
+ if (tp_trigger_price !== void 0 && tp_trigger_price !== "" && tp_trigger_price !== null) {
9528
+ const tpTrigger = Number(tp_trigger_price);
9529
+ if (!isNaN(tpTrigger)) {
9530
+ if (tpTrigger >= mark_price) {
9531
+ result.tp_trigger_price = OrderValidation.max(
9532
+ "tp_trigger_price",
9533
+ formatPrice(mark_price, quote_dp)
9534
+ );
9535
+ }
9536
+ if (quote_min > 0 && tpTrigger < quote_min) {
9537
+ result.tp_trigger_price = OrderValidation.min(
9538
+ "tp_trigger_price",
9539
+ formatPrice(quote_min, quote_dp)
9540
+ );
9541
+ }
9542
+ }
9094
9543
  }
9095
9544
  if (sl_trigger_price && sl_order_price) {
9096
9545
  const priceRange = getPriceRange({
9097
9546
  side: tpslSide,
9098
9547
  basePrice: Number(sl_trigger_price),
9099
- symbolInfo: config.symbol
9548
+ symbolInfo: symbol
9100
9549
  });
9101
- if (Number(sl_order_price) < priceRange.minPrice) {
9550
+ const slOrderPrice = Number(sl_order_price);
9551
+ const slTrigger = Number(sl_trigger_price);
9552
+ if (slOrderPrice < priceRange.minPrice) {
9102
9553
  result.sl_order_price = OrderValidation.min(
9103
9554
  "sl_order_price",
9104
9555
  formatPrice(priceRange.minPrice, quote_dp)
9105
9556
  );
9106
9557
  }
9107
- if (Number(sl_order_price) > priceRange.maxPrice) {
9558
+ if (slOrderPrice > priceRange.maxPrice) {
9108
9559
  result.sl_order_price = OrderValidation.max(
9109
9560
  "sl_order_price",
9110
9561
  formatPrice(priceRange.maxPrice, quote_dp)
9111
9562
  );
9112
9563
  }
9113
- if (Number(sl_trigger_price) > Number(sl_order_price)) {
9564
+ if (slTrigger > slOrderPrice) {
9114
9565
  result.sl_trigger_price = OrderValidation.priceErrorMin("sl_trigger_price");
9115
9566
  }
9116
9567
  }
@@ -9118,37 +9569,294 @@ async function bracketOrderValidator(values, config) {
9118
9569
  const priceRange = getPriceRange({
9119
9570
  side: tpslSide,
9120
9571
  basePrice: Number(tp_trigger_price),
9121
- symbolInfo: config.symbol
9572
+ symbolInfo: symbol
9122
9573
  });
9123
- if (Number(tp_order_price) < priceRange.minPrice) {
9574
+ const tpOrderPrice = Number(tp_order_price);
9575
+ const tpTrigger = Number(tp_trigger_price);
9576
+ if (tpOrderPrice < priceRange.minPrice) {
9124
9577
  result.tp_order_price = OrderValidation.min(
9125
9578
  "tp_order_price",
9126
9579
  formatPrice(priceRange.minPrice, quote_dp)
9127
9580
  );
9128
9581
  }
9129
- if (Number(tp_order_price) > priceRange.maxPrice) {
9582
+ if (tpOrderPrice > priceRange.maxPrice) {
9130
9583
  result.tp_order_price = OrderValidation.max(
9131
9584
  "tp_order_price",
9132
9585
  formatPrice(priceRange.maxPrice, quote_dp)
9133
9586
  );
9134
9587
  }
9135
- if (Number(tp_trigger_price) < Number(tp_order_price)) {
9588
+ if (tpTrigger < tpOrderPrice) {
9136
9589
  result.tp_trigger_price = OrderValidation.priceErrorMax("tp_trigger_price");
9137
9590
  }
9138
9591
  }
9139
9592
  }
9140
- return Object.keys(result).length > 0 ? result : null;
9593
+ };
9594
+
9595
+ // src/services/orderCreator/baseBracketOrderCreator.ts
9596
+ async function bracketOrderValidator(values, config) {
9597
+ const strategy = new TPSLValidationStrategy();
9598
+ return strategy.validate(values, config);
9141
9599
  }
9142
- var { maxPrice, minPrice, scopePrice } = perp.order;
9600
+
9601
+ // src/services/orderCreator/validators/BaseValidator.ts
9602
+ var BaseValidator = class {
9603
+ /**
9604
+ * Sets the next validator in the chain
9605
+ * @param validator - The next validator to call
9606
+ * @returns The next validator for method chaining
9607
+ */
9608
+ setNext(validator) {
9609
+ this.next = validator;
9610
+ return validator;
9611
+ }
9612
+ /**
9613
+ * Validates values and passes to next validator in chain
9614
+ * @param values - The values to validate
9615
+ * @param config - Configuration for validation
9616
+ * @param errors - Accumulated validation errors
9617
+ * @returns Updated validation result
9618
+ */
9619
+ validate(values, config, errors) {
9620
+ const result = this.doValidate(values, config);
9621
+ if (result) {
9622
+ errors[this.getFieldName()] = result;
9623
+ }
9624
+ return this.next?.validate(values, config, errors) ?? errors;
9625
+ }
9626
+ };
9627
+ var PriceValidationStrategy = class {
9628
+ /**
9629
+ * Validates order price against symbol constraints and price range
9630
+ * @param values - Object containing order_price, side, and order_type
9631
+ * @param config - Configuration with symbol info and mark price
9632
+ * @returns Validation error if price is invalid, undefined otherwise
9633
+ */
9634
+ validate(values, config) {
9635
+ const { order_price, side } = values;
9636
+ if (!order_price) {
9637
+ return OrderValidation.required("order_price");
9638
+ }
9639
+ const price = new utils.Decimal(order_price);
9640
+ const { symbol } = config;
9641
+ const { quote_max, quote_min, quote_dp, price_range, price_scope } = symbol;
9642
+ const maxPriceNumber = perp.order.maxPrice(config.markPrice, price_range);
9643
+ const minPriceNumber = perp.order.minPrice(config.markPrice, price_range);
9644
+ const scopePriceNumber = perp.order.scopePrice(
9645
+ config.markPrice,
9646
+ price_scope,
9647
+ side
9648
+ );
9649
+ const priceRange = side === types.OrderSide.BUY ? {
9650
+ min: scopePriceNumber,
9651
+ max: maxPriceNumber
9652
+ } : {
9653
+ min: minPriceNumber,
9654
+ max: scopePriceNumber
9655
+ };
9656
+ if (price.gt(quote_max)) {
9657
+ return OrderValidation.max("order_price", quote_max);
9658
+ }
9659
+ if (price.lt(quote_min)) {
9660
+ return OrderValidation.min("order_price", quote_min);
9661
+ }
9662
+ if (price.gt(priceRange.max)) {
9663
+ return OrderValidation.max(
9664
+ "order_price",
9665
+ new utils.Decimal(priceRange.max).todp(quote_dp).toString()
9666
+ );
9667
+ }
9668
+ if (price.lt(priceRange.min)) {
9669
+ return OrderValidation.min(
9670
+ "order_price",
9671
+ new utils.Decimal(priceRange.min).todp(quote_dp).toString()
9672
+ );
9673
+ }
9674
+ return void 0;
9675
+ }
9676
+ };
9677
+ var TriggerPriceValidationStrategy = class {
9678
+ /**
9679
+ * Validates trigger price against symbol constraints
9680
+ * @param values - Object containing trigger_price
9681
+ * @param config - Configuration with symbol info
9682
+ * @returns Validation error if trigger price is invalid, undefined otherwise
9683
+ */
9684
+ validate(values, config) {
9685
+ const { trigger_price } = values;
9686
+ const { symbol } = config;
9687
+ const { quote_max, quote_min } = symbol;
9688
+ if (!trigger_price) {
9689
+ return OrderValidation.required("trigger_price");
9690
+ }
9691
+ const triggerPrice = Number(trigger_price);
9692
+ if (triggerPrice > quote_max) {
9693
+ return OrderValidation.max("trigger_price", quote_max);
9694
+ }
9695
+ if (triggerPrice < quote_min || triggerPrice === 0) {
9696
+ return OrderValidation.min("trigger_price", quote_min);
9697
+ }
9698
+ return void 0;
9699
+ }
9700
+ };
9701
+
9702
+ // src/services/orderCreator/validators/PriceValidator.ts
9703
+ var PriceValidator = class extends BaseValidator {
9704
+ constructor() {
9705
+ super();
9706
+ this.strategy = new PriceValidationStrategy();
9707
+ }
9708
+ doValidate(values, config) {
9709
+ return this.strategy.validate(
9710
+ {
9711
+ order_price: values.order_price,
9712
+ side: values.side,
9713
+ order_type: values.order_type
9714
+ },
9715
+ config
9716
+ );
9717
+ }
9718
+ getFieldName() {
9719
+ return "order_price";
9720
+ }
9721
+ };
9722
+ var QuantityValidationStrategy = class {
9723
+ /**
9724
+ * Validates order quantity against symbol constraints
9725
+ * Also handles conversion from total to quantity if needed
9726
+ * @param values - Object containing order_quantity, total, and order_price
9727
+ * @param config - Configuration with symbol info and max quantity
9728
+ * @returns Validation error if quantity is invalid, undefined otherwise
9729
+ */
9730
+ validate(values, config) {
9731
+ let { order_quantity, total, order_price } = values;
9732
+ const { maxQty, symbol } = config;
9733
+ const { base_min, base_dp, quote_dp } = symbol;
9734
+ if (!order_quantity && total && order_price) {
9735
+ const totalNumber = new utils.Decimal(total);
9736
+ const qty2 = totalNumber.dividedBy(order_price).toFixed(quote_dp);
9737
+ order_quantity = qty2;
9738
+ }
9739
+ if (!order_quantity) {
9740
+ return OrderValidation.required("order_quantity");
9741
+ }
9742
+ const qty = new utils.Decimal(order_quantity);
9743
+ if (qty.lt(base_min)) {
9744
+ return OrderValidation.min(
9745
+ "order_quantity",
9746
+ new utils.Decimal(base_min).todp(base_dp).toString()
9747
+ );
9748
+ }
9749
+ if (qty.gt(maxQty)) {
9750
+ return OrderValidation.max(
9751
+ "order_quantity",
9752
+ new utils.Decimal(maxQty).todp(base_dp).toString()
9753
+ );
9754
+ }
9755
+ return void 0;
9756
+ }
9757
+ };
9758
+
9759
+ // src/services/orderCreator/validators/QuantityValidator.ts
9760
+ var QuantityValidator = class extends BaseValidator {
9761
+ constructor() {
9762
+ super();
9763
+ this.strategy = new QuantityValidationStrategy();
9764
+ }
9765
+ doValidate(values, config) {
9766
+ return this.strategy.validate(
9767
+ {
9768
+ order_quantity: values.order_quantity,
9769
+ total: values.total,
9770
+ order_price: values.order_price
9771
+ },
9772
+ config
9773
+ );
9774
+ }
9775
+ getFieldName() {
9776
+ return "order_quantity";
9777
+ }
9778
+ };
9779
+
9780
+ // src/services/orderCreator/validators/ValidationChain.ts
9781
+ var ValidationChain = class {
9782
+ constructor() {
9783
+ this.validators = [];
9784
+ }
9785
+ /**
9786
+ * Adds a validator to the chain
9787
+ * @param validator - The validator to add
9788
+ * @returns This chain instance for method chaining
9789
+ */
9790
+ addValidator(validator) {
9791
+ this.validators.push(validator);
9792
+ if (!this.head) {
9793
+ this.head = validator;
9794
+ } else {
9795
+ let current = this.head;
9796
+ while (current && current.next) {
9797
+ current = current.next;
9798
+ }
9799
+ if (current) {
9800
+ current.setNext(validator);
9801
+ }
9802
+ }
9803
+ return this;
9804
+ }
9805
+ /**
9806
+ * Adds multiple validators to the chain
9807
+ * @param validators - Array of validators to add
9808
+ * @returns This chain instance for method chaining
9809
+ */
9810
+ addValidators(validators) {
9811
+ validators.forEach((validator) => this.addValidator(validator));
9812
+ return this;
9813
+ }
9814
+ /**
9815
+ * Validates values using all validators in the chain
9816
+ * @param values - The values to validate
9817
+ * @param config - Configuration for validation
9818
+ * @returns Validation result with all errors found
9819
+ */
9820
+ validate(values, config) {
9821
+ const errors = {};
9822
+ if (this.head) {
9823
+ return this.head.validate(values, config, errors);
9824
+ }
9825
+ return errors;
9826
+ }
9827
+ /**
9828
+ * Clears all validators from the chain
9829
+ */
9830
+ clear() {
9831
+ this.validators = [];
9832
+ this.head = void 0;
9833
+ }
9834
+ /**
9835
+ * Gets the number of validators in the chain
9836
+ * @returns The number of validators
9837
+ */
9838
+ get length() {
9839
+ return this.validators.length;
9840
+ }
9841
+ };
9842
+
9843
+ // src/services/orderCreator/limitOrderCreator.ts
9143
9844
  var LimitOrderCreator = class extends BaseOrderCreator {
9144
9845
  constructor() {
9145
9846
  super(...arguments);
9847
+ // private priceValidationStrategy = new PriceValidationStrategy();
9848
+ this.validationChain = new ValidationChain().addValidator(new QuantityValidator()).addValidator(new PriceValidator());
9146
9849
  this.orderType = types.OrderType.LIMIT;
9147
9850
  }
9148
- create(values, config) {
9851
+ /**
9852
+ * Builds the limit order
9853
+ * Implements template method hook
9854
+ */
9855
+ buildOrder(values, config) {
9856
+ const orderlyValues = values;
9149
9857
  const order = {
9150
- ...this.baseOrder(values),
9151
- order_price: values.order_price
9858
+ ...this.baseOrder(orderlyValues),
9859
+ order_price: orderlyValues.order_price
9152
9860
  };
9153
9861
  this.totalToQuantity(order, config);
9154
9862
  return ramda.pick(
@@ -9160,58 +9868,23 @@ var LimitOrderCreator = class extends BaseOrderCreator {
9160
9868
  "reduce_only",
9161
9869
  "side",
9162
9870
  "order_type",
9871
+ "margin_mode",
9163
9872
  "algo_type",
9164
9873
  "child_orders"
9165
9874
  ],
9166
9875
  order
9167
9876
  );
9168
9877
  }
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
- });
9878
+ /**
9879
+ * Runs validations using validation chain
9880
+ * Implements template method hook
9881
+ */
9882
+ runValidations(values, config) {
9883
+ const orderlyValues = values;
9884
+ const errors = this.baseValidate(orderlyValues, config);
9885
+ const chainErrors = this.validationChain.validate(orderlyValues, config);
9886
+ Object.assign(errors, chainErrors);
9887
+ return errors;
9215
9888
  }
9216
9889
  };
9217
9890
 
@@ -9234,34 +9907,81 @@ var BracketLimitOrderCreator = class extends LimitOrderCreator {
9234
9907
  }
9235
9908
  };
9236
9909
 
9910
+ // src/services/orderCreator/validators/SlippageValidationStrategy.ts
9911
+ var SlippageValidationStrategy = class {
9912
+ /**
9913
+ * Validates slippage against estimated slippage
9914
+ * @param values - Object containing slippage value
9915
+ * @param config - Configuration with estimated slippage
9916
+ * @returns Validation error if slippage exceeds estimated, undefined otherwise
9917
+ */
9918
+ validate(values, config) {
9919
+ const slippage = Number(values.slippage);
9920
+ const estSlippage = Number.isNaN(config.estSlippage) ? 0 : Number(config.estSlippage) * 100;
9921
+ if (!isNaN(slippage) && estSlippage > slippage) {
9922
+ return {
9923
+ type: "max",
9924
+ message: "Estimated slippage exceeds your maximum allowed slippage.",
9925
+ value: estSlippage
9926
+ };
9927
+ }
9928
+ return void 0;
9929
+ }
9930
+ };
9931
+
9932
+ // src/services/orderCreator/validators/SlippageValidator.ts
9933
+ var SlippageValidator = class extends BaseValidator {
9934
+ constructor() {
9935
+ super();
9936
+ this.strategy = new SlippageValidationStrategy();
9937
+ }
9938
+ doValidate(values, config) {
9939
+ return this.strategy.validate(
9940
+ {
9941
+ slippage: values.slippage
9942
+ },
9943
+ config
9944
+ );
9945
+ }
9946
+ getFieldName() {
9947
+ return "slippage";
9948
+ }
9949
+ };
9950
+
9237
9951
  // src/services/orderCreator/marketOrderCreator.ts
9238
9952
  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
- };
9953
+ constructor() {
9954
+ super(...arguments);
9955
+ this.slippageValidationStrategy = new SlippageValidationStrategy();
9956
+ this.validationChain = new ValidationChain().addValidator(new QuantityValidator()).addValidator(new SlippageValidator());
9957
+ this.orderType = types.OrderType.MARKET;
9248
9958
  }
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
- });
9959
+ /**
9960
+ * Builds the market order
9961
+ * Implements template method hook
9962
+ */
9963
+ buildOrder(values, config) {
9964
+ const orderlyValues = values;
9965
+ const data = this.baseOrder(orderlyValues);
9966
+ const result = { ...data };
9967
+ delete result.order_price;
9968
+ delete result.total;
9969
+ delete result.trigger_price;
9970
+ if ("isStopOrder" in result) {
9971
+ delete result.isStopOrder;
9972
+ }
9973
+ return result;
9974
+ }
9975
+ /**
9976
+ * Runs validations using validation chain
9977
+ * Implements template method hook
9978
+ */
9979
+ runValidations(values, configs) {
9980
+ const orderlyValues = values;
9981
+ const result = this.baseValidate(orderlyValues, configs);
9982
+ const chainErrors = this.validationChain.validate(orderlyValues, configs);
9983
+ Object.assign(result, chainErrors);
9984
+ return result;
9265
9985
  }
9266
9986
  };
9267
9987
 
@@ -9293,14 +10013,26 @@ var FOKOrderCreator = class extends LimitOrderCreator {
9293
10013
 
9294
10014
  // src/services/orderCreator/generalCreator.ts
9295
10015
  var GeneralOrderCreator = class extends BaseOrderCreator {
9296
- create(data) {
10016
+ constructor() {
10017
+ super(...arguments);
10018
+ this.orderType = void 0;
10019
+ }
10020
+ /**
10021
+ * Builds the general order
10022
+ * Implements template method hook
10023
+ */
10024
+ buildOrder(data) {
9297
10025
  return {
9298
10026
  ...this.baseOrder(data),
9299
10027
  order_price: data.order_price,
9300
10028
  order_quantity: data.order_quantity
9301
10029
  };
9302
10030
  }
9303
- validate(values, configs) {
10031
+ /**
10032
+ * Runs base validations
10033
+ * Implements template method hook
10034
+ */
10035
+ runValidations(values, configs) {
9304
10036
  return super.baseValidate(values, configs);
9305
10037
  }
9306
10038
  };
@@ -9409,7 +10141,8 @@ function calcScaledOrderBatchBody(order, symbolInfo) {
9409
10141
  distribution_type,
9410
10142
  skew,
9411
10143
  reduce_only,
9412
- visible_quantity
10144
+ visible_quantity,
10145
+ margin_mode
9413
10146
  } = order;
9414
10147
  const prices = calcScaledOrderPrices({
9415
10148
  start_price,
@@ -9435,6 +10168,8 @@ function calcScaledOrderBatchBody(order, symbolInfo) {
9435
10168
  order_quantity: qtys[index],
9436
10169
  order_price: price,
9437
10170
  reduce_only,
10171
+ margin_mode: margin_mode || types.MarginMode.CROSS,
10172
+ // Default to CROSS if not provided for backward compatibility
9438
10173
  // it will be used for identify the scaled order from ws
9439
10174
  client_order_id: `scaled_${index}_${now}`
9440
10175
  };
@@ -9538,7 +10273,11 @@ var ScaledOrderCreator = class extends BaseOrderCreator {
9538
10273
  super(...arguments);
9539
10274
  this.orderType = types.OrderType.SCALED;
9540
10275
  }
9541
- create(values, config) {
10276
+ /**
10277
+ * Builds the scaled order
10278
+ * Implements template method hook
10279
+ */
10280
+ buildOrder(values, config) {
9542
10281
  const orders = calcScaledOrderBatchBody(values, config.symbol);
9543
10282
  const { total_orders, distribution_type, skew } = values;
9544
10283
  const order = {
@@ -9556,6 +10295,7 @@ var ScaledOrderCreator = class extends BaseOrderCreator {
9556
10295
  "reduce_only",
9557
10296
  "side",
9558
10297
  "order_type",
10298
+ "margin_mode",
9559
10299
  "orders",
9560
10300
  "total_orders",
9561
10301
  "distribution_type",
@@ -9564,7 +10304,11 @@ var ScaledOrderCreator = class extends BaseOrderCreator {
9564
10304
  order
9565
10305
  );
9566
10306
  }
9567
- async validate(values, config) {
10307
+ /**
10308
+ * Runs validations for scaled order
10309
+ * Implements template method hook
10310
+ */
10311
+ runValidations(values, config) {
9568
10312
  const { maxQty, askAndBid, markPrice, symbol } = config;
9569
10313
  const { base_dp, quote_dp } = config.symbol;
9570
10314
  const { order_quantity, total, total_orders, distribution_type, skew } = values;
@@ -9633,22 +10377,22 @@ function validatePrice(values, config) {
9633
10377
  if (!config.markPrice) {
9634
10378
  return errors;
9635
10379
  }
9636
- const { minPrice: minPrice3, maxPrice: maxPrice3 } = getPriceRange({
10380
+ const { minPrice, maxPrice } = getPriceRange({
9637
10381
  side: values.side,
9638
10382
  basePrice: config.markPrice,
9639
10383
  symbolInfo: config.symbol
9640
10384
  });
9641
10385
  const comparePrice = (key, value) => {
9642
10386
  const price = new utils.Decimal(value || 0);
9643
- if (price.lt(minPrice3)) {
10387
+ if (price.lt(minPrice)) {
9644
10388
  errors[key] = OrderValidation.min(
9645
10389
  key,
9646
- new utils.Decimal(minPrice3).todp(quote_dp).toString()
10390
+ new utils.Decimal(minPrice).todp(quote_dp).toString()
9647
10391
  );
9648
- } else if (price.gt(maxPrice3)) {
10392
+ } else if (price.gt(maxPrice)) {
9649
10393
  errors[key] = OrderValidation.max(
9650
10394
  key,
9651
- new utils.Decimal(maxPrice3).todp(quote_dp).toString()
10395
+ new utils.Decimal(maxPrice).todp(quote_dp).toString()
9652
10396
  );
9653
10397
  }
9654
10398
  };
@@ -9656,13 +10400,40 @@ function validatePrice(values, config) {
9656
10400
  comparePrice("end_price", end_price);
9657
10401
  return errors;
9658
10402
  }
9659
- var { maxPrice: maxPrice2, minPrice: minPrice2, scopePrice: scopePrice2 } = perp.order;
10403
+
10404
+ // src/services/orderCreator/validators/TriggerPriceValidator.ts
10405
+ var TriggerPriceValidator = class extends BaseValidator {
10406
+ constructor() {
10407
+ super();
10408
+ this.strategy = new TriggerPriceValidationStrategy();
10409
+ }
10410
+ doValidate(values, config) {
10411
+ return this.strategy.validate(
10412
+ {
10413
+ trigger_price: values.trigger_price
10414
+ },
10415
+ config
10416
+ );
10417
+ }
10418
+ getFieldName() {
10419
+ return "trigger_price";
10420
+ }
10421
+ };
10422
+
10423
+ // src/services/orderCreator/stopLimitOrderCreator.ts
9660
10424
  var StopLimitOrderCreator = class extends BaseOrderCreator {
9661
10425
  constructor() {
9662
10426
  super(...arguments);
10427
+ this.priceValidationStrategy = new PriceValidationStrategy();
10428
+ this.triggerPriceValidationStrategy = new TriggerPriceValidationStrategy();
10429
+ this.validationChain = new ValidationChain().addValidator(new QuantityValidator()).addValidator(new TriggerPriceValidator()).addValidator(new PriceValidator());
9663
10430
  this.orderType = types.OrderType.STOP_LIMIT;
9664
10431
  }
9665
- create(values, config) {
10432
+ /**
10433
+ * Builds the stop-limit order
10434
+ * Implements template method hook
10435
+ */
10436
+ buildOrder(values, config) {
9666
10437
  this.totalToQuantity(values, config);
9667
10438
  const order = {
9668
10439
  ...this.baseOrder(values),
@@ -9684,84 +10455,82 @@ var StopLimitOrderCreator = class extends BaseOrderCreator {
9684
10455
  "trigger_price_type",
9685
10456
  "side",
9686
10457
  "reduce_only",
10458
+ "margin_mode",
9687
10459
  "visible_quantity"
9688
10460
  ],
9689
10461
  order
9690
10462
  );
9691
10463
  }
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
- }
10464
+ /**
10465
+ * Runs validations using validation chain
10466
+ * Implements template method hook
10467
+ */
10468
+ runValidations(values, config) {
10469
+ const orderlyValues = values;
10470
+ const errors = this.baseValidate(orderlyValues, config);
10471
+ const triggerPrice = values.trigger_price;
10472
+ if (!triggerPrice || triggerPrice === 0) {
10473
+ errors.trigger_price = OrderValidation.required("trigger_price");
10474
+ } else {
10475
+ const triggerError = this.triggerPriceValidationStrategy.validate(
10476
+ { trigger_price: triggerPrice },
10477
+ config
10478
+ );
10479
+ if (triggerError) {
10480
+ errors.trigger_price = triggerError;
10481
+ }
10482
+ }
10483
+ const valuesWithFields = values;
10484
+ const orderPrice = valuesWithFields.order_price ?? valuesWithFields.price;
10485
+ const triggerPriceForPriceValidation = triggerPrice;
10486
+ const side = valuesWithFields.side ?? orderlyValues.side;
10487
+ if (!orderPrice) {
10488
+ errors.order_price = OrderValidation.required("order_price");
10489
+ } else if (orderPrice && triggerPriceForPriceValidation && side) {
10490
+ const modifiedConfig = {
10491
+ ...config,
10492
+ markPrice: Number(triggerPriceForPriceValidation)
10493
+ };
10494
+ const priceError = this.priceValidationStrategy.validate(
10495
+ {
10496
+ order_price: orderPrice,
10497
+ side,
10498
+ order_type: types.OrderType.LIMIT
10499
+ },
10500
+ modifiedConfig
10501
+ );
10502
+ if (priceError) {
10503
+ errors.order_price = priceError;
9750
10504
  }
9751
- return errors;
9752
- });
10505
+ } else if (orderPrice && triggerPriceForPriceValidation) {
10506
+ const { quote_max, quote_min } = config.symbol;
10507
+ const price = Number(orderPrice);
10508
+ if (quote_max && price > quote_max) {
10509
+ errors.order_price = OrderValidation.max("order_price", quote_max);
10510
+ } else if (quote_min && price < quote_min) {
10511
+ errors.order_price = OrderValidation.min("order_price", quote_min);
10512
+ }
10513
+ }
10514
+ return errors;
9753
10515
  }
9754
10516
  };
9755
10517
  var StopMarketOrderCreator = class extends BaseOrderCreator {
9756
- create(values) {
10518
+ constructor() {
10519
+ super(...arguments);
10520
+ this.triggerPriceValidationStrategy = new TriggerPriceValidationStrategy();
10521
+ this.validationChain = new ValidationChain().addValidator(new QuantityValidator()).addValidator(new TriggerPriceValidator());
10522
+ }
10523
+ /**
10524
+ * Builds the stop-market order
10525
+ * Implements template method hook
10526
+ */
10527
+ buildOrder(values) {
9757
10528
  const order = {
9758
10529
  ...this.baseOrder(values),
9759
- // order_price: values.order_price,
9760
10530
  trigger_price: values.trigger_price,
9761
10531
  algo_type: types.AlgoOrderRootType.STOP,
9762
10532
  type: types.OrderType.MARKET,
9763
10533
  quantity: values["order_quantity"],
9764
- // price: values["order_price"],
9765
10534
  trigger_price_type: types.TriggerPriceType.MARK_PRICE
9766
10535
  };
9767
10536
  return ramda.pick(
@@ -9771,225 +10540,40 @@ var StopMarketOrderCreator = class extends BaseOrderCreator {
9771
10540
  "algo_type",
9772
10541
  "type",
9773
10542
  "quantity",
9774
- // "price",
9775
10543
  "trigger_price_type",
9776
10544
  "side",
9777
10545
  "reduce_only",
10546
+ "margin_mode",
9778
10547
  "visible_quantity"
9779
10548
  ],
9780
10549
  order
9781
10550
  );
9782
10551
  }
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
- });
10552
+ /**
10553
+ * Runs validations using validation chain
10554
+ * Implements template method hook
10555
+ */
10556
+ runValidations(values, config) {
10557
+ const errors = this.baseValidate(values, config);
10558
+ const chainErrors = this.validationChain.validate(values, config);
10559
+ Object.assign(errors, chainErrors);
10560
+ return errors;
9797
10561
  }
9798
10562
  };
9799
- var formatPrice2 = (price, quote_dp) => {
9800
- return new utils.Decimal(price).toDecimalPlaces(quote_dp).toNumber();
9801
- };
10563
+
10564
+ // src/services/orderCreator/baseAlgoCreator.ts
9802
10565
  var BaseAlgoOrderCreator = class {
10566
+ constructor() {
10567
+ this.tpslValidationStrategy = new TPSLValidationStrategy();
10568
+ }
9803
10569
  /**
9804
- * base validate
10570
+ * Validates TP/SL order using TPSLValidationStrategy
10571
+ * Consolidates validation logic from baseBracketOrderCreator
9805
10572
  */
9806
10573
  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
- });
10574
+ return Promise.resolve(
10575
+ this.tpslValidationStrategy.validate(values, config)
10576
+ );
9993
10577
  }
9994
10578
  };
9995
10579
 
@@ -10042,7 +10626,9 @@ var TPSLOrderCreator = class extends BaseAlgoOrderCreator {
10042
10626
  reduce_only: true,
10043
10627
  quantity: values.quantity,
10044
10628
  symbol: values.symbol,
10045
- child_orders
10629
+ child_orders,
10630
+ // Include margin_mode for isolated/cross margin support; default CROSS per order entry pattern
10631
+ margin_mode: values.margin_mode || types.MarginMode.CROSS
10046
10632
  };
10047
10633
  }
10048
10634
  crateUpdateOrder(values, oldValue, config) {
@@ -10144,7 +10730,9 @@ var TPSLPositionOrderCreator = class extends BaseAlgoOrderCreator {
10144
10730
  trigger_price_type: types.TriggerPriceType.MARK_PRICE,
10145
10731
  // reduce_only: true,
10146
10732
  symbol: values.symbol,
10147
- child_orders
10733
+ child_orders,
10734
+ // Include margin_mode for isolated/cross margin support; default CROSS per order entry pattern
10735
+ margin_mode: values.margin_mode || types.MarginMode.CROSS
10148
10736
  };
10149
10737
  }
10150
10738
  crateUpdateOrder(values, oldValue, config) {
@@ -10181,7 +10769,11 @@ var TrailingStopOrderCreator = class extends BaseOrderCreator {
10181
10769
  super(...arguments);
10182
10770
  this.orderType = types.OrderType.TRAILING_STOP;
10183
10771
  }
10184
- create(values, config) {
10772
+ /**
10773
+ * Builds the trailing stop order
10774
+ * Implements template method hook
10775
+ */
10776
+ buildOrder(values, config) {
10185
10777
  const { order_quantity, activated_price, callback_value, callback_rate } = values;
10186
10778
  const order = {
10187
10779
  ...this.baseOrder(values),
@@ -10202,6 +10794,7 @@ var TrailingStopOrderCreator = class extends BaseOrderCreator {
10202
10794
  "quantity",
10203
10795
  "side",
10204
10796
  "reduce_only",
10797
+ "margin_mode",
10205
10798
  "visible_quantity",
10206
10799
  "activated_price",
10207
10800
  "callback_value",
@@ -10210,28 +10803,34 @@ var TrailingStopOrderCreator = class extends BaseOrderCreator {
10210
10803
  order
10211
10804
  );
10212
10805
  }
10213
- async validate(values, config) {
10806
+ /**
10807
+ * Runs validations for trailing stop order
10808
+ * Implements template method hook
10809
+ */
10810
+ runValidations(values, config) {
10214
10811
  const { markPrice, symbol } = config;
10215
10812
  const { quote_dp } = config.symbol;
10216
10813
  const { side, activated_price, callback_value, callback_rate } = values;
10217
- const errors = await this.baseValidate(values, config);
10814
+ const errors = this.baseValidate(values, config);
10218
10815
  if (activated_price) {
10219
- const { minPrice: minPrice3, maxPrice: maxPrice3 } = getPriceRange2({
10816
+ const { minPrice, maxPrice } = getPriceRange({
10220
10817
  side,
10221
- markPrice,
10818
+ basePrice: markPrice,
10222
10819
  symbolInfo: symbol
10223
10820
  });
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
- );
10821
+ if (!isNaN(minPrice) && !isNaN(maxPrice)) {
10822
+ const activatedPrice = new utils.Decimal(activated_price);
10823
+ if (activatedPrice.lt(minPrice) || activatedPrice.equals(0)) {
10824
+ errors.activated_price = OrderValidation.min(
10825
+ "activated_price",
10826
+ new utils.Decimal(minPrice).todp(quote_dp).toString()
10827
+ );
10828
+ } else if (activatedPrice.gt(maxPrice)) {
10829
+ errors.activated_price = OrderValidation.max(
10830
+ "activated_price",
10831
+ new utils.Decimal(maxPrice).todp(quote_dp).toString()
10832
+ );
10833
+ }
10235
10834
  }
10236
10835
  }
10237
10836
  if (!callback_value && !callback_rate) {
@@ -10263,23 +10862,6 @@ var TrailingStopOrderCreator = class extends BaseOrderCreator {
10263
10862
  return errors;
10264
10863
  }
10265
10864
  };
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
10865
 
10284
10866
  // src/services/orderCreator/factory.ts
10285
10867
  var OrderFactory = class {
@@ -10402,27 +10984,63 @@ var calcEstLiqPrice = (order, askAndBid, inputs) => {
10402
10984
  markPrice,
10403
10985
  totalCollateral,
10404
10986
  futures_taker_fee_rate,
10405
- positions: positions3
10987
+ positions: positions3,
10988
+ symbolLeverage,
10989
+ sumUnitaryFunding
10406
10990
  } = inputs;
10407
10991
  const orderFee = perp.order.orderFee({
10408
10992
  qty: quantity,
10409
10993
  price,
10410
10994
  futuresTakeFeeRate: Number(futures_taker_fee_rate) / 1e4
10411
10995
  });
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
10996
+ let liqPrice = 0;
10997
+ if (order.margin_mode === types.MarginMode.CROSS) {
10998
+ liqPrice = perp.order.estLiqPrice({
10999
+ markPrice,
11000
+ baseIMR: symbolInfo.base_imr,
11001
+ baseMMR: symbolInfo.base_mmr,
11002
+ totalCollateral,
11003
+ positions: positions3 == null ? [] : positions3,
11004
+ IMR_Factor: imr_factor,
11005
+ orderFee,
11006
+ newOrder: {
11007
+ qty: quantity,
11008
+ price,
11009
+ symbol
11010
+ }
11011
+ });
11012
+ } else {
11013
+ let isolatedPositionMargin = 0, costPosition = 0, positionQty = 0, lastSumUnitaryFunding = 0, leverage = symbolLeverage ?? 1;
11014
+ if (positions3) {
11015
+ const position = positions3.find(
11016
+ (p) => p.symbol === symbol && p.margin_mode === types.MarginMode.ISOLATED
11017
+ );
11018
+ if (position) {
11019
+ isolatedPositionMargin = position.margin ?? 0;
11020
+ costPosition = position.cost_position ?? 0;
11021
+ positionQty = position.position_qty ?? 0;
11022
+ lastSumUnitaryFunding = position.last_sum_unitary_funding ?? 0;
11023
+ leverage = position.leverage ? Number(position.leverage) : 1;
11024
+ }
10424
11025
  }
10425
- });
11026
+ liqPrice = perp.order.estLiqPriceIsolated({
11027
+ isolatedPositionMargin,
11028
+ costPosition,
11029
+ positionQty,
11030
+ sumUnitaryFunding,
11031
+ lastSumUnitaryFunding,
11032
+ markPrice,
11033
+ baseIMR: symbolInfo.base_imr,
11034
+ baseMMR: symbolInfo.base_mmr,
11035
+ IMR_Factor: imr_factor,
11036
+ leverage,
11037
+ newOrder: {
11038
+ symbol,
11039
+ qty: quantity,
11040
+ price
11041
+ }
11042
+ });
11043
+ }
10426
11044
  if (liqPrice <= 0) return null;
10427
11045
  return liqPrice;
10428
11046
  };
@@ -10480,7 +11098,9 @@ var useTaskProfitAndStopLossInternal = (position, options) => {
10480
11098
  // sl_enable: isEditing
10481
11099
  // ? checkIsEnableTpSL(options?.defaultOrder).sl_enable
10482
11100
  // : options?.tpslEnable?.sl_enable,
10483
- position_type: options?.positionType
11101
+ position_type: options?.positionType,
11102
+ // Use defaultOrder.margin_mode when editing; otherwise position.margin_mode; default CROSS for backward compatibility
11103
+ margin_mode: options?.defaultOrder?.margin_mode ?? position?.margin_mode ?? types.MarginMode.CROSS
10484
11104
  });
10485
11105
  const symbolInfo = useSymbolsInfo()[position.symbol]();
10486
11106
  const { data: markPrice } = useMarkPrice(order.symbol);
@@ -10783,11 +11403,53 @@ var useMaxLeverage = (symbol) => {
10783
11403
  };
10784
11404
  var useSymbolLeverage = (symbol) => {
10785
11405
  const symbolInfo = useSymbolInfo(symbol);
10786
- const [update, { isMutating }] = useMutation("/v1/client/leverage");
11406
+ const { state } = useAccount();
11407
+ const [updateMutation, { isMutating }] = useMutation("/v1/client/leverage");
10787
11408
  const maxLeverage = React.useMemo(() => {
10788
11409
  const baseIMR = symbolInfo?.("base_imr");
10789
11410
  return baseIMR ? 1 / baseIMR : 1;
10790
11411
  }, [symbolInfo]);
11412
+ const update = async (data) => {
11413
+ const result = await updateMutation(data);
11414
+ if (result?.success && data.symbol && state.accountId) {
11415
+ const key = ["/v1/client/leverages", state.accountId];
11416
+ useSWR5.mutate(
11417
+ key,
11418
+ (prev) => {
11419
+ if (!prev) {
11420
+ return [
11421
+ {
11422
+ symbol: data.symbol,
11423
+ leverage: data.leverage,
11424
+ margin_mode: data.margin_mode
11425
+ }
11426
+ ];
11427
+ }
11428
+ const index = prev.findIndex(
11429
+ (item) => item.symbol === data.symbol && (item.margin_mode ?? types.MarginMode.CROSS) === (data.margin_mode ?? types.MarginMode.CROSS)
11430
+ );
11431
+ if (index === -1) {
11432
+ return [
11433
+ ...prev,
11434
+ {
11435
+ symbol: data.symbol,
11436
+ leverage: data.leverage,
11437
+ margin_mode: data.margin_mode
11438
+ }
11439
+ ];
11440
+ }
11441
+ const next = [...prev];
11442
+ next[index] = {
11443
+ ...next[index],
11444
+ leverage: data.leverage
11445
+ };
11446
+ return next;
11447
+ },
11448
+ { revalidate: false }
11449
+ );
11450
+ }
11451
+ return result;
11452
+ };
10791
11453
  return {
10792
11454
  maxLeverage,
10793
11455
  update,
@@ -11524,8 +12186,8 @@ function useOrderEntry(symbolOrOrder, sideOrOptions, reduceOnly, options) {
11524
12186
  const keys = Object.keys(current);
11525
12187
  for (let i = 0; i < keys.length; i++) {
11526
12188
  const k = keys[i];
11527
- let preveValue = prev[k];
11528
- let currentValue = current[k];
12189
+ const preveValue = prev[k];
12190
+ const currentValue = current[k];
11529
12191
  if (typeof preveValue === "undefined" && typeof currentValue === "undefined")
11530
12192
  continue;
11531
12193
  if (preveValue !== currentValue) {
@@ -11538,7 +12200,12 @@ function useOrderEntry(symbolOrOrder, sideOrOptions, reduceOnly, options) {
11538
12200
  if (!key) return null;
11539
12201
  return { key, value, preValue };
11540
12202
  };
11541
- const maxQty = useMaxQty(symbol, sideValue, isReduceOnly);
12203
+ const { marginMode: symbolMarginMode } = useMarginModeBySymbol(symbol);
12204
+ const marginMode = typeof symbolOrOrder === "object" && symbolOrOrder.margin_mode ? symbolOrOrder.margin_mode : symbolMarginMode;
12205
+ const maxQty = useMaxQty(symbol, sideValue, {
12206
+ reduceOnly: isReduceOnly,
12207
+ marginMode: marginMode ?? types.MarginMode.CROSS
12208
+ });
11542
12209
  const parseString2Number = (order, key, dp) => {
11543
12210
  if (typeof order[key] !== "string") return;
11544
12211
  if (order[key] && order[key].startsWith(".")) {
@@ -12089,7 +12756,7 @@ var DataPaint = class extends BasePaint {
12089
12756
  );
12090
12757
  const { position, fontSize = 14 } = layout;
12091
12758
  let left = this._ratio(position.left);
12092
- let top = layout.position.top + offsetTop + this.transformTop;
12759
+ const top = layout.position.top + offsetTop + this.transformTop;
12093
12760
  let prevElementBoundingBox = {};
12094
12761
  if (typeof options.data?.position.side !== "undefined") {
12095
12762
  prevElementBoundingBox = this._drawText(options.data.position.side, {
@@ -12120,6 +12787,28 @@ var DataPaint = class extends BasePaint {
12120
12787
  fontFamily: options.fontFamily
12121
12788
  });
12122
12789
  }
12790
+ const marginMode = options.data?.position.marginMode;
12791
+ if (marginMode) {
12792
+ left += (prevElementBoundingBox.width ?? 0) + this._ratio(7);
12793
+ if (prevElementBoundingBox.width) {
12794
+ prevElementBoundingBox = this._drawText("|", {
12795
+ color: "rgba(255,255,255,0.2)",
12796
+ left,
12797
+ top: this._ratio(top),
12798
+ fontSize: this._ratio(fontSize),
12799
+ fontFamily: options.fontFamily
12800
+ });
12801
+ }
12802
+ left += (prevElementBoundingBox.width ?? 0) + this._ratio(7);
12803
+ const marginModeText = marginMode.charAt(0).toUpperCase() + marginMode.slice(1);
12804
+ prevElementBoundingBox = this._drawText(marginModeText, {
12805
+ color: layout.color,
12806
+ left,
12807
+ top: this._ratio(top),
12808
+ fontSize: this._ratio(fontSize),
12809
+ fontFamily: options.fontFamily
12810
+ });
12811
+ }
12123
12812
  if (typeof options.data?.position.leverage !== "undefined") {
12124
12813
  left += (prevElementBoundingBox.width ?? 0) + this._ratio(7);
12125
12814
  if (prevElementBoundingBox.width) {
@@ -12200,8 +12889,8 @@ var DataPaint = class extends BasePaint {
12200
12889
  (options.data?.position.informations.length ?? 0) === 2;
12201
12890
  const col = informations.length > 4 ? 3 : 2;
12202
12891
  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;
12892
+ const left = position.left + index % col * this.positionInfoCellWidth;
12893
+ const top = position.top + Math.floor(index / col) * 38 + this.transformTop;
12205
12894
  this._drawText(info.title, {
12206
12895
  left: this._ratio(left),
12207
12896
  top: this._ratio(top),
@@ -17743,95 +18432,111 @@ var initialOrderState = {
17743
18432
  trigger_price: "",
17744
18433
  tp_trigger_price: "",
17745
18434
  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
18435
  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: ""
18436
+ symbol: ""
17766
18437
  };
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,
18438
+ var useOrderStore = zustand.create()(
18439
+ immer.immer((set, get3) => ({
18440
+ entry: {
18441
+ side: types.OrderSide.BUY,
18442
+ order_type: types.OrderType.LIMIT,
18443
+ ...initialOrderState
18444
+ },
18445
+ estLeverage: null,
18446
+ estLiquidationPrice: null,
18447
+ errors: {},
17813
18448
  actions: {
17814
- updateOrder,
17815
- updateOrderByKey,
17816
- restoreOrder,
17817
- updateOrderComputed,
17818
- resetOrder,
17819
- hasTP_SL
18449
+ initOrder: (symbol, options) => {
18450
+ set((state) => {
18451
+ state.entry = {
18452
+ ...initialOrderState,
18453
+ symbol,
18454
+ side: options?.side ?? types.OrderSide.BUY,
18455
+ order_type: options?.order_type ?? types.OrderType.LIMIT,
18456
+ margin_mode: options?.margin_mode ?? types.MarginMode.CROSS
18457
+ };
18458
+ state.estLeverage = null;
18459
+ state.estLiquidationPrice = null;
18460
+ state.errors = {};
18461
+ });
18462
+ },
18463
+ hasTP_SL: () => {
18464
+ const order = get3().entry;
18465
+ return typeof order.tp_trigger_price !== "undefined" || typeof order.sl_trigger_price !== "undefined";
18466
+ },
18467
+ updateOrderComputed: (data) => {
18468
+ set(
18469
+ (state) => {
18470
+ state.estLeverage = data.estLeverage;
18471
+ state.estLiquidationPrice = data.estLiquidationPrice;
18472
+ },
18473
+ false
18474
+ // "updateOrderComputed"
18475
+ );
18476
+ },
18477
+ updateOrder: (order) => {
18478
+ set(
18479
+ (state) => {
18480
+ state.entry = {
18481
+ ...state.entry,
18482
+ ...order
18483
+ };
18484
+ },
18485
+ false
18486
+ // "updateOrder"
18487
+ );
18488
+ },
18489
+ updateOrderByKey: (key, value) => {
18490
+ set(
18491
+ (state) => {
18492
+ state.entry[key] = value;
18493
+ },
18494
+ false
18495
+ // "updateOrderByKey"
18496
+ );
18497
+ },
18498
+ restoreOrder: (order) => {
18499
+ set(
18500
+ (state) => {
18501
+ state.entry = order;
18502
+ },
18503
+ false
18504
+ // "restoreOrder"
18505
+ );
18506
+ },
18507
+ resetOrder: (_order) => {
18508
+ set(
18509
+ (state) => {
18510
+ state.entry.order_price = "";
18511
+ state.entry.order_quantity = "";
18512
+ state.entry.trigger_price = "";
18513
+ state.entry.total = "";
18514
+ state.entry.tp_trigger_price = "";
18515
+ state.entry.tp_pnl = "";
18516
+ state.entry.tp_offset = "";
18517
+ state.entry.tp_offset_percentage = "";
18518
+ state.entry.sl_trigger_price = "";
18519
+ state.entry.sl_pnl = "";
18520
+ state.entry.sl_offset = "";
18521
+ state.entry.sl_offset_percentage = "";
18522
+ },
18523
+ true
18524
+ // "resetOrder"
18525
+ );
18526
+ }
17820
18527
  }
17821
- };
17822
- };
17823
-
17824
- // src/next/useOrderEntry/useOrderEntry.internal.ts
18528
+ }))
18529
+ );
17825
18530
  var useOrderEntryNextInternal = (symbol, options = {}) => {
17826
18531
  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);
18532
+ const orderEntity = useOrderStore((state) => state.entry);
18533
+ const orderEntryActions = useOrderStore((state) => state.actions);
18534
+ React.useEffect(() => {
18535
+ orderEntryActions.initOrder(symbol, options.initialOrder);
18536
+ if (options.initialOrder) {
18537
+ orderEntryActions.updateOrder(options.initialOrder);
18538
+ }
18539
+ }, [symbol]);
17835
18540
  const calculate2 = React.useCallback(
17836
18541
  (values, fieldName, value, markPrice, config) => {
17837
18542
  const fieldHandler = getCalculateHandler(fieldName);
@@ -17845,17 +18550,15 @@ var useOrderEntryNextInternal = (symbol, options = {}) => {
17845
18550
  },
17846
18551
  []
17847
18552
  );
17848
- React.useEffect(() => {
17849
- orderEntryActions.updateOrderByKey("symbol", symbol);
17850
- }, [orderEntryActions, symbol]);
17851
18553
  const setValue = (key, value, additional) => {
17852
18554
  if (!symbolInfo) {
17853
18555
  orderEntryActions.updateOrderByKey(key, value);
17854
18556
  return;
17855
18557
  }
18558
+ const currentEntry = useOrderStore.getState().entry;
17856
18559
  const { markPrice } = additional ?? { markPrice: 0 };
17857
18560
  let newValues = calculate2(
17858
- { ...orderEntity },
18561
+ { ...currentEntry },
17859
18562
  key,
17860
18563
  value,
17861
18564
  markPrice,
@@ -17936,7 +18639,8 @@ var useOrderEntryNextInternal = (symbol, options = {}) => {
17936
18639
  orderEntryActions.updateOrder(values);
17937
18640
  return;
17938
18641
  }
17939
- let newValues = { ...orderEntity };
18642
+ const currentEntry = useOrderStore.getState().entry;
18643
+ let newValues = { ...currentEntry };
17940
18644
  Object.keys(values).forEach((key) => {
17941
18645
  newValues = calculate2(
17942
18646
  newValues,
@@ -17952,10 +18656,11 @@ var useOrderEntryNextInternal = (symbol, options = {}) => {
17952
18656
  const onMarkPriceUpdated = React.useCallback(
17953
18657
  (markPrice, baseOn = []) => {
17954
18658
  if (!options.symbolInfo) return;
17955
- let newValues = { ...orderEntity };
18659
+ const currentEntry = useOrderStore.getState().entry;
18660
+ let newValues = { ...currentEntry };
17956
18661
  if (baseOn.length === 0) {
17957
18662
  newValues = calculate2(
17958
- { ...orderEntity },
18663
+ { ...currentEntry },
17959
18664
  "order_price",
17960
18665
  markPrice,
17961
18666
  markPrice,
@@ -17966,7 +18671,7 @@ var useOrderEntryNextInternal = (symbol, options = {}) => {
17966
18671
  newValues = calculate2(
17967
18672
  { ...newValues },
17968
18673
  key,
17969
- orderEntity[key],
18674
+ currentEntry[key],
17970
18675
  markPrice,
17971
18676
  options.symbolInfo
17972
18677
  );
@@ -17987,7 +18692,7 @@ var useOrderEntryNextInternal = (symbol, options = {}) => {
17987
18692
  }
17988
18693
  orderEntryActions.updateOrder(newValues);
17989
18694
  },
17990
- [calculate2, options.symbolInfo, orderEntity, orderEntryActions]
18695
+ [calculate2, options.symbolInfo, orderEntryActions]
17991
18696
  );
17992
18697
  const validate = (order, creator, options2) => {
17993
18698
  return creator?.validate(order, {
@@ -18036,6 +18741,7 @@ var useOrderEntry2 = (symbol, options = {}) => {
18036
18741
  const lastChangedField = React.useRef();
18037
18742
  const lastOrderTypeExt = React.useRef();
18038
18743
  const lastLevel = React.useRef();
18744
+ const fundingRates = useFundingRatesStore();
18039
18745
  const calculateTPSL_baseOn = React.useRef({
18040
18746
  tp: "",
18041
18747
  sl: ""
@@ -18044,7 +18750,9 @@ var useOrderEntry2 = (symbol, options = {}) => {
18044
18750
  const symbolConfig = useSymbolsInfo();
18045
18751
  const accountInfo = useAccountInfo();
18046
18752
  const positions3 = usePositions();
18047
- const symbolLeverage = useLeverageBySymbol(symbol);
18753
+ const entry = useOrderStore((s) => s.entry);
18754
+ const effectiveMarginMode = options?.initialOrder?.margin_mode ?? entry?.margin_mode ?? types.MarginMode.CROSS;
18755
+ const symbolLeverage = useLeverageBySymbol(symbol, effectiveMarginMode);
18048
18756
  const symbolInfo = symbolConfig[symbol]();
18049
18757
  const markPrice = actions.getMarkPriceBySymbol(symbol);
18050
18758
  const { orderMetadata } = useOrderlyContext();
@@ -18066,11 +18774,13 @@ var useOrderEntry2 = (symbol, options = {}) => {
18066
18774
  const [doCreateOrder, { isMutating }] = useMutation(
18067
18775
  getCreateOrderUrl(formattedOrder)
18068
18776
  );
18069
- const maxQtyValue = useMaxQty(
18070
- symbol,
18071
- formattedOrder.side,
18072
- formattedOrder.reduce_only
18073
- );
18777
+ const bestAskBid = askAndBid.current?.[0] || [];
18778
+ const referencePriceFromOrder = bestAskBid.length >= 2 && formattedOrder.order_type && formattedOrder.side ? getOrderReferencePriceFromOrder(formattedOrder, bestAskBid) : null;
18779
+ const maxQtyValue = useMaxQty(symbol, formattedOrder.side, {
18780
+ reduceOnly: formattedOrder.reduce_only,
18781
+ marginMode: effectiveMarginMode,
18782
+ currentOrderReferencePrice: referencePriceFromOrder && referencePriceFromOrder > 0 ? referencePriceFromOrder : void 0
18783
+ });
18074
18784
  const maxQty = options.maxQty ?? maxQtyValue;
18075
18785
  const updateOrderPrice = () => {
18076
18786
  const order_type = formattedOrder.order_type;
@@ -18160,6 +18870,9 @@ var useOrderEntry2 = (symbol, options = {}) => {
18160
18870
  };
18161
18871
  }, []);
18162
18872
  React.useEffect(() => {
18873
+ if (formattedOrder.symbol !== symbol) {
18874
+ return;
18875
+ }
18163
18876
  if ((formattedOrder.order_type === types.OrderType.MARKET || formattedOrder.order_type === types.OrderType.STOP_MARKET) && markPrice) {
18164
18877
  const baseOn = /* @__PURE__ */ new Set();
18165
18878
  if (lastChangedField.current) {
@@ -18173,7 +18886,7 @@ var useOrderEntry2 = (symbol, options = {}) => {
18173
18886
  }
18174
18887
  orderEntryActions.onMarkPriceChange(markPrice, Array.from(baseOn));
18175
18888
  }
18176
- }, [markPrice, formattedOrder.order_type]);
18889
+ }, [markPrice, formattedOrder.order_type, formattedOrder.symbol, symbol]);
18177
18890
  const prepareData = React.useCallback(() => {
18178
18891
  return {
18179
18892
  markPrice: actions.getMarkPriceBySymbol(symbol),
@@ -18282,7 +18995,7 @@ var useOrderEntry2 = (symbol, options = {}) => {
18282
18995
  }
18283
18996
  );
18284
18997
  };
18285
- const { freeCollateral, totalCollateral } = useCollateral();
18998
+ const { freeCollateral, freeCollateralUSDCOnly, totalCollateral } = useCollateral();
18286
18999
  const currentPosition = React.useMemo(() => {
18287
19000
  const rows = positions3 ?? [];
18288
19001
  const p = Array.isArray(rows) ? rows.find(
@@ -18295,6 +19008,7 @@ var useOrderEntry2 = (symbol, options = {}) => {
18295
19008
  if (!markPrice2 || !accountInfo || !symbolInfo) {
18296
19009
  return null;
18297
19010
  }
19011
+ const sumUnitaryFunding = fundingRates[symbol]?.sum_unitary_funding ?? 0;
18298
19012
  const estLiqPrice2 = calcEstLiqPrice(formattedOrder, askAndBid.current[0], {
18299
19013
  markPrice: markPrice2,
18300
19014
  totalCollateral,
@@ -18302,7 +19016,9 @@ var useOrderEntry2 = (symbol, options = {}) => {
18302
19016
  imr_factor: accountInfo.imr_factor[symbol],
18303
19017
  symbol,
18304
19018
  positions: positions3,
18305
- symbolInfo
19019
+ symbolInfo,
19020
+ sumUnitaryFunding,
19021
+ symbolLeverage
18306
19022
  });
18307
19023
  return estLiqPrice2;
18308
19024
  }, [
@@ -18312,7 +19028,9 @@ var useOrderEntry2 = (symbol, options = {}) => {
18312
19028
  totalCollateral,
18313
19029
  symbol,
18314
19030
  maxQty,
18315
- symbolInfo
19031
+ symbolInfo,
19032
+ fundingRates,
19033
+ symbolLeverage
18316
19034
  ]);
18317
19035
  const estLiqPriceDistance = React.useMemo(() => {
18318
19036
  if (!estLiqPrice) {
@@ -18447,7 +19165,7 @@ var useOrderEntry2 = (symbol, options = {}) => {
18447
19165
  validator: validateOrder,
18448
19166
  validate: validateOrder
18449
19167
  },
18450
- freeCollateral,
19168
+ freeCollateral: effectiveMarginMode === types.MarginMode.ISOLATED ? freeCollateralUSDCOnly : freeCollateral,
18451
19169
  setValue: useMemoizedFn(setValue),
18452
19170
  setValues: useMemoizedFn(setValues),
18453
19171
  symbolInfo: symbolInfo || types.EMPTY_OBJECT,
@@ -18457,93 +19175,6 @@ var useOrderEntry2 = (symbol, options = {}) => {
18457
19175
  symbolLeverage
18458
19176
  };
18459
19177
  };
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
19178
  var useOrderEntity = (order, options) => {
18548
19179
  const { symbol } = order;
18549
19180
  const { maxQty } = options || {};
@@ -18701,13 +19332,15 @@ var usePositionClose = (options) => {
18701
19332
  symbol,
18702
19333
  order_type: type,
18703
19334
  side,
18704
- reduce_only: true
19335
+ reduce_only: true,
19336
+ // Use position's margin_mode or default to CROSS for backward compatibility
19337
+ margin_mode: position.margin_mode || types.MarginMode.CROSS
18705
19338
  };
18706
19339
  if (type === types.OrderType.LIMIT) {
18707
19340
  data.order_price = price;
18708
19341
  }
18709
19342
  return data;
18710
- }, [symbol, price, type, quantity]);
19343
+ }, [symbol, price, type, quantity, position.margin_mode]);
18711
19344
  const maxQty = React.useMemo(() => {
18712
19345
  if (!position) {
18713
19346
  return 0;
@@ -18909,9 +19542,11 @@ var useTpslPriceChecker = (params) => {
18909
19542
  prevResultRef.current = currentResult;
18910
19543
  return currentResult;
18911
19544
  };
18912
- var useEstLiqPriceBySymbol = (symbol) => {
19545
+ var useEstLiqPriceBySymbol = (symbol, marginMode) => {
18913
19546
  const [data] = usePositionStream(symbol);
18914
- const position = data?.rows?.find((row) => row.symbol === symbol);
19547
+ const position = data?.rows?.find(
19548
+ (row) => row.symbol === symbol && row.margin_mode === marginMode
19549
+ );
18915
19550
  return React.useMemo(() => {
18916
19551
  return position?.est_liq_price ?? void 0;
18917
19552
  }, [position]);
@@ -18932,6 +19567,62 @@ var useGetEstLiqPrice = (props) => {
18932
19567
  return estLiqPrice;
18933
19568
  }, [estLiqPrice, markPrice, side]);
18934
19569
  };
19570
+ var useFeatureFlag = (key) => {
19571
+ const { data: publicFlags, isLoading: publicLoading } = useQuery("/v1/public/feature_flags", {});
19572
+ const publicFlag = React.useMemo(() => {
19573
+ if (!publicFlags || publicLoading) {
19574
+ return void 0;
19575
+ }
19576
+ return publicFlags.find((flag) => flag.key === key);
19577
+ }, [publicFlags, publicLoading, key]);
19578
+ const shouldQueryPrivate = React.useMemo(() => {
19579
+ return publicFlag !== void 0;
19580
+ }, [publicFlag]);
19581
+ const { data: privateFlags, isLoading: privateLoading } = usePrivateQuery(shouldQueryPrivate ? "/v1/feature_flags" : null, {});
19582
+ const privateFlag = React.useMemo(() => {
19583
+ if (!shouldQueryPrivate || !privateFlags || privateLoading) {
19584
+ return void 0;
19585
+ }
19586
+ return privateFlags.find((flag) => flag.key === key);
19587
+ }, [shouldQueryPrivate, privateFlags, privateLoading, key]);
19588
+ return React.useMemo(() => {
19589
+ if (publicLoading || shouldQueryPrivate && privateLoading) {
19590
+ return {
19591
+ enabled: false,
19592
+ data: void 0
19593
+ };
19594
+ }
19595
+ if (publicFlag === void 0) {
19596
+ return {
19597
+ enabled: true,
19598
+ data: void 0
19599
+ };
19600
+ }
19601
+ if (privateFlag === void 0) {
19602
+ return {
19603
+ enabled: false,
19604
+ data: void 0
19605
+ };
19606
+ }
19607
+ return {
19608
+ enabled: true,
19609
+ data: privateFlag
19610
+ };
19611
+ }, [
19612
+ publicFlag,
19613
+ privateFlag,
19614
+ publicLoading,
19615
+ shouldQueryPrivate,
19616
+ privateLoading,
19617
+ key
19618
+ ]);
19619
+ };
19620
+
19621
+ // src/feature-flag/flagKeys.ts
19622
+ var FlagKeys = /* @__PURE__ */ ((FlagKeys2) => {
19623
+ FlagKeys2["IsolatedMargin"] = "isolated-margin";
19624
+ return FlagKeys2;
19625
+ })(FlagKeys || {});
18935
19626
 
18936
19627
  exports.swr = useSWR5__namespace;
18937
19628
  Object.defineProperty(exports, "unstable_serialize", {
@@ -18956,6 +19647,7 @@ exports.ENVType = ENVType2;
18956
19647
  exports.ERROR_MSG_CODES = ERROR_MSG_CODES;
18957
19648
  exports.EpochStatus = EpochStatus;
18958
19649
  exports.ExtendedConfigStore = ExtendedConfigStore;
19650
+ exports.FlagKeys = FlagKeys;
18959
19651
  exports.MaintenanceStatus = MaintenanceStatus;
18960
19652
  exports.MarketsStorageKey = MarketsStorageKey;
18961
19653
  exports.MarketsType = MarketsType;
@@ -19013,6 +19705,7 @@ exports.useDistributionHistory = useDistributionHistory;
19013
19705
  exports.useEpochInfo = useEpochInfo;
19014
19706
  exports.useEstLiqPriceBySymbol = useEstLiqPriceBySymbol;
19015
19707
  exports.useEventEmitter = useEventEmitter;
19708
+ exports.useFeatureFlag = useFeatureFlag;
19016
19709
  exports.useFeeState = useFeeState;
19017
19710
  exports.useFundingDetails = useFundingDetails;
19018
19711
  exports.useFundingFeeHistory = useFundingFeeHistory;
@@ -19043,6 +19736,8 @@ exports.useLocalStorage = useLocalStorage;
19043
19736
  exports.useMainTokenStore = useMainTokenStore;
19044
19737
  exports.useMainnetChainsStore = useMainnetChainsStore;
19045
19738
  exports.useMaintenanceStatus = useMaintenanceStatus;
19739
+ exports.useMarginModeBySymbol = useMarginModeBySymbol;
19740
+ exports.useMarginModes = useMarginModes;
19046
19741
  exports.useMarginRatio = useMarginRatio;
19047
19742
  exports.useMarkPrice = useMarkPrice;
19048
19743
  exports.useMarkPriceBySymbol = useMarkPriceBySymbol;
@@ -19065,7 +19760,7 @@ exports.useOdosQuote = useOdosQuote;
19065
19760
  exports.useOrderEntity = useOrderEntity;
19066
19761
  exports.useOrderEntry = useOrderEntry2;
19067
19762
  exports.useOrderEntry_deprecated = useOrderEntry;
19068
- exports.useOrderStore = useOrderStore2;
19763
+ exports.useOrderStore = useOrderStore;
19069
19764
  exports.useOrderStream = useOrderStream;
19070
19765
  exports.useOrderbookStream = useOrderbookStream;
19071
19766
  exports.useOrderlyContext = useOrderlyContext;
@@ -19073,6 +19768,7 @@ exports.usePortfolio = usePortfolio;
19073
19768
  exports.usePositionActions = usePositionActions;
19074
19769
  exports.usePositionClose = usePositionClose;
19075
19770
  exports.usePositionStream = usePositionStream;
19771
+ exports.usePositions = usePositions;
19076
19772
  exports.usePoster = usePoster;
19077
19773
  exports.usePreLoadData = usePreLoadData;
19078
19774
  exports.usePrivateDataObserver = usePrivateDataObserver;
@@ -19102,6 +19798,7 @@ exports.useSubAccountWS = useSubAccountWS;
19102
19798
  exports.useSwapSupportStore = useSwapSupportStore;
19103
19799
  exports.useSymbolInfo = useSymbolInfo;
19104
19800
  exports.useSymbolLeverage = useSymbolLeverage;
19801
+ exports.useSymbolLeverageMap = useSymbolLeverageMap;
19105
19802
  exports.useSymbolPriceRange = useSymbolPriceRange;
19106
19803
  exports.useSymbolsInfo = useSymbolsInfo;
19107
19804
  exports.useSymbolsInfoStore = useSymbolsInfoStore;