@orderly.network/hooks 2.10.2 → 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.mjs CHANGED
@@ -3,7 +3,7 @@ import useSWR5__default, { mutate } from 'swr';
3
3
  import * as useSWR5 from 'swr';
4
4
  export { useSWR5 as swr };
5
5
  export { unstable_serialize, default as useSWR, useSWRConfig } from 'swr';
6
- import { TesnetTokenFallback, ArbitrumSepoliaTokenInfo, SolanaDevnetTokenInfo, OrderType, OrderSide, SDKError, TrackerEventName, AccountStatusEnum, AlgoOrderType, AlgoOrderRootType, OrderStatus, ArbitrumSepoliaChainInfo, SolanaDevnetChainInfo, EMPTY_LIST, EMPTY_OBJECT, isNativeTokenChecker, nativeTokenAddress, ChainKey, chainsInfoMap, ARBITRUM_TESTNET_CHAINID, ARBITRUM_MAINNET_CHAINID, ChainNamespace, MaxUint256, DEPOSIT_FEE_RATE, ETHEREUM_MAINNET_CHAINID, LedgerWalletKey, SOLANA_TESTNET_CHAINID, MONAD_TESTNET_CHAINID, ABSTRACT_TESTNET_CHAINID, BSC_TESTNET_CHAINID, SolanaChains, PositionType, DistributionType, TriggerPriceType } from '@orderly.network/types';
6
+ import { TesnetTokenFallback, ArbitrumSepoliaTokenInfo, SolanaDevnetTokenInfo, OrderType, OrderSide, MarginMode, SDKError, TrackerEventName, AccountStatusEnum, AlgoOrderType, AlgoOrderRootType, OrderStatus, ArbitrumSepoliaChainInfo, SolanaDevnetChainInfo, EMPTY_LIST, EMPTY_OBJECT, isNativeTokenChecker, nativeTokenAddress, ChainKey, chainsInfoMap, ARBITRUM_TESTNET_CHAINID, ARBITRUM_MAINNET_CHAINID, ChainNamespace, MaxUint256, DEPOSIT_FEE_RATE, ETHEREUM_MAINNET_CHAINID, LedgerWalletKey, SOLANA_TESTNET_CHAINID, MONAD_TESTNET_CHAINID, ABSTRACT_TESTNET_CHAINID, BSC_TESTNET_CHAINID, SolanaChains, PositionType, DistributionType, TriggerPriceType } from '@orderly.network/types';
7
7
  import React, { createContext, useContext, useCallback, useState, useEffect, useMemo, useRef, useId, useLayoutEffect } from 'react';
8
8
  import { zero, windowGuard, getTimestamp, getGlobalObject, Decimal, timeConvertString, isTestnet, getPrecisionByNumber, getBBOType, camelCaseToUnderscoreCase, commify, todpIfNeed, getTPSLDirection } from '@orderly.network/utils';
9
9
  import useSWRMutation from 'swr/mutation';
@@ -38,9 +38,9 @@ var __export = (target, all) => {
38
38
  // src/version.ts
39
39
  if (typeof window !== "undefined") {
40
40
  window.__ORDERLY_VERSION__ = window.__ORDERLY_VERSION__ || {};
41
- window.__ORDERLY_VERSION__["@orderly.network/hooks"] = "2.10.2";
41
+ window.__ORDERLY_VERSION__["@orderly.network/hooks"] = "2.11.0-alpha.0";
42
42
  }
43
- var version_default = "2.10.2";
43
+ var version_default = "2.11.0-alpha.0";
44
44
  var fetcher = (url, init2 = {}, queryOptions) => get(url, init2, queryOptions?.formatter);
45
45
  var noCacheConfig = {
46
46
  dedupingInterval: 0,
@@ -1084,12 +1084,12 @@ var findTPSLOrderPriceFromOrder = (order) => {
1084
1084
  sl_order_price
1085
1085
  };
1086
1086
  };
1087
- var findPositionTPSLFromOrders = (orders, symbol) => {
1087
+ var findPositionTPSLFromOrders = (orders, symbol, marginMode = MarginMode.CROSS) => {
1088
1088
  const fullPositionOrder = orders?.find((order) => {
1089
- return order.symbol === symbol && order.algo_type === AlgoOrderRootType.POSITIONAL_TP_SL && (order.root_algo_status === OrderStatus.NEW || order.root_algo_status === OrderStatus.REPLACED || order.root_algo_status === OrderStatus.PARTIAL_FILLED);
1089
+ return order.symbol === symbol && order.algo_type === AlgoOrderRootType.POSITIONAL_TP_SL && order.margin_mode === marginMode && (order.root_algo_status === OrderStatus.NEW || order.root_algo_status === OrderStatus.REPLACED || order.root_algo_status === OrderStatus.PARTIAL_FILLED);
1090
1090
  });
1091
1091
  const partialPositionOrders = orders?.filter((order) => {
1092
- return order.symbol === symbol && order.algo_type === AlgoOrderRootType.TP_SL && (order.root_algo_status === OrderStatus.NEW || order.root_algo_status === OrderStatus.REPLACED || order.root_algo_status === OrderStatus.PARTIAL_FILLED);
1092
+ return order.symbol === symbol && order.margin_mode === marginMode && order.algo_type === AlgoOrderRootType.TP_SL && (order.root_algo_status === OrderStatus.NEW || order.root_algo_status === OrderStatus.REPLACED || order.root_algo_status === OrderStatus.PARTIAL_FILLED);
1093
1093
  }).sort((a, b) => {
1094
1094
  return b.created_time - a.created_time;
1095
1095
  });
@@ -2114,9 +2114,11 @@ var useAppStore = create()(
2114
2114
  totalCollateral: zero,
2115
2115
  totalValue: null,
2116
2116
  freeCollateral: zero,
2117
+ freeCollateralUSDCOnly: zero,
2117
2118
  availableBalance: 0,
2118
2119
  unsettledPnL: 0,
2119
- totalUnrealizedROI: 0
2120
+ totalUnrealizedROI: 0,
2121
+ usdcHolding: 0
2120
2122
  },
2121
2123
  appState: {
2122
2124
  positionsLoading: false,
@@ -2137,9 +2139,11 @@ var useAppStore = create()(
2137
2139
  totalCollateral: zero,
2138
2140
  totalValue: null,
2139
2141
  freeCollateral: zero,
2142
+ freeCollateralUSDCOnly: zero,
2140
2143
  availableBalance: 0,
2141
2144
  unsettledPnL: 0,
2142
- totalUnrealizedROI: 0
2145
+ totalUnrealizedROI: 0,
2146
+ usdcHolding: 0
2143
2147
  };
2144
2148
  }, false);
2145
2149
  },
@@ -3935,25 +3939,27 @@ var OrderbookService = class _OrderbookService {
3935
3939
  };
3936
3940
  var orderBookService = OrderbookService.getInstance();
3937
3941
  var orderbook_service_default = orderBookService;
3942
+ var useMarkPriceStore = create((set, get3) => ({
3943
+ markPrices: {},
3944
+ // orderBook: {},
3945
+ // ask_bid: [],
3946
+ actions: {
3947
+ updateMarkPrice: (markPrice) => {
3948
+ set({
3949
+ markPrices: markPrice
3950
+ });
3951
+ },
3952
+ getMarkPriceBySymbol: (symbol) => {
3953
+ return get3().markPrices[symbol];
3954
+ }
3955
+ }
3956
+ }));
3957
+ var useMarkPriceBySymbol = (symbol) => useMarkPriceStore((state) => state.actions.getMarkPriceBySymbol(symbol));
3958
+ var useMarkPriceActions = () => useMarkPriceStore((state) => state.actions);
3959
+
3960
+ // src/orderly/useMarkPrice.ts
3938
3961
  var useMarkPrice = (symbol) => {
3939
- const ws = useWS();
3940
- const [price, setPrice] = useState(0);
3941
- const symbolRef = useRef(symbol);
3942
- symbolRef.current = symbol;
3943
- useEffect(() => {
3944
- const unsubscribe = ws.subscribe(`${symbol}@markprice`, {
3945
- onMessage: (message) => {
3946
- if (message.symbol !== symbolRef.current) {
3947
- unsubscribe?.();
3948
- return;
3949
- }
3950
- setPrice(message.price);
3951
- }
3952
- });
3953
- return () => {
3954
- unsubscribe?.();
3955
- };
3956
- }, [symbol]);
3962
+ const price = useMarkPriceBySymbol(symbol);
3957
3963
  return { data: price };
3958
3964
  };
3959
3965
  var useIndexPrice = (symbol) => {
@@ -3976,6 +3982,12 @@ var useIndexPrice = (symbol) => {
3976
3982
  };
3977
3983
  });
3978
3984
  };
3985
+
3986
+ // src/orderly/useMarkPricesStream.ts
3987
+ var useMarkPricesStream = () => {
3988
+ const data = useMarkPriceStore((state) => state.markPrices);
3989
+ return { data };
3990
+ };
3979
3991
  var useOpenInterest = (symbol) => {
3980
3992
  const ws = useWS();
3981
3993
  const symbolRef = useRef(symbol);
@@ -3995,29 +4007,6 @@ var useOpenInterest = (symbol) => {
3995
4007
  };
3996
4008
  });
3997
4009
  };
3998
- var useMarkPriceStore = create((set, get3) => ({
3999
- markPrices: {},
4000
- // orderBook: {},
4001
- // ask_bid: [],
4002
- actions: {
4003
- updateMarkPrice: (markPrice) => {
4004
- set({
4005
- markPrices: markPrice
4006
- });
4007
- },
4008
- getMarkPriceBySymbol: (symbol) => {
4009
- return get3().markPrices[symbol];
4010
- }
4011
- }
4012
- }));
4013
- var useMarkPriceBySymbol = (symbol) => useMarkPriceStore((state) => state.actions.getMarkPriceBySymbol(symbol));
4014
- var useMarkPriceActions = () => useMarkPriceStore((state) => state.actions);
4015
-
4016
- // src/orderly/useMarkPricesStream.ts
4017
- var useMarkPricesStream = () => {
4018
- const data = useMarkPriceStore((state) => state.markPrices);
4019
- return { data };
4020
- };
4021
4010
 
4022
4011
  // src/orderly/useTickerStream.ts
4023
4012
  var useTickerStream = (symbol) => {
@@ -4710,6 +4699,94 @@ var useLeverage = () => {
4710
4699
  maxLeverage: memoizedMaxLeverage
4711
4700
  };
4712
4701
  };
4702
+ var buildKey = (symbol, marginMode) => `${symbol}_${marginMode ?? MarginMode.CROSS}`;
4703
+ var useSymbolLeverageMap = () => {
4704
+ const { data, error, isLoading, mutate: mutate6 } = usePrivateQuery("/v1/client/leverages", {
4705
+ revalidateOnFocus: false,
4706
+ revalidateOnReconnect: false,
4707
+ errorRetryCount: 1
4708
+ });
4709
+ const leverages = useMemo(() => {
4710
+ if (!data || !Array.isArray(data)) return {};
4711
+ const map = {};
4712
+ for (const item of data) {
4713
+ const key = buildKey(item.symbol, item.margin_mode);
4714
+ map[key] = item.leverage;
4715
+ }
4716
+ return map;
4717
+ }, [data]);
4718
+ const getSymbolLeverage = (symbol, marginMode) => {
4719
+ if (!symbol) return void 0;
4720
+ const key = buildKey(symbol, marginMode);
4721
+ return leverages[key];
4722
+ };
4723
+ return {
4724
+ leverages,
4725
+ getSymbolLeverage,
4726
+ isLoading,
4727
+ error,
4728
+ refresh: mutate6
4729
+ };
4730
+ };
4731
+ var useMarginModes = () => {
4732
+ const { data, error, isLoading, mutate: mutate6 } = usePrivateQuery("/v1/client/margin_modes", {
4733
+ revalidateOnFocus: false,
4734
+ revalidateOnMount: true
4735
+ });
4736
+ const [setMarginModeInternal, { isMutating }] = useMutation(
4737
+ "/v1/client/margin_mode",
4738
+ "POST"
4739
+ );
4740
+ const marginModes = useMemo(() => {
4741
+ if (!data || !Array.isArray(data)) return {};
4742
+ const map = {};
4743
+ for (const item of data) {
4744
+ map[item.symbol] = item.default_margin_mode;
4745
+ }
4746
+ return map;
4747
+ }, [data]);
4748
+ const setMarginMode = (payload) => setMarginModeInternal(payload);
4749
+ const updateMarginMode = useCallback(
4750
+ async (payload) => {
4751
+ const result = await setMarginMode(payload);
4752
+ if (result.success) {
4753
+ await mutate6();
4754
+ return result;
4755
+ }
4756
+ throw new Error(result.message ?? "Failed to update margin mode");
4757
+ },
4758
+ [setMarginMode, mutate6]
4759
+ );
4760
+ return {
4761
+ marginModes,
4762
+ isLoading,
4763
+ error,
4764
+ refresh: mutate6,
4765
+ setMarginMode,
4766
+ updateMarginMode,
4767
+ isMutating
4768
+ };
4769
+ };
4770
+ var useMarginModeBySymbol = (symbol, fallback = MarginMode.CROSS) => {
4771
+ const { marginModes, isLoading, error, refresh, updateMarginMode } = useMarginModes();
4772
+ const marginMode = fallback === null ? marginModes[symbol] : marginModes[symbol] ?? fallback;
4773
+ const update = useCallback(
4774
+ async (mode) => {
4775
+ return updateMarginMode({
4776
+ symbol_list: [symbol],
4777
+ default_margin_mode: mode
4778
+ });
4779
+ },
4780
+ [symbol, updateMarginMode]
4781
+ );
4782
+ return {
4783
+ marginMode,
4784
+ isLoading,
4785
+ error,
4786
+ refresh,
4787
+ update
4788
+ };
4789
+ };
4713
4790
 
4714
4791
  // src/orderly/useOdosQuote.ts
4715
4792
  var useOdosQuote = () => {
@@ -5067,10 +5144,13 @@ var CalculatorService = class {
5067
5144
  // this.pendingCalc = [];
5068
5145
  // }
5069
5146
  async handleCalcQueue(context) {
5070
- const first = this.calcQueue.shift();
5071
- if (first) {
5147
+ const batchCollector = /* @__PURE__ */ new Map();
5148
+ let currentContext = context;
5149
+ while (this.calcQueue.length > 0) {
5150
+ const first = this.calcQueue.shift();
5151
+ if (!first) break;
5072
5152
  const { scope, data, options } = first;
5073
- const ctx = context || CalculatorContext.create(scope, data);
5153
+ const ctx = currentContext || CalculatorContext.create(scope, data);
5074
5154
  const calculators = this.calculators.get(scope);
5075
5155
  if (Array.isArray(calculators) && calculators.length) {
5076
5156
  try {
@@ -5078,13 +5158,46 @@ var CalculatorService = class {
5078
5158
  } catch (e) {
5079
5159
  }
5080
5160
  if (!options?.skipUpdate) {
5081
- this.scheduler.update(scope, calculators, ctx.outputToValue());
5161
+ this.collectUpdates(
5162
+ batchCollector,
5163
+ scope,
5164
+ calculators,
5165
+ ctx.outputToValue()
5166
+ );
5082
5167
  }
5083
5168
  }
5084
- if (this.calcQueue.length) {
5085
- this.handleCalcQueue(ctx);
5169
+ currentContext = ctx;
5170
+ }
5171
+ await this.commitBatchUpdates(batchCollector);
5172
+ this.ctx = currentContext;
5173
+ }
5174
+ collectUpdates(collector, scope, calculators, data) {
5175
+ if (!collector.has(scope)) {
5176
+ collector.set(scope, /* @__PURE__ */ new Map());
5177
+ }
5178
+ const scopeCollector = collector.get(scope);
5179
+ for (const calculator of calculators) {
5180
+ const item = data[calculator.name];
5181
+ if (item !== void 0 && item !== null) {
5182
+ scopeCollector.set(calculator.name, item);
5183
+ }
5184
+ }
5185
+ }
5186
+ async commitBatchUpdates(collector) {
5187
+ if (collector.size === 0) return;
5188
+ for (const [scope, updateMap] of collector.entries()) {
5189
+ const calculators = this.calculators.get(scope);
5190
+ if (!Array.isArray(calculators)) continue;
5191
+ const batchData = {};
5192
+ for (const [calculatorName, data] of updateMap.entries()) {
5193
+ batchData[calculatorName] = data;
5194
+ }
5195
+ try {
5196
+ this.scheduler.update(scope, calculators, batchData);
5197
+ } catch (e) {
5086
5198
  }
5087
5199
  }
5200
+ collector.clear();
5088
5201
  }
5089
5202
  stop() {
5090
5203
  this.calcQueue = [];
@@ -5115,6 +5228,18 @@ var cancelIdleCallbackPolyfill = (id) => {
5115
5228
  var safeRequestIdleCallback = typeof window !== "undefined" && window.requestIdleCallback ? window.requestIdleCallback.bind(window) : requestIdleCallbackPolyfill;
5116
5229
  typeof window !== "undefined" && window.cancelIdleCallback ? window.cancelIdleCallback.bind(window) : cancelIdleCallbackPolyfill;
5117
5230
  var ShardingScheduler = class {
5231
+ constructor() {
5232
+ /**
5233
+ * Maximum continuous execution time per frame (in milliseconds)
5234
+ * Prevents blocking the main thread for too long
5235
+ */
5236
+ this.MAX_CONTINUOUS_MS = 5;
5237
+ /**
5238
+ * Minimum remaining idle time threshold (in milliseconds)
5239
+ * Ensures the browser has enough idle time for other tasks
5240
+ */
5241
+ this.MIN_IDLE_REMAINING = 2;
5242
+ }
5118
5243
  // run(calculators: Calculator[]) {}
5119
5244
  calc(scope, calculators, data, ctx) {
5120
5245
  return new Promise((resolve, reject) => {
@@ -5155,28 +5280,27 @@ var ShardingScheduler = class {
5155
5280
  computation(data, processor, onComplete) {
5156
5281
  let index = 0;
5157
5282
  const results = [];
5158
- const estimatedShardSize = Math.min(data.length, 2);
5159
- function processNextShard(deadline) {
5160
- let shardSize = estimatedShardSize;
5161
- while (index + shardSize <= data.length && deadline.timeRemaining() > 0) {
5162
- const shard = data.slice(index, index + shardSize);
5163
- const result = processor(shard);
5164
- results.push(result);
5165
- index += shardSize;
5166
- if (deadline.timeRemaining() < 1) {
5167
- shardSize = Math.max(1, Math.floor(shardSize / 2));
5168
- } else {
5169
- shardSize = Math.min(data.length - index, shardSize * 2);
5283
+ const MAX_CONTINUOUS_MS = this.MAX_CONTINUOUS_MS;
5284
+ const MIN_IDLE_REMAINING = this.MIN_IDLE_REMAINING;
5285
+ const processNextShard = (deadline) => {
5286
+ const frameStart = performance.now();
5287
+ while (index < data.length) {
5288
+ const elapsed = performance.now() - frameStart;
5289
+ const remaining = deadline.timeRemaining();
5290
+ if (elapsed > MAX_CONTINUOUS_MS || remaining < MIN_IDLE_REMAINING) {
5291
+ safeRequestIdleCallback(processNextShard, {
5292
+ timeout: 1e3
5293
+ });
5294
+ return;
5170
5295
  }
5296
+ const result = processor([data[index]]);
5297
+ if (result && result.length > 0) {
5298
+ results.push(...result);
5299
+ }
5300
+ index++;
5171
5301
  }
5172
- if (index < data.length) {
5173
- safeRequestIdleCallback(processNextShard, {
5174
- timeout: 1e3
5175
- });
5176
- } else {
5177
- onComplete(results.flat());
5178
- }
5179
- }
5302
+ onComplete(results);
5303
+ };
5180
5304
  safeRequestIdleCallback(processNextShard, {
5181
5305
  timeout: 1e3
5182
5306
  });
@@ -5389,21 +5513,38 @@ var PositionCalculator = class extends BaseCalculator {
5389
5513
  const unsettlementPnL = unsettlementPnL_total.toNumber();
5390
5514
  let totalUnrealizedROI = 0, totalUnrealizedROI_index = 0;
5391
5515
  if (portfolio) {
5392
- const { totalValue, totalCollateral } = portfolio;
5516
+ const { totalValue, totalCollateral: crossMarginCollateral } = portfolio;
5393
5517
  rows = rows.map((item) => {
5394
5518
  const info = symbolsInfo[item.symbol];
5395
- const est_liq_price = positions.liqPrice({
5396
- symbol: item.symbol,
5397
- markPrice: item.mark_price,
5398
- totalCollateral: totalCollateral.toNumber(),
5399
- positionQty: item.position_qty,
5400
- positions: rows,
5401
- MMR: item.mmr,
5402
- baseMMR: info?.["base_mmr"],
5403
- baseIMR: info?.["base_imr"],
5404
- IMRFactor: accountInfo.imr_factor[item.symbol],
5405
- costPosition: item.cost_position
5406
- });
5519
+ const totalCollateral = item.margin_mode === MarginMode.ISOLATED ? new Decimal(item.margin ?? 0).add(item.unsettlement_pnl ?? 0).toNumber() : crossMarginCollateral.toNumber();
5520
+ let est_liq_price;
5521
+ if (item.margin_mode === MarginMode.ISOLATED) {
5522
+ est_liq_price = positions.liquidationPriceIsolated({
5523
+ isolatedPositionMargin: item.margin ?? 0,
5524
+ costPosition: item.cost_position ?? 0,
5525
+ positionQty: item.position_qty ?? 0,
5526
+ sumUnitaryFunding: fundingRates?.[item.symbol]?.["sum_unitary_funding"] ?? 0,
5527
+ lastSumUnitaryFunding: item.last_sum_unitary_funding ?? 0,
5528
+ baseMMR: info?.["base_mmr"] ?? 0,
5529
+ baseIMR: info?.["base_imr"] ?? 0,
5530
+ IMRFactor: accountInfo.imr_factor[item.symbol],
5531
+ referencePrice: item.mark_price,
5532
+ leverage: item.leverage ?? 0
5533
+ });
5534
+ } else {
5535
+ est_liq_price = positions.liqPrice({
5536
+ symbol: item.symbol,
5537
+ markPrice: item.mark_price,
5538
+ totalCollateral,
5539
+ positionQty: item.position_qty,
5540
+ positions: rows,
5541
+ MMR: item.mmr,
5542
+ baseMMR: info?.["base_mmr"],
5543
+ baseIMR: info?.["base_imr"],
5544
+ IMRFactor: accountInfo.imr_factor[item.symbol],
5545
+ costPosition: item.cost_position
5546
+ });
5547
+ }
5407
5548
  return {
5408
5549
  ...item,
5409
5550
  est_liq_price
@@ -5554,7 +5695,9 @@ var PortfolioCalculator = class extends BaseCalculator {
5554
5695
  return {
5555
5696
  ...item,
5556
5697
  holding: data.holding[item.token].holding,
5557
- frozen: data.holding[item.token].frozen
5698
+ frozen: data.holding[item.token].frozen,
5699
+ isolatedMargin: data.holding[item.token].isolatedMargin,
5700
+ isolatedOrderFrozen: data.holding[item.token].isolatedOrderFrozen
5558
5701
  };
5559
5702
  }
5560
5703
  return item;
@@ -5590,7 +5733,14 @@ var PortfolioCalculator = class extends BaseCalculator {
5590
5733
  if (!holding || !positions3 || !Array.isArray(positions3.rows) || !markPrices || !indexPrices || !accountInfo) {
5591
5734
  return null;
5592
5735
  }
5593
- const unsettledPnL = pathOr(0, ["total_unsettled_pnl"])(positions3);
5736
+ const totallCrossUnsettledPnL = positions3.rows.reduce(
5737
+ (sum, pos) => pos.margin_mode === MarginMode.ISOLATED ? sum : sum + (pos.unsettled_pnl ?? 0),
5738
+ 0
5739
+ );
5740
+ const totalUnsettlementPnL = positions3.rows.reduce(
5741
+ (sum, pos) => sum + (pos.unsettled_pnl ?? 0),
5742
+ 0
5743
+ );
5594
5744
  const unrealizedPnL = pathOr(0, ["total_unreal_pnl"])(positions3);
5595
5745
  const [USDC_holding, nonUSDC] = parseHolding(
5596
5746
  holding,
@@ -5601,28 +5751,51 @@ var PortfolioCalculator = class extends BaseCalculator {
5601
5751
  const totalCollateral = account.totalCollateral({
5602
5752
  USDCHolding: USDC_holding,
5603
5753
  nonUSDCHolding: nonUSDC,
5604
- unsettlementPnL: unsettledPnL
5754
+ unsettlementPnL: totallCrossUnsettledPnL,
5755
+ usdcBalancePendingShortQty: usdc?.pending_short ?? 0,
5756
+ usdcBalanceIsolatedOrderFrozen: usdc?.isolated_order_frozen ?? 0
5605
5757
  });
5758
+ const sumIsolatedMargin = positions3.rows.reduce((acc, curr) => {
5759
+ if (curr.margin_mode !== MarginMode.ISOLATED) {
5760
+ return acc;
5761
+ }
5762
+ return acc.add(curr.margin ?? 0);
5763
+ }, zero);
5606
5764
  const totalValue = account.totalValue({
5607
- totalUnsettlementPnL: unsettledPnL,
5765
+ totalUnsettlementPnL,
5608
5766
  USDCHolding: USDC_holding,
5609
- nonUSDCHolding: nonUSDC
5767
+ nonUSDCHolding: nonUSDC,
5768
+ totalIsolatedPositionMargin: sumIsolatedMargin.toNumber()
5610
5769
  });
5611
5770
  const totalUnrealizedROI = account.totalUnrealizedROI({
5612
5771
  totalUnrealizedPnL: unrealizedPnL,
5613
5772
  totalValue: totalValue.toNumber()
5614
5773
  });
5774
+ const maxLeverageBySymbol = positions3.rows.reduce(
5775
+ (acc, position) => {
5776
+ if (position.margin_mode !== MarginMode.ISOLATED && position.leverage && !acc[position.symbol]) {
5777
+ acc[position.symbol] = position.leverage;
5778
+ }
5779
+ return acc;
5780
+ },
5781
+ {}
5782
+ );
5615
5783
  const totalInitialMarginWithOrders = account.totalInitialMarginWithQty({
5616
5784
  positions: positions3.rows,
5785
+ orders: [],
5617
5786
  markPrices,
5618
5787
  IMR_Factors: accountInfo.imr_factor,
5619
- maxLeverage: accountInfo.max_leverage,
5788
+ maxLeverageBySymbol,
5620
5789
  symbolInfo: createGetter({ ...symbolsInfo })
5621
5790
  });
5622
5791
  const freeCollateral = account.freeCollateral({
5623
5792
  totalCollateral,
5624
5793
  totalInitialMarginWithOrders
5625
5794
  });
5795
+ const freeCollateralUSDCOnly = account.freeCollateralUSDCOnly({
5796
+ freeCollateral,
5797
+ nonUSDCHolding: nonUSDC
5798
+ });
5626
5799
  const availableBalance = account.availableBalance({
5627
5800
  USDCHolding: usdc?.holding ?? 0,
5628
5801
  unsettlementPnL: positions3.total_unsettled_pnl ?? 0
@@ -5633,8 +5806,10 @@ var PortfolioCalculator = class extends BaseCalculator {
5633
5806
  totalUnrealizedROI,
5634
5807
  freeCollateral,
5635
5808
  availableBalance,
5636
- unsettledPnL,
5637
- holding
5809
+ unsettledPnL: totalUnsettlementPnL,
5810
+ holding,
5811
+ usdcHolding: USDC_holding,
5812
+ freeCollateralUSDCOnly
5638
5813
  };
5639
5814
  }
5640
5815
  update(data, scope) {
@@ -5643,10 +5818,12 @@ var PortfolioCalculator = class extends BaseCalculator {
5643
5818
  totalCollateral: data.totalCollateral,
5644
5819
  totalValue: data.totalValue,
5645
5820
  freeCollateral: data.freeCollateral,
5821
+ freeCollateralUSDCOnly: data.freeCollateralUSDCOnly,
5646
5822
  availableBalance: data.availableBalance,
5647
5823
  totalUnrealizedROI: data.totalUnrealizedROI,
5648
5824
  unsettledPnL: data.unsettledPnL,
5649
- holding: Array.isArray(data.holding) ? data.holding : []
5825
+ holding: Array.isArray(data.holding) ? data.holding : [],
5826
+ usdcHolding: typeof data.usdcHolding === "number" ? data.usdcHolding : data.usdcHolding.toNumber()
5650
5827
  });
5651
5828
  }
5652
5829
  }
@@ -5777,7 +5954,7 @@ var usePositionStream = (symbol = "all", options) => {
5777
5954
  }
5778
5955
  if (Array.isArray(tpslOrders) && tpslOrders.length) {
5779
5956
  rows = rows.map((item) => {
5780
- const { fullPositionOrder, partialPositionOrders } = findPositionTPSLFromOrders(tpslOrders, item.symbol);
5957
+ const { fullPositionOrder, partialPositionOrders } = findPositionTPSLFromOrders(tpslOrders, item.symbol, item.margin_mode);
5781
5958
  const full_tp_sl = fullPositionOrder ? findTPSLFromOrder(fullPositionOrder) : void 0;
5782
5959
  const partialPossitionOrder = partialPositionOrders && partialPositionOrders.length ? partialPositionOrders[0] : void 0;
5783
5960
  const partial_tp_sl = partialPossitionOrder ? findTPSLFromOrder(partialPossitionOrder) : void 0;
@@ -5909,15 +6086,21 @@ var useOrderStream = (params, options) => {
5909
6086
  }
5910
6087
  };
5911
6088
  }, [normalOrderKeyFn, options?.keeplive]);
5912
- const normalOrdersResponse = usePrivateInfiniteQuery(normalOrderKeyFn, {
5913
- initialSize: 1,
5914
- formatter: (data) => data,
5915
- revalidateOnFocus: false
5916
- });
5917
- const algoOrdersResponse = usePrivateInfiniteQuery(algoOrderKeyFn, {
5918
- formatter: (data) => data,
5919
- revalidateOnFocus: false
5920
- });
6089
+ const normalOrdersResponse = usePrivateInfiniteQuery(
6090
+ normalOrderKeyFn,
6091
+ {
6092
+ initialSize: 1,
6093
+ formatter: (data) => data,
6094
+ revalidateOnFocus: false
6095
+ }
6096
+ );
6097
+ const algoOrdersResponse = usePrivateInfiniteQuery(
6098
+ algoOrderKeyFn,
6099
+ {
6100
+ formatter: (data) => data,
6101
+ revalidateOnFocus: false
6102
+ }
6103
+ );
5921
6104
  const flattenOrders = useMemo(() => {
5922
6105
  if (!normalOrdersResponse.data || !algoOrdersResponse.data && !sourceTypeAll) {
5923
6106
  return null;
@@ -6035,7 +6218,9 @@ var useOrderStream = (params, options) => {
6035
6218
  // trailing stop order fields
6036
6219
  activated_price: order.activated_price,
6037
6220
  callback_value: order.callback_value,
6038
- callback_rate: order.callback_rate
6221
+ callback_rate: order.callback_rate,
6222
+ // Include margin_mode if present
6223
+ ...order.margin_mode && { margin_mode: order.margin_mode }
6039
6224
  });
6040
6225
  default:
6041
6226
  return doUpdateOrder({ ...order, order_id: orderId });
@@ -6230,7 +6415,14 @@ function formatPortfolio(inputs) {
6230
6415
  if (!holding || !positions3 || !Array.isArray(positions3.rows) || !markPrices || !indexPrices || !accountInfo || symbolsInfo?.isNil) {
6231
6416
  return null;
6232
6417
  }
6233
- const unsettledPnL = pathOr(0, ["total_unsettled_pnl"])(positions3);
6418
+ const totallCrossUnsettledPnL = positions3.rows.reduce(
6419
+ (sum, pos) => pos.margin_mode === MarginMode.ISOLATED ? sum : sum + (pos.unsettled_pnl ?? 0),
6420
+ 0
6421
+ );
6422
+ const totalUnsettlementPnL = positions3.rows.reduce(
6423
+ (sum, pos) => sum + (pos.unsettled_pnl ?? 0),
6424
+ 0
6425
+ );
6234
6426
  const unrealizedPnL = pathOr(0, ["total_unreal_pnl"])(positions3);
6235
6427
  const [USDC_holding, nonUSDC] = parseHolding(
6236
6428
  holding,
@@ -6241,29 +6433,51 @@ function formatPortfolio(inputs) {
6241
6433
  const totalCollateral = account.totalCollateral({
6242
6434
  USDCHolding: USDC_holding,
6243
6435
  nonUSDCHolding: nonUSDC,
6244
- unsettlementPnL: unsettledPnL
6436
+ unsettlementPnL: totallCrossUnsettledPnL,
6437
+ usdcBalancePendingShortQty: usdc?.pending_short ?? 0,
6438
+ usdcBalanceIsolatedOrderFrozen: usdc?.isolated_order_frozen ?? 0
6245
6439
  });
6440
+ const sumIsolatedMargin = positions3.rows.reduce((acc, curr) => {
6441
+ if (curr.margin_mode !== MarginMode.ISOLATED) {
6442
+ return acc;
6443
+ }
6444
+ return acc.add(curr.margin ?? 0);
6445
+ }, zero);
6246
6446
  const totalValue = account.totalValue({
6247
- totalUnsettlementPnL: unsettledPnL,
6447
+ totalUnsettlementPnL,
6248
6448
  USDCHolding: USDC_holding,
6249
- nonUSDCHolding: nonUSDC
6449
+ nonUSDCHolding: nonUSDC,
6450
+ totalIsolatedPositionMargin: sumIsolatedMargin.toNumber()
6250
6451
  });
6251
6452
  const totalUnrealizedROI = account.totalUnrealizedROI({
6252
6453
  totalUnrealizedPnL: unrealizedPnL,
6253
6454
  totalValue: totalValue.toNumber()
6254
6455
  });
6456
+ const maxLeverageBySymbol = positions3.rows.reduce(
6457
+ (acc, position) => {
6458
+ if (position.margin_mode !== MarginMode.ISOLATED && position.leverage && !acc[position.symbol]) {
6459
+ acc[position.symbol] = position.leverage;
6460
+ }
6461
+ return acc;
6462
+ },
6463
+ {}
6464
+ );
6255
6465
  const totalInitialMarginWithOrders = account.totalInitialMarginWithQty({
6256
6466
  positions: positions3.rows,
6467
+ orders: [],
6257
6468
  markPrices,
6258
6469
  IMR_Factors: accountInfo.imr_factor,
6259
- // Not used
6260
- maxLeverage: accountInfo.max_leverage,
6261
- symbolInfo: symbolsInfo
6470
+ maxLeverageBySymbol,
6471
+ symbolInfo: createGetter({ ...symbolsInfo })
6262
6472
  });
6263
6473
  const freeCollateral = account.freeCollateral({
6264
6474
  totalCollateral,
6265
6475
  totalInitialMarginWithOrders
6266
6476
  });
6477
+ const freeCollateralUSDCOnly = account.freeCollateralUSDCOnly({
6478
+ freeCollateral,
6479
+ nonUSDCHolding: nonUSDC
6480
+ });
6267
6481
  const availableBalance = account.availableBalance({
6268
6482
  USDCHolding: usdc?.holding ?? 0,
6269
6483
  unsettlementPnL: positions3.total_unsettled_pnl ?? 0
@@ -6274,8 +6488,9 @@ function formatPortfolio(inputs) {
6274
6488
  totalUnrealizedROI,
6275
6489
  freeCollateral,
6276
6490
  availableBalance,
6277
- unsettledPnL,
6278
- holding
6491
+ unsettledPnL: totalUnsettlementPnL,
6492
+ holding,
6493
+ freeCollateralUSDCOnly
6279
6494
  };
6280
6495
  }
6281
6496
  function formatPositions(data, accountInfo, symbolsInfo, fundingRates) {
@@ -6795,7 +7010,9 @@ var useSubAccountAlgoOrderStream = (params, options) => {
6795
7010
  // trailing stop order fields
6796
7011
  activated_price: order.activated_price,
6797
7012
  callback_value: order.callback_value,
6798
- callback_rate: order.callback_rate
7013
+ callback_rate: order.callback_rate,
7014
+ // include margin_mode if present (align with useOrderStream)
7015
+ ...order.margin_mode && { margin_mode: order.margin_mode }
6799
7016
  });
6800
7017
  default:
6801
7018
  return doUpdateOrder({ ...order, order_id: orderId });
@@ -6982,120 +7199,122 @@ var useCollateral = (options = { dp: 6 }) => {
6982
7199
  totalCollateral,
6983
7200
  totalValue,
6984
7201
  freeCollateral,
7202
+ freeCollateralUSDCOnly,
6985
7203
  availableBalance,
6986
7204
  unsettledPnL,
6987
- holding
7205
+ holding,
7206
+ usdcHolding
6988
7207
  } = useAppStore((state) => state.portfolio);
6989
7208
  const accountInfo = useAppStore((state) => state.accountInfo);
6990
7209
  return {
6991
7210
  totalCollateral: totalCollateral.toDecimalPlaces(dp).toNumber(),
6992
7211
  freeCollateral: freeCollateral.toDecimalPlaces(dp).toNumber(),
7212
+ freeCollateralUSDCOnly: freeCollateralUSDCOnly.toDecimalPlaces(dp).toNumber(),
6993
7213
  totalValue: totalValue?.toDecimalPlaces(dp).toNumber() ?? null,
6994
7214
  availableBalance,
6995
7215
  unsettledPnL,
6996
7216
  accountInfo,
6997
- holding
7217
+ holding,
7218
+ usdcHolding
6998
7219
  // @hidden
6999
7220
  // positions: positionsPath(positions),
7000
7221
  };
7001
7222
  };
7002
- var useLeverageBySymbol = (symbol) => {
7003
- const { state } = useAccount();
7004
- const ws = useWS();
7005
- const { data } = usePrivateQuery(
7006
- symbol ? `/v1/client/leverage?symbol=${symbol}` : null,
7007
- {
7008
- revalidateOnFocus: false
7009
- }
7010
- );
7011
- useEffect(() => {
7012
- if (!state.accountId || !symbol) return;
7013
- const unsubscribe = ws.privateSubscribe("account", {
7014
- onMessage: (data2) => {
7015
- const res = data2?.accountDetail?.symbolLeverage || {};
7016
- if (res.symbol === symbol) {
7017
- const key = [`/v1/client/leverage?symbol=${symbol}`, state.accountId];
7018
- mutate(
7019
- key,
7020
- (prevData) => {
7021
- return {
7022
- ...prevData,
7023
- leverage: res.leverage
7024
- };
7025
- },
7026
- {
7027
- revalidate: false
7028
- }
7029
- );
7030
- }
7031
- }
7032
- });
7033
- return () => unsubscribe?.();
7034
- }, [symbol, state.accountId]);
7035
- return data?.leverage;
7223
+
7224
+ // src/orderly/useLeverageBySymbol.ts
7225
+ var useLeverageBySymbol = (symbol, marginMode) => {
7226
+ const { getSymbolLeverage } = useSymbolLeverageMap();
7227
+ return getSymbolLeverage(symbol, marginMode);
7036
7228
  };
7037
7229
 
7038
7230
  // src/orderly/useMaxQty.ts
7039
- var useMaxQty = (symbol, side, reduceOnly = false) => {
7231
+ function useMaxQty(symbol, side, reduceOnlyOrOptions, marginMode) {
7232
+ const reduceOnly = typeof reduceOnlyOrOptions === "object" && reduceOnlyOrOptions !== null ? reduceOnlyOrOptions.reduceOnly ?? false : reduceOnlyOrOptions ?? false;
7233
+ const finalMarginMode = typeof reduceOnlyOrOptions === "object" && reduceOnlyOrOptions !== null ? reduceOnlyOrOptions.marginMode ?? MarginMode.CROSS : marginMode ?? MarginMode.CROSS;
7040
7234
  const positions3 = usePositions();
7041
7235
  const accountInfo = useAccountInfo();
7042
7236
  const symbolInfo = useSymbolsInfo();
7043
- const { totalCollateral } = useCollateral();
7237
+ const { totalCollateral, freeCollateralUSDCOnly } = useCollateral();
7044
7238
  const { data: markPrices } = useMarkPricesStream();
7045
- const symbolLeverage = useLeverageBySymbol(symbol);
7239
+ const symbolLeverage = useLeverageBySymbol(symbol, finalMarginMode);
7046
7240
  const maxQty = useMemo(() => {
7047
7241
  if (!symbol) return 0;
7048
- const positionQty = account.getQtyFromPositions(
7049
- positions3 === null ? [] : positions3,
7050
- symbol
7242
+ if (!markPrices || !markPrices[symbol] || !accountInfo || !positions3) {
7243
+ return 0;
7244
+ }
7245
+ const positionsArray = (positions3 === null ? [] : positions3).filter(
7246
+ (position) => position.margin_mode === finalMarginMode
7051
7247
  );
7248
+ const positionQty = account.getQtyFromPositions(positionsArray, symbol);
7052
7249
  if (reduceOnly) {
7053
- if (positionQty > 0) {
7054
- if (side === OrderSide.BUY) {
7055
- return 0;
7056
- } else {
7057
- return Math.abs(positionQty);
7058
- }
7059
- }
7060
- if (positionQty < 0) {
7061
- if (side === OrderSide.BUY) {
7062
- return Math.abs(positionQty);
7063
- } else {
7064
- return 0;
7065
- }
7066
- }
7067
- return 0;
7250
+ if (positionQty === 0) return 0;
7251
+ return side === OrderSide.BUY ? positionQty < 0 ? Math.abs(positionQty) : 0 : positionQty > 0 ? positionQty : 0;
7068
7252
  }
7069
- if (!markPrices || !markPrices[symbol] || !accountInfo || !positions3)
7070
- return 0;
7071
7253
  const getSymbolInfo = symbolInfo[symbol];
7072
- const currentSymbolPosition = positions3.find(
7073
- (item) => item.symbol === symbol
7074
- );
7254
+ let currentSymbolPosition;
7255
+ const otherPositions = [];
7256
+ for (const position of positionsArray) {
7257
+ if (position.symbol === symbol) {
7258
+ currentSymbolPosition = position;
7259
+ } else {
7260
+ otherPositions.push(position);
7261
+ }
7262
+ }
7263
+ const markPrice = markPrices[symbol];
7264
+ const baseIMR = getSymbolInfo("base_imr") ?? 0;
7265
+ const IMR_Factor = accountInfo.imr_factor[symbol] ?? 0;
7266
+ const leverage = symbolLeverage || currentSymbolPosition?.leverage || 1;
7075
7267
  const buyOrdersQty = currentSymbolPosition?.pending_long_qty ?? 0;
7076
7268
  const sellOrdersQty = currentSymbolPosition?.pending_short_qty ?? 0;
7077
- const otherPositions = !Array.isArray(positions3) ? [] : positions3.filter((item) => item.symbol !== symbol);
7269
+ if (finalMarginMode === MarginMode.ISOLATED) {
7270
+ const availableBalance = freeCollateralUSDCOnly;
7271
+ const pendingLongOrders = buyOrdersQty > 0 ? [{ referencePrice: markPrice, quantity: buyOrdersQty }] : [];
7272
+ const pendingSellOrders = sellOrdersQty > 0 ? [{ referencePrice: markPrice, quantity: sellOrdersQty }] : [];
7273
+ const markPriceDecimal = new Decimal(markPrice);
7274
+ const leverageDecimal = new Decimal(leverage);
7275
+ const isoOrderFrozenLong = buyOrdersQty > 0 ? markPriceDecimal.mul(buyOrdersQty).div(leverageDecimal).toNumber() : 0;
7276
+ const isoOrderFrozenShort = sellOrdersQty > 0 ? markPriceDecimal.mul(sellOrdersQty).div(leverageDecimal).toNumber() : 0;
7277
+ const symbolMaxNotional = accountInfo.max_notional?.[symbol] ?? positions.maxPositionNotional({
7278
+ leverage,
7279
+ IMRFactor: IMR_Factor
7280
+ });
7281
+ const currentOrderReferencePrice = typeof reduceOnlyOrOptions === "object" && reduceOnlyOrOptions !== null && typeof reduceOnlyOrOptions.currentOrderReferencePrice === "number" && reduceOnlyOrOptions.currentOrderReferencePrice > 0 ? reduceOnlyOrOptions.currentOrderReferencePrice : markPrice;
7282
+ return account.maxQtyForIsolatedMargin({
7283
+ symbol,
7284
+ orderSide: side,
7285
+ currentOrderReferencePrice,
7286
+ availableBalance,
7287
+ leverage,
7288
+ baseIMR,
7289
+ IMR_Factor,
7290
+ markPrice,
7291
+ positionQty,
7292
+ pendingLongOrders,
7293
+ pendingSellOrders,
7294
+ isoOrderFrozenLong,
7295
+ isoOrderFrozenShort,
7296
+ symbolMaxNotional
7297
+ });
7298
+ }
7078
7299
  const otherIMs = account.otherIMs({
7079
7300
  positions: otherPositions,
7080
7301
  symbolInfo,
7081
7302
  markPrices,
7082
- IMR_Factors: accountInfo.imr_factor,
7083
- // Not used
7084
- maxLeverage: accountInfo.max_leverage
7303
+ IMR_Factors: accountInfo.imr_factor
7085
7304
  });
7086
7305
  return account.maxQty(side, {
7087
- markPrice: markPrices[symbol],
7306
+ markPrice,
7088
7307
  symbol,
7089
7308
  baseMaxQty: getSymbolInfo("base_max"),
7090
7309
  totalCollateral,
7091
- maxLeverage: symbolLeverage || currentSymbolPosition?.leverage || 1,
7310
+ maxLeverage: leverage,
7092
7311
  takerFeeRate: accountInfo.futures_taker_fee_rate,
7093
- baseIMR: getSymbolInfo("base_imr"),
7312
+ baseIMR,
7094
7313
  otherIMs,
7095
7314
  positionQty,
7096
7315
  buyOrdersQty,
7097
7316
  sellOrdersQty,
7098
- IMR_Factor: accountInfo.imr_factor[symbol]
7317
+ IMR_Factor
7099
7318
  });
7100
7319
  }, [
7101
7320
  symbol,
@@ -7105,10 +7324,12 @@ var useMaxQty = (symbol, side, reduceOnly = false) => {
7105
7324
  accountInfo,
7106
7325
  symbolInfo,
7107
7326
  side,
7108
- totalCollateral
7327
+ totalCollateral,
7328
+ finalMarginMode,
7329
+ symbolLeverage
7109
7330
  ]);
7110
7331
  return Math.max(maxQty, 0);
7111
- };
7332
+ }
7112
7333
  var useMarginRatio = () => {
7113
7334
  const positions3 = usePositionStore((state2) => state2.positions.all);
7114
7335
  const { rows, notional } = positions3;
@@ -8414,29 +8635,67 @@ var usePrivateDataObserver = (options) => {
8414
8635
  }, [state.accountId, subOrder]);
8415
8636
  useEffect(() => {
8416
8637
  if (!state.accountId) return;
8417
- const key = ["/v1/positions", state.accountId];
8638
+ const positionsKey = ["/v1/positions", state.accountId];
8639
+ const leveragesKey = ["/v1/client/leverages", state.accountId];
8418
8640
  const unsubscribe = ws.privateSubscribe("account", {
8419
8641
  onMessage: (data) => {
8420
- const { symbol, leverage } = data?.accountDetail?.symbolLeverage || {};
8421
- if (symbol && leverage) {
8422
- mutate(
8423
- key,
8424
- (prevPositions) => {
8425
- if (prevPositions?.rows?.length) {
8426
- return {
8427
- ...prevPositions,
8428
- rows: prevPositions.rows.map((row) => {
8429
- return row.symbol === symbol ? { ...row, leverage } : row;
8430
- })
8431
- };
8432
- }
8433
- return prevPositions;
8434
- },
8435
- {
8436
- revalidate: false
8437
- }
8438
- );
8642
+ const { symbol, leverage, marginMode } = data?.accountDetail?.symbolLeverage || {};
8643
+ if (!symbol || leverage === void 0) {
8644
+ return;
8439
8645
  }
8646
+ mutate(
8647
+ positionsKey,
8648
+ (prevPositions) => {
8649
+ if (prevPositions?.rows?.length) {
8650
+ return {
8651
+ ...prevPositions,
8652
+ rows: prevPositions.rows.map((row) => {
8653
+ return row.symbol === symbol && row.margin_mode === marginMode ? { ...row, leverage } : row;
8654
+ })
8655
+ };
8656
+ }
8657
+ return prevPositions;
8658
+ },
8659
+ {
8660
+ revalidate: false
8661
+ }
8662
+ );
8663
+ mutate(
8664
+ leveragesKey,
8665
+ (prev) => {
8666
+ if (!prev) {
8667
+ return [
8668
+ {
8669
+ symbol,
8670
+ leverage,
8671
+ margin_mode: marginMode
8672
+ }
8673
+ ];
8674
+ }
8675
+ const index = prev.findIndex(
8676
+ (item) => item.symbol === symbol && (item.margin_mode ?? MarginMode.CROSS) === (marginMode ?? MarginMode.CROSS)
8677
+ );
8678
+ if (index === -1) {
8679
+ return [
8680
+ ...prev,
8681
+ {
8682
+ symbol,
8683
+ leverage,
8684
+ margin_mode: marginMode
8685
+ }
8686
+ ];
8687
+ }
8688
+ const next = [...prev];
8689
+ next[index] = {
8690
+ ...next[index],
8691
+ leverage
8692
+ };
8693
+ return next;
8694
+ },
8695
+ {
8696
+ revalidate: false
8697
+ }
8698
+ );
8440
8699
  }
8441
8700
  });
8442
8701
  return () => unsubscribe?.();
@@ -8457,7 +8716,7 @@ var usePrivateDataObserver = (options) => {
8457
8716
  ...prevPositions,
8458
8717
  rows: prevPositions.rows.map((row) => {
8459
8718
  const itemIndex = nextPositions.findIndex(
8460
- (item) => item.symbol === row.symbol
8719
+ (item) => item.symbol === row.symbol && item.marginMode === row.margin_mode
8461
8720
  );
8462
8721
  if (itemIndex >= 0) {
8463
8722
  const itemArr = nextPositions.splice(itemIndex, 1);
@@ -8640,14 +8899,70 @@ var OrderValidation = class {
8640
8899
 
8641
8900
  // src/services/orderCreator/baseCreator.ts
8642
8901
  var BaseOrderCreator = class {
8643
- baseOrder(data) {
8902
+ /**
8903
+ * Template method for order creation
8904
+ * Defines the algorithm structure with hooks for subclasses
8905
+ */
8906
+ create(values, config) {
8907
+ this.beforeCreate(values, config);
8908
+ const order = this.buildOrder(values, config);
8909
+ return this.afterCreate(order, config);
8910
+ }
8911
+ /**
8912
+ * Template method for order validation
8913
+ * Defines the algorithm structure with hooks for subclasses
8914
+ */
8915
+ validate(values, config) {
8916
+ this.beforeValidate(values, config);
8917
+ const errors = this.runValidations(values, config);
8918
+ return Promise.resolve(this.afterValidate(errors, values, config));
8919
+ }
8920
+ /**
8921
+ * Hook method called before order creation
8922
+ * Subclasses can override to perform pre-creation setup
8923
+ * @param values - Order values
8924
+ * @param config - Configuration
8925
+ */
8926
+ beforeCreate(values, config) {
8927
+ }
8928
+ /**
8929
+ * Hook method called after order creation
8930
+ * Subclasses can override to perform post-creation processing
8931
+ * @param order - The created order
8932
+ * @param config - Configuration
8933
+ * @returns The final order (possibly modified)
8934
+ */
8935
+ afterCreate(order, config) {
8936
+ return order;
8937
+ }
8938
+ /**
8939
+ * Hook method called before validation
8940
+ * Subclasses can override to perform pre-validation setup
8941
+ * @param values - Order values to validate
8942
+ * @param config - Configuration
8943
+ */
8944
+ beforeValidate(values, config) {
8945
+ }
8946
+ /**
8947
+ * Hook method called after validation
8948
+ * Subclasses can override to perform post-validation processing
8949
+ * @param errors - Validation errors found
8950
+ * @param values - Original order values
8951
+ * @param config - Configuration
8952
+ * @returns Final validation result (possibly modified)
8953
+ */
8954
+ afterValidate(errors, values, config) {
8955
+ return errors;
8956
+ }
8957
+ baseOrder(data) {
8644
8958
  const order = {
8645
8959
  symbol: data.symbol,
8646
8960
  order_type: data.order_type === OrderType.LIMIT ? !!data.order_type_ext ? data.order_type_ext : data.order_type : data.order_type,
8647
8961
  side: data.side,
8648
8962
  reduce_only: data.reduce_only,
8649
8963
  order_quantity: data.order_quantity,
8650
- total: data.total
8964
+ total: data.total,
8965
+ margin_mode: data.margin_mode || MarginMode.CROSS
8651
8966
  // slippage: data.slippage,
8652
8967
  };
8653
8968
  if (data.order_type === OrderType.MARKET && !!data.slippage) {
@@ -8666,10 +8981,21 @@ var BaseOrderCreator = class {
8666
8981
  child_orders: [bracketOrder]
8667
8982
  };
8668
8983
  }
8984
+ /**
8985
+ * Base validation method that can be called by subclasses
8986
+ * Validates common order properties like quantity and min notional
8987
+ * @param values - Order values to validate
8988
+ * @param configs - Configuration
8989
+ * @returns Validation result (synchronous, not a Promise)
8990
+ */
8669
8991
  baseValidate(values, configs) {
8670
8992
  const errors = {};
8671
8993
  const { maxQty, symbol, markPrice } = configs;
8672
- let { order_quantity, total, order_price, reduce_only, order_type } = values;
8994
+ let order_quantity = values.order_quantity;
8995
+ const total = values.total;
8996
+ const order_price = values.order_price;
8997
+ const reduce_only = values.reduce_only;
8998
+ const order_type = values.order_type;
8673
8999
  const { min_notional, base_tick, quote_dp, quote_tick, base_dp } = symbol || {};
8674
9000
  if (!order_quantity) {
8675
9001
  if (total && order_price) {
@@ -8714,7 +9040,7 @@ var BaseOrderCreator = class {
8714
9040
  };
8715
9041
  }
8716
9042
  this.validateBracketOrder(values, configs, errors);
8717
- return Promise.resolve(errors);
9043
+ return errors;
8718
9044
  }
8719
9045
  totalToQuantity(order, config) {
8720
9046
  if (!order.order_quantity && order.total && order.order_price) {
@@ -8863,7 +9189,11 @@ var BBOOrderCreator = class extends BaseOrderCreator {
8863
9189
  super(...arguments);
8864
9190
  this.orderType = OrderType.LIMIT;
8865
9191
  }
8866
- create(values) {
9192
+ /**
9193
+ * Builds the BBO order
9194
+ * Implements template method hook
9195
+ */
9196
+ buildOrder(values) {
8867
9197
  const order = {
8868
9198
  ...this.baseOrder(values),
8869
9199
  level: values.level
@@ -8876,15 +9206,18 @@ var BBOOrderCreator = class extends BaseOrderCreator {
8876
9206
  "reduce_only",
8877
9207
  "side",
8878
9208
  "order_type",
9209
+ "margin_mode",
8879
9210
  "level"
8880
9211
  ],
8881
9212
  order
8882
9213
  );
8883
9214
  }
8884
- async validate(values, configs) {
8885
- return this.baseValidate(values, configs).then((errors) => {
8886
- return errors;
8887
- });
9215
+ /**
9216
+ * Runs base validations
9217
+ * Implements template method hook
9218
+ */
9219
+ runValidations(values, configs) {
9220
+ return this.baseValidate(values, configs);
8888
9221
  }
8889
9222
  };
8890
9223
  function getOrderPrice(order, askAndBid) {
@@ -8911,6 +9244,24 @@ function getOrderPrice(order, askAndBid) {
8911
9244
  }
8912
9245
  }
8913
9246
  }
9247
+ order.getOrderReferencePrice;
9248
+ function getOrderReferencePriceFromOrder(order$1, askAndBid) {
9249
+ if (!askAndBid || askAndBid.length < 2) return null;
9250
+ if (!order$1.order_type || !order$1.side) {
9251
+ return null;
9252
+ }
9253
+ return order.getOrderReferencePrice(
9254
+ {
9255
+ orderType: order$1.order_type,
9256
+ orderTypeExt: order$1.order_type_ext,
9257
+ side: order$1.side,
9258
+ limitPrice: order$1.order_price ? Number(order$1.order_price) : void 0,
9259
+ triggerPrice: order$1.trigger_price ? Number(order$1.trigger_price) : void 0
9260
+ },
9261
+ askAndBid[0],
9262
+ askAndBid[1]
9263
+ );
9264
+ }
8914
9265
  function getPriceRange(inputs) {
8915
9266
  const { basePrice, side, symbolInfo } = inputs;
8916
9267
  const { price_range, price_scope, quote_min, quote_max } = symbolInfo;
@@ -8924,97 +9275,170 @@ function getPriceRange(inputs) {
8924
9275
  min: minPriceNumber,
8925
9276
  max: scopePriceNumber
8926
9277
  };
8927
- const minPrice3 = Math.max(quote_min, priceRange?.min);
8928
- const maxPrice3 = Math.min(quote_max, priceRange?.max);
9278
+ const minPrice = Math.max(quote_min, priceRange?.min);
9279
+ const maxPrice = Math.min(quote_max, priceRange?.max);
8929
9280
  return {
8930
- minPrice: minPrice3,
8931
- maxPrice: maxPrice3
9281
+ minPrice,
9282
+ maxPrice
8932
9283
  };
8933
9284
  }
8934
9285
 
8935
- // src/services/orderCreator/baseBracketOrderCreator.ts
9286
+ // src/services/orderCreator/validators/TPSLValidationStrategy.ts
8936
9287
  var formatPrice = (price, quote_dp) => {
8937
9288
  return new Decimal(price).toDecimalPlaces(quote_dp).toNumber();
8938
9289
  };
8939
- async function bracketOrderValidator(values, config) {
8940
- const result = /* @__PURE__ */ Object.create(null);
8941
- await Promise.resolve();
8942
- const {
8943
- // tp_enable,
8944
- // sl_enable,
8945
- tp_trigger_price,
8946
- tp_order_price,
8947
- tp_order_type,
8948
- sl_trigger_price,
8949
- sl_order_price,
8950
- sl_order_type,
8951
- side
8952
- } = values;
8953
- const qty = Number(values.quantity);
8954
- const maxQty = config.maxQty;
8955
- const type = values.order_type;
8956
- const { quote_max, quote_min, quote_dp } = config.symbol ?? {};
8957
- const mark_price = type === OrderType.MARKET ? config.markPrice : values.order_price ? Number(values.order_price) : void 0;
8958
- const tpslSide = side === OrderSide.BUY ? OrderSide.SELL : OrderSide.BUY;
8959
- if (!isNaN(qty) && qty > maxQty) {
8960
- result.quantity = OrderValidation.max("quantity", config.maxQty);
8961
- }
8962
- if (Number(tp_trigger_price) < 0) {
8963
- result.tp_trigger_price = OrderValidation.min("tp_trigger_price", 0);
8964
- }
8965
- if (Number(sl_trigger_price) < 0) {
8966
- result.sl_trigger_price = OrderValidation.min("sl_trigger_price", 0);
8967
- }
8968
- if (tp_order_type === OrderType.LIMIT && !tp_order_price) {
8969
- result.tp_order_price = OrderValidation.required("tp_order_price");
8970
- }
8971
- if (sl_order_type === OrderType.LIMIT && !sl_order_price) {
8972
- result.sl_order_price = OrderValidation.required("sl_order_price");
8973
- }
8974
- if (side === OrderSide.BUY && mark_price) {
8975
- if (!!sl_trigger_price && Number(sl_trigger_price) < quote_min) {
8976
- result.sl_trigger_price = OrderValidation.min(
8977
- "sl_trigger_price",
8978
- formatPrice(quote_min, quote_dp)
9290
+ var TPSLValidationStrategy = class {
9291
+ /**
9292
+ * Validates TP/SL order values
9293
+ * @param values - TP/SL order values including trigger prices, order prices, etc.
9294
+ * @param config - Configuration with symbol info and mark price
9295
+ * @returns Validation result object with any errors found
9296
+ */
9297
+ validate(values, config) {
9298
+ const result = /* @__PURE__ */ Object.create(null);
9299
+ const {
9300
+ tp_trigger_price,
9301
+ tp_order_price,
9302
+ tp_order_type,
9303
+ sl_trigger_price,
9304
+ sl_order_price,
9305
+ sl_order_type,
9306
+ side,
9307
+ quantity,
9308
+ order_type,
9309
+ order_price
9310
+ } = values;
9311
+ const qty = Number(quantity);
9312
+ const maxQty = config.maxQty;
9313
+ const { quote_max, quote_min, quote_dp, base_min } = config.symbol ?? {};
9314
+ const mark_price = order_type === OrderType.MARKET || order_type == null ? config.markPrice : order_price ? Number(order_price) : void 0;
9315
+ const tpslSide = side === OrderSide.BUY ? OrderSide.SELL : OrderSide.BUY;
9316
+ if (!isNaN(qty) && qty > maxQty) {
9317
+ result.quantity = OrderValidation.max("quantity", config.maxQty);
9318
+ }
9319
+ if (!isNaN(qty) && qty < (base_min ?? 0)) {
9320
+ result.quantity = OrderValidation.min("quantity", base_min ?? 0);
9321
+ }
9322
+ if (tp_trigger_price !== void 0 && tp_trigger_price !== "" && tp_trigger_price !== null && Number(tp_trigger_price) < 0) {
9323
+ result.tp_trigger_price = OrderValidation.min("tp_trigger_price", 0);
9324
+ }
9325
+ if (sl_trigger_price !== void 0 && sl_trigger_price !== "" && sl_trigger_price !== null && Number(sl_trigger_price) < 0) {
9326
+ result.sl_trigger_price = OrderValidation.min("sl_trigger_price", 0);
9327
+ }
9328
+ if (tp_order_type === OrderType.LIMIT && !tp_order_price) {
9329
+ result.tp_order_price = OrderValidation.required("tp_order_price");
9330
+ }
9331
+ if (sl_order_type === OrderType.LIMIT && !sl_order_price) {
9332
+ result.sl_order_price = OrderValidation.required("sl_order_price");
9333
+ }
9334
+ if (side === OrderSide.BUY && mark_price) {
9335
+ this.validateBuySide(
9336
+ {
9337
+ tp_trigger_price,
9338
+ tp_order_price,
9339
+ sl_trigger_price,
9340
+ sl_order_price
9341
+ },
9342
+ {
9343
+ mark_price,
9344
+ quote_min: quote_min ?? 0,
9345
+ quote_max: quote_max ?? 0,
9346
+ quote_dp: quote_dp ?? 0,
9347
+ tpslSide,
9348
+ symbol: config.symbol
9349
+ },
9350
+ result
8979
9351
  );
8980
- }
8981
- if (!!sl_trigger_price && Number(sl_trigger_price) > mark_price) {
8982
- result.sl_trigger_price = OrderValidation.max(
8983
- "sl_trigger_price",
8984
- formatPrice(mark_price, quote_dp)
9352
+ } else if (side === OrderSide.SELL && mark_price) {
9353
+ this.validateSellSide(
9354
+ {
9355
+ tp_trigger_price,
9356
+ tp_order_price,
9357
+ sl_trigger_price,
9358
+ sl_order_price
9359
+ },
9360
+ {
9361
+ mark_price,
9362
+ quote_min: quote_min ?? 0,
9363
+ quote_max: quote_max ?? 0,
9364
+ quote_dp: quote_dp ?? 0,
9365
+ tpslSide,
9366
+ symbol: config.symbol
9367
+ },
9368
+ result
8985
9369
  );
8986
9370
  }
8987
- if (!!tp_trigger_price && Number(tp_trigger_price) <= mark_price) {
8988
- result.tp_trigger_price = OrderValidation.min(
8989
- "tp_trigger_price",
8990
- formatPrice(mark_price, quote_dp)
8991
- );
9371
+ return Object.keys(result).length > 0 ? result : null;
9372
+ }
9373
+ /**
9374
+ * Validates TP/SL for BUY orders
9375
+ * For BUY orders:
9376
+ * - SL trigger price must be < mark price
9377
+ * - TP trigger price must be > mark price
9378
+ */
9379
+ validateBuySide(prices, config, result) {
9380
+ const {
9381
+ tp_trigger_price,
9382
+ tp_order_price,
9383
+ sl_trigger_price,
9384
+ sl_order_price
9385
+ } = prices;
9386
+ const { mark_price, quote_min, quote_max, quote_dp, tpslSide, symbol } = config;
9387
+ if (sl_trigger_price !== void 0 && sl_trigger_price !== "" && sl_trigger_price !== null) {
9388
+ const slTrigger = Number(sl_trigger_price);
9389
+ if (!isNaN(slTrigger)) {
9390
+ if (quote_min > 0 && slTrigger < quote_min) {
9391
+ result.sl_trigger_price = OrderValidation.min(
9392
+ "sl_trigger_price",
9393
+ formatPrice(quote_min, quote_dp)
9394
+ );
9395
+ }
9396
+ if (slTrigger >= mark_price) {
9397
+ result.sl_trigger_price = OrderValidation.max(
9398
+ "sl_trigger_price",
9399
+ formatPrice(mark_price, quote_dp)
9400
+ );
9401
+ }
9402
+ }
8992
9403
  }
8993
- if (!!tp_trigger_price && Number(tp_trigger_price) > quote_max) {
8994
- result.tp_trigger_price = OrderValidation.max(
8995
- "tp_trigger_price",
8996
- formatPrice(quote_max, quote_dp)
8997
- );
9404
+ if (tp_trigger_price !== void 0 && tp_trigger_price !== "" && tp_trigger_price !== null) {
9405
+ const tpTrigger = Number(tp_trigger_price);
9406
+ if (!isNaN(tpTrigger)) {
9407
+ if (tpTrigger <= mark_price) {
9408
+ result.tp_trigger_price = OrderValidation.min(
9409
+ "tp_trigger_price",
9410
+ formatPrice(mark_price, quote_dp)
9411
+ );
9412
+ }
9413
+ if (quote_max > 0 && tpTrigger > quote_max) {
9414
+ result.tp_trigger_price = OrderValidation.max(
9415
+ "tp_trigger_price",
9416
+ formatPrice(quote_max, quote_dp)
9417
+ );
9418
+ }
9419
+ }
8998
9420
  }
8999
9421
  if (sl_trigger_price && sl_order_price) {
9000
9422
  const priceRange = getPriceRange({
9001
9423
  side: tpslSide,
9002
9424
  basePrice: Number(sl_trigger_price),
9003
- symbolInfo: config.symbol
9425
+ symbolInfo: symbol
9004
9426
  });
9005
- if (Number(sl_order_price) < priceRange.minPrice) {
9427
+ const slOrderPrice = Number(sl_order_price);
9428
+ const slTrigger = Number(sl_trigger_price);
9429
+ if (slOrderPrice < priceRange.minPrice) {
9006
9430
  result.sl_order_price = OrderValidation.min(
9007
9431
  "sl_order_price",
9008
9432
  formatPrice(priceRange.minPrice, quote_dp)
9009
9433
  );
9010
9434
  }
9011
- if (Number(sl_order_price) > priceRange.maxPrice) {
9435
+ if (slOrderPrice > priceRange.maxPrice) {
9012
9436
  result.sl_order_price = OrderValidation.max(
9013
9437
  "sl_order_price",
9014
9438
  formatPrice(priceRange.maxPrice, quote_dp)
9015
9439
  );
9016
9440
  }
9017
- if (Number(sl_trigger_price) < Number(sl_order_price)) {
9441
+ if (slTrigger < slOrderPrice) {
9018
9442
  result.sl_trigger_price = OrderValidation.priceErrorMax("sl_trigger_price");
9019
9443
  }
9020
9444
  }
@@ -9022,69 +9446,96 @@ async function bracketOrderValidator(values, config) {
9022
9446
  const priceRange = getPriceRange({
9023
9447
  side: tpslSide,
9024
9448
  basePrice: Number(tp_trigger_price),
9025
- symbolInfo: config.symbol
9449
+ symbolInfo: symbol
9026
9450
  });
9027
- if (Number(tp_order_price) > priceRange.maxPrice) {
9451
+ const tpOrderPrice = Number(tp_order_price);
9452
+ const tpTrigger = Number(tp_trigger_price);
9453
+ if (tpOrderPrice > priceRange.maxPrice) {
9028
9454
  result.tp_order_price = OrderValidation.max(
9029
9455
  "tp_order_price",
9030
9456
  formatPrice(priceRange.maxPrice, quote_dp)
9031
9457
  );
9032
9458
  }
9033
- if (Number(tp_order_price) < priceRange.minPrice) {
9459
+ if (tpOrderPrice < priceRange.minPrice) {
9034
9460
  result.tp_order_price = OrderValidation.min(
9035
9461
  "tp_order_price",
9036
9462
  formatPrice(priceRange.minPrice, quote_dp)
9037
9463
  );
9038
9464
  }
9039
- if (Number(tp_trigger_price) > Number(tp_order_price)) {
9465
+ if (tpTrigger > tpOrderPrice) {
9040
9466
  result.tp_trigger_price = OrderValidation.priceErrorMax("tp_trigger_price");
9041
9467
  }
9042
9468
  }
9043
9469
  }
9044
- if (side === OrderSide.SELL && mark_price) {
9045
- if (!!sl_trigger_price && Number(sl_trigger_price) > quote_max) {
9046
- result.sl_trigger_price = OrderValidation.max(
9047
- "sl_trigger_price",
9048
- formatPrice(quote_max, quote_dp)
9049
- );
9050
- }
9051
- if (!!sl_trigger_price && Number(sl_trigger_price) < mark_price) {
9052
- result.sl_trigger_price = OrderValidation.min(
9053
- "sl_trigger_price",
9054
- formatPrice(mark_price, quote_dp)
9055
- );
9056
- }
9057
- if (!!tp_trigger_price && Number(tp_trigger_price) >= mark_price) {
9058
- result.tp_trigger_price = OrderValidation.max(
9059
- "tp_trigger_price",
9060
- formatPrice(mark_price, quote_dp)
9061
- );
9470
+ /**
9471
+ * Validates TP/SL for SELL orders
9472
+ * For SELL orders:
9473
+ * - SL trigger price must be > mark price
9474
+ * - TP trigger price must be < mark price
9475
+ */
9476
+ validateSellSide(prices, config, result) {
9477
+ const {
9478
+ tp_trigger_price,
9479
+ tp_order_price,
9480
+ sl_trigger_price,
9481
+ sl_order_price
9482
+ } = prices;
9483
+ const { mark_price, quote_min, quote_max, quote_dp, tpslSide, symbol } = config;
9484
+ if (sl_trigger_price !== void 0 && sl_trigger_price !== "" && sl_trigger_price !== null) {
9485
+ const slTrigger = Number(sl_trigger_price);
9486
+ if (!isNaN(slTrigger)) {
9487
+ if (quote_max > 0 && slTrigger > quote_max) {
9488
+ result.sl_trigger_price = OrderValidation.max(
9489
+ "sl_trigger_price",
9490
+ formatPrice(quote_max, quote_dp)
9491
+ );
9492
+ }
9493
+ if (slTrigger <= mark_price) {
9494
+ result.sl_trigger_price = OrderValidation.min(
9495
+ "sl_trigger_price",
9496
+ formatPrice(mark_price, quote_dp)
9497
+ );
9498
+ }
9499
+ }
9062
9500
  }
9063
- if (!!tp_trigger_price && Number(tp_trigger_price) < quote_min) {
9064
- result.tp_trigger_price = OrderValidation.min(
9065
- "tp_trigger_price",
9066
- formatPrice(quote_min, quote_dp)
9067
- );
9501
+ if (tp_trigger_price !== void 0 && tp_trigger_price !== "" && tp_trigger_price !== null) {
9502
+ const tpTrigger = Number(tp_trigger_price);
9503
+ if (!isNaN(tpTrigger)) {
9504
+ if (tpTrigger >= mark_price) {
9505
+ result.tp_trigger_price = OrderValidation.max(
9506
+ "tp_trigger_price",
9507
+ formatPrice(mark_price, quote_dp)
9508
+ );
9509
+ }
9510
+ if (quote_min > 0 && tpTrigger < quote_min) {
9511
+ result.tp_trigger_price = OrderValidation.min(
9512
+ "tp_trigger_price",
9513
+ formatPrice(quote_min, quote_dp)
9514
+ );
9515
+ }
9516
+ }
9068
9517
  }
9069
9518
  if (sl_trigger_price && sl_order_price) {
9070
9519
  const priceRange = getPriceRange({
9071
9520
  side: tpslSide,
9072
9521
  basePrice: Number(sl_trigger_price),
9073
- symbolInfo: config.symbol
9522
+ symbolInfo: symbol
9074
9523
  });
9075
- if (Number(sl_order_price) < priceRange.minPrice) {
9524
+ const slOrderPrice = Number(sl_order_price);
9525
+ const slTrigger = Number(sl_trigger_price);
9526
+ if (slOrderPrice < priceRange.minPrice) {
9076
9527
  result.sl_order_price = OrderValidation.min(
9077
9528
  "sl_order_price",
9078
9529
  formatPrice(priceRange.minPrice, quote_dp)
9079
9530
  );
9080
9531
  }
9081
- if (Number(sl_order_price) > priceRange.maxPrice) {
9532
+ if (slOrderPrice > priceRange.maxPrice) {
9082
9533
  result.sl_order_price = OrderValidation.max(
9083
9534
  "sl_order_price",
9084
9535
  formatPrice(priceRange.maxPrice, quote_dp)
9085
9536
  );
9086
9537
  }
9087
- if (Number(sl_trigger_price) > Number(sl_order_price)) {
9538
+ if (slTrigger > slOrderPrice) {
9088
9539
  result.sl_trigger_price = OrderValidation.priceErrorMin("sl_trigger_price");
9089
9540
  }
9090
9541
  }
@@ -9092,37 +9543,294 @@ async function bracketOrderValidator(values, config) {
9092
9543
  const priceRange = getPriceRange({
9093
9544
  side: tpslSide,
9094
9545
  basePrice: Number(tp_trigger_price),
9095
- symbolInfo: config.symbol
9546
+ symbolInfo: symbol
9096
9547
  });
9097
- if (Number(tp_order_price) < priceRange.minPrice) {
9548
+ const tpOrderPrice = Number(tp_order_price);
9549
+ const tpTrigger = Number(tp_trigger_price);
9550
+ if (tpOrderPrice < priceRange.minPrice) {
9098
9551
  result.tp_order_price = OrderValidation.min(
9099
9552
  "tp_order_price",
9100
9553
  formatPrice(priceRange.minPrice, quote_dp)
9101
9554
  );
9102
9555
  }
9103
- if (Number(tp_order_price) > priceRange.maxPrice) {
9556
+ if (tpOrderPrice > priceRange.maxPrice) {
9104
9557
  result.tp_order_price = OrderValidation.max(
9105
9558
  "tp_order_price",
9106
9559
  formatPrice(priceRange.maxPrice, quote_dp)
9107
9560
  );
9108
9561
  }
9109
- if (Number(tp_trigger_price) < Number(tp_order_price)) {
9562
+ if (tpTrigger < tpOrderPrice) {
9110
9563
  result.tp_trigger_price = OrderValidation.priceErrorMax("tp_trigger_price");
9111
9564
  }
9112
9565
  }
9113
9566
  }
9114
- return Object.keys(result).length > 0 ? result : null;
9567
+ };
9568
+
9569
+ // src/services/orderCreator/baseBracketOrderCreator.ts
9570
+ async function bracketOrderValidator(values, config) {
9571
+ const strategy = new TPSLValidationStrategy();
9572
+ return strategy.validate(values, config);
9115
9573
  }
9116
- var { maxPrice, minPrice, scopePrice } = order;
9574
+
9575
+ // src/services/orderCreator/validators/BaseValidator.ts
9576
+ var BaseValidator = class {
9577
+ /**
9578
+ * Sets the next validator in the chain
9579
+ * @param validator - The next validator to call
9580
+ * @returns The next validator for method chaining
9581
+ */
9582
+ setNext(validator) {
9583
+ this.next = validator;
9584
+ return validator;
9585
+ }
9586
+ /**
9587
+ * Validates values and passes to next validator in chain
9588
+ * @param values - The values to validate
9589
+ * @param config - Configuration for validation
9590
+ * @param errors - Accumulated validation errors
9591
+ * @returns Updated validation result
9592
+ */
9593
+ validate(values, config, errors) {
9594
+ const result = this.doValidate(values, config);
9595
+ if (result) {
9596
+ errors[this.getFieldName()] = result;
9597
+ }
9598
+ return this.next?.validate(values, config, errors) ?? errors;
9599
+ }
9600
+ };
9601
+ var PriceValidationStrategy = class {
9602
+ /**
9603
+ * Validates order price against symbol constraints and price range
9604
+ * @param values - Object containing order_price, side, and order_type
9605
+ * @param config - Configuration with symbol info and mark price
9606
+ * @returns Validation error if price is invalid, undefined otherwise
9607
+ */
9608
+ validate(values, config) {
9609
+ const { order_price, side } = values;
9610
+ if (!order_price) {
9611
+ return OrderValidation.required("order_price");
9612
+ }
9613
+ const price = new Decimal(order_price);
9614
+ const { symbol } = config;
9615
+ const { quote_max, quote_min, quote_dp, price_range, price_scope } = symbol;
9616
+ const maxPriceNumber = order.maxPrice(config.markPrice, price_range);
9617
+ const minPriceNumber = order.minPrice(config.markPrice, price_range);
9618
+ const scopePriceNumber = order.scopePrice(
9619
+ config.markPrice,
9620
+ price_scope,
9621
+ side
9622
+ );
9623
+ const priceRange = side === OrderSide.BUY ? {
9624
+ min: scopePriceNumber,
9625
+ max: maxPriceNumber
9626
+ } : {
9627
+ min: minPriceNumber,
9628
+ max: scopePriceNumber
9629
+ };
9630
+ if (price.gt(quote_max)) {
9631
+ return OrderValidation.max("order_price", quote_max);
9632
+ }
9633
+ if (price.lt(quote_min)) {
9634
+ return OrderValidation.min("order_price", quote_min);
9635
+ }
9636
+ if (price.gt(priceRange.max)) {
9637
+ return OrderValidation.max(
9638
+ "order_price",
9639
+ new Decimal(priceRange.max).todp(quote_dp).toString()
9640
+ );
9641
+ }
9642
+ if (price.lt(priceRange.min)) {
9643
+ return OrderValidation.min(
9644
+ "order_price",
9645
+ new Decimal(priceRange.min).todp(quote_dp).toString()
9646
+ );
9647
+ }
9648
+ return void 0;
9649
+ }
9650
+ };
9651
+ var TriggerPriceValidationStrategy = class {
9652
+ /**
9653
+ * Validates trigger price against symbol constraints
9654
+ * @param values - Object containing trigger_price
9655
+ * @param config - Configuration with symbol info
9656
+ * @returns Validation error if trigger price is invalid, undefined otherwise
9657
+ */
9658
+ validate(values, config) {
9659
+ const { trigger_price } = values;
9660
+ const { symbol } = config;
9661
+ const { quote_max, quote_min } = symbol;
9662
+ if (!trigger_price) {
9663
+ return OrderValidation.required("trigger_price");
9664
+ }
9665
+ const triggerPrice = Number(trigger_price);
9666
+ if (triggerPrice > quote_max) {
9667
+ return OrderValidation.max("trigger_price", quote_max);
9668
+ }
9669
+ if (triggerPrice < quote_min || triggerPrice === 0) {
9670
+ return OrderValidation.min("trigger_price", quote_min);
9671
+ }
9672
+ return void 0;
9673
+ }
9674
+ };
9675
+
9676
+ // src/services/orderCreator/validators/PriceValidator.ts
9677
+ var PriceValidator = class extends BaseValidator {
9678
+ constructor() {
9679
+ super();
9680
+ this.strategy = new PriceValidationStrategy();
9681
+ }
9682
+ doValidate(values, config) {
9683
+ return this.strategy.validate(
9684
+ {
9685
+ order_price: values.order_price,
9686
+ side: values.side,
9687
+ order_type: values.order_type
9688
+ },
9689
+ config
9690
+ );
9691
+ }
9692
+ getFieldName() {
9693
+ return "order_price";
9694
+ }
9695
+ };
9696
+ var QuantityValidationStrategy = class {
9697
+ /**
9698
+ * Validates order quantity against symbol constraints
9699
+ * Also handles conversion from total to quantity if needed
9700
+ * @param values - Object containing order_quantity, total, and order_price
9701
+ * @param config - Configuration with symbol info and max quantity
9702
+ * @returns Validation error if quantity is invalid, undefined otherwise
9703
+ */
9704
+ validate(values, config) {
9705
+ let { order_quantity, total, order_price } = values;
9706
+ const { maxQty, symbol } = config;
9707
+ const { base_min, base_dp, quote_dp } = symbol;
9708
+ if (!order_quantity && total && order_price) {
9709
+ const totalNumber = new Decimal(total);
9710
+ const qty2 = totalNumber.dividedBy(order_price).toFixed(quote_dp);
9711
+ order_quantity = qty2;
9712
+ }
9713
+ if (!order_quantity) {
9714
+ return OrderValidation.required("order_quantity");
9715
+ }
9716
+ const qty = new Decimal(order_quantity);
9717
+ if (qty.lt(base_min)) {
9718
+ return OrderValidation.min(
9719
+ "order_quantity",
9720
+ new Decimal(base_min).todp(base_dp).toString()
9721
+ );
9722
+ }
9723
+ if (qty.gt(maxQty)) {
9724
+ return OrderValidation.max(
9725
+ "order_quantity",
9726
+ new Decimal(maxQty).todp(base_dp).toString()
9727
+ );
9728
+ }
9729
+ return void 0;
9730
+ }
9731
+ };
9732
+
9733
+ // src/services/orderCreator/validators/QuantityValidator.ts
9734
+ var QuantityValidator = class extends BaseValidator {
9735
+ constructor() {
9736
+ super();
9737
+ this.strategy = new QuantityValidationStrategy();
9738
+ }
9739
+ doValidate(values, config) {
9740
+ return this.strategy.validate(
9741
+ {
9742
+ order_quantity: values.order_quantity,
9743
+ total: values.total,
9744
+ order_price: values.order_price
9745
+ },
9746
+ config
9747
+ );
9748
+ }
9749
+ getFieldName() {
9750
+ return "order_quantity";
9751
+ }
9752
+ };
9753
+
9754
+ // src/services/orderCreator/validators/ValidationChain.ts
9755
+ var ValidationChain = class {
9756
+ constructor() {
9757
+ this.validators = [];
9758
+ }
9759
+ /**
9760
+ * Adds a validator to the chain
9761
+ * @param validator - The validator to add
9762
+ * @returns This chain instance for method chaining
9763
+ */
9764
+ addValidator(validator) {
9765
+ this.validators.push(validator);
9766
+ if (!this.head) {
9767
+ this.head = validator;
9768
+ } else {
9769
+ let current = this.head;
9770
+ while (current && current.next) {
9771
+ current = current.next;
9772
+ }
9773
+ if (current) {
9774
+ current.setNext(validator);
9775
+ }
9776
+ }
9777
+ return this;
9778
+ }
9779
+ /**
9780
+ * Adds multiple validators to the chain
9781
+ * @param validators - Array of validators to add
9782
+ * @returns This chain instance for method chaining
9783
+ */
9784
+ addValidators(validators) {
9785
+ validators.forEach((validator) => this.addValidator(validator));
9786
+ return this;
9787
+ }
9788
+ /**
9789
+ * Validates values using all validators in the chain
9790
+ * @param values - The values to validate
9791
+ * @param config - Configuration for validation
9792
+ * @returns Validation result with all errors found
9793
+ */
9794
+ validate(values, config) {
9795
+ const errors = {};
9796
+ if (this.head) {
9797
+ return this.head.validate(values, config, errors);
9798
+ }
9799
+ return errors;
9800
+ }
9801
+ /**
9802
+ * Clears all validators from the chain
9803
+ */
9804
+ clear() {
9805
+ this.validators = [];
9806
+ this.head = void 0;
9807
+ }
9808
+ /**
9809
+ * Gets the number of validators in the chain
9810
+ * @returns The number of validators
9811
+ */
9812
+ get length() {
9813
+ return this.validators.length;
9814
+ }
9815
+ };
9816
+
9817
+ // src/services/orderCreator/limitOrderCreator.ts
9117
9818
  var LimitOrderCreator = class extends BaseOrderCreator {
9118
9819
  constructor() {
9119
9820
  super(...arguments);
9821
+ // private priceValidationStrategy = new PriceValidationStrategy();
9822
+ this.validationChain = new ValidationChain().addValidator(new QuantityValidator()).addValidator(new PriceValidator());
9120
9823
  this.orderType = OrderType.LIMIT;
9121
9824
  }
9122
- create(values, config) {
9825
+ /**
9826
+ * Builds the limit order
9827
+ * Implements template method hook
9828
+ */
9829
+ buildOrder(values, config) {
9830
+ const orderlyValues = values;
9123
9831
  const order = {
9124
- ...this.baseOrder(values),
9125
- order_price: values.order_price
9832
+ ...this.baseOrder(orderlyValues),
9833
+ order_price: orderlyValues.order_price
9126
9834
  };
9127
9835
  this.totalToQuantity(order, config);
9128
9836
  return pick(
@@ -9134,58 +9842,23 @@ var LimitOrderCreator = class extends BaseOrderCreator {
9134
9842
  "reduce_only",
9135
9843
  "side",
9136
9844
  "order_type",
9845
+ "margin_mode",
9137
9846
  "algo_type",
9138
9847
  "child_orders"
9139
9848
  ],
9140
9849
  order
9141
9850
  );
9142
9851
  }
9143
- validate(values, config) {
9144
- return this.baseValidate(values, config).then((errors) => {
9145
- const { order_price, side } = values;
9146
- if (!order_price) {
9147
- errors.order_price = OrderValidation.required("order_price");
9148
- } else {
9149
- const price = new Decimal(order_price);
9150
- const { symbol } = config;
9151
- const { price_range, price_scope, quote_max, quote_min } = symbol;
9152
- const maxPriceNumber = maxPrice(config.markPrice, price_range);
9153
- const minPriceNumber = minPrice(config.markPrice, price_range);
9154
- const scopePriceNumber = scopePrice(
9155
- config.markPrice,
9156
- price_scope,
9157
- side
9158
- );
9159
- const priceRange = side === "BUY" ? {
9160
- min: scopePriceNumber,
9161
- max: maxPriceNumber
9162
- } : {
9163
- min: minPriceNumber,
9164
- max: scopePriceNumber
9165
- };
9166
- if (price.gt(quote_max)) {
9167
- errors.order_price = OrderValidation.max("order_price", quote_max);
9168
- } else {
9169
- if (price.gt(priceRange?.max)) {
9170
- errors.order_price = OrderValidation.max(
9171
- "order_price",
9172
- new Decimal(priceRange.max).todp(symbol.quote_dp).toString()
9173
- );
9174
- }
9175
- }
9176
- if (price.lt(quote_min)) {
9177
- errors.order_price = OrderValidation.min("order_price", quote_min);
9178
- } else {
9179
- if (price.lt(priceRange?.min)) {
9180
- errors.order_price = OrderValidation.min(
9181
- "order_price",
9182
- new Decimal(priceRange.min).todp(symbol.quote_dp).toString()
9183
- );
9184
- }
9185
- }
9186
- }
9187
- return errors;
9188
- });
9852
+ /**
9853
+ * Runs validations using validation chain
9854
+ * Implements template method hook
9855
+ */
9856
+ runValidations(values, config) {
9857
+ const orderlyValues = values;
9858
+ const errors = this.baseValidate(orderlyValues, config);
9859
+ const chainErrors = this.validationChain.validate(orderlyValues, config);
9860
+ Object.assign(errors, chainErrors);
9861
+ return errors;
9189
9862
  }
9190
9863
  };
9191
9864
 
@@ -9208,34 +9881,81 @@ var BracketLimitOrderCreator = class extends LimitOrderCreator {
9208
9881
  }
9209
9882
  };
9210
9883
 
9884
+ // src/services/orderCreator/validators/SlippageValidationStrategy.ts
9885
+ var SlippageValidationStrategy = class {
9886
+ /**
9887
+ * Validates slippage against estimated slippage
9888
+ * @param values - Object containing slippage value
9889
+ * @param config - Configuration with estimated slippage
9890
+ * @returns Validation error if slippage exceeds estimated, undefined otherwise
9891
+ */
9892
+ validate(values, config) {
9893
+ const slippage = Number(values.slippage);
9894
+ const estSlippage = Number.isNaN(config.estSlippage) ? 0 : Number(config.estSlippage) * 100;
9895
+ if (!isNaN(slippage) && estSlippage > slippage) {
9896
+ return {
9897
+ type: "max",
9898
+ message: "Estimated slippage exceeds your maximum allowed slippage.",
9899
+ value: estSlippage
9900
+ };
9901
+ }
9902
+ return void 0;
9903
+ }
9904
+ };
9905
+
9906
+ // src/services/orderCreator/validators/SlippageValidator.ts
9907
+ var SlippageValidator = class extends BaseValidator {
9908
+ constructor() {
9909
+ super();
9910
+ this.strategy = new SlippageValidationStrategy();
9911
+ }
9912
+ doValidate(values, config) {
9913
+ return this.strategy.validate(
9914
+ {
9915
+ slippage: values.slippage
9916
+ },
9917
+ config
9918
+ );
9919
+ }
9920
+ getFieldName() {
9921
+ return "slippage";
9922
+ }
9923
+ };
9924
+
9211
9925
  // src/services/orderCreator/marketOrderCreator.ts
9212
9926
  var MarketOrderCreator = class extends BaseOrderCreator {
9213
- create(values) {
9214
- const data = this.baseOrder(values);
9215
- delete data["order_price"];
9216
- delete data["total"];
9217
- delete data["trigger_price"];
9218
- delete data["isStopOrder"];
9219
- return {
9220
- ...data
9221
- };
9927
+ constructor() {
9928
+ super(...arguments);
9929
+ this.slippageValidationStrategy = new SlippageValidationStrategy();
9930
+ this.validationChain = new ValidationChain().addValidator(new QuantityValidator()).addValidator(new SlippageValidator());
9931
+ this.orderType = OrderType.MARKET;
9222
9932
  }
9223
- validate(values, configs) {
9224
- return this.baseValidate(values, configs).then((result) => {
9225
- const slippage = Number(values.slippage);
9226
- const estSlippage = Number.isNaN(configs.estSlippage) ? 0 : Number(configs.estSlippage) * 100;
9227
- if (!isNaN(slippage) && estSlippage > slippage) {
9228
- return {
9229
- ...result,
9230
- slippage: {
9231
- type: "max",
9232
- message: "Estimated slippage exceeds your maximum allowed slippage.",
9233
- value: estSlippage
9234
- }
9235
- };
9236
- }
9237
- return result;
9238
- });
9933
+ /**
9934
+ * Builds the market order
9935
+ * Implements template method hook
9936
+ */
9937
+ buildOrder(values, config) {
9938
+ const orderlyValues = values;
9939
+ const data = this.baseOrder(orderlyValues);
9940
+ const result = { ...data };
9941
+ delete result.order_price;
9942
+ delete result.total;
9943
+ delete result.trigger_price;
9944
+ if ("isStopOrder" in result) {
9945
+ delete result.isStopOrder;
9946
+ }
9947
+ return result;
9948
+ }
9949
+ /**
9950
+ * Runs validations using validation chain
9951
+ * Implements template method hook
9952
+ */
9953
+ runValidations(values, configs) {
9954
+ const orderlyValues = values;
9955
+ const result = this.baseValidate(orderlyValues, configs);
9956
+ const chainErrors = this.validationChain.validate(orderlyValues, configs);
9957
+ Object.assign(result, chainErrors);
9958
+ return result;
9239
9959
  }
9240
9960
  };
9241
9961
 
@@ -9267,14 +9987,26 @@ var FOKOrderCreator = class extends LimitOrderCreator {
9267
9987
 
9268
9988
  // src/services/orderCreator/generalCreator.ts
9269
9989
  var GeneralOrderCreator = class extends BaseOrderCreator {
9270
- create(data) {
9990
+ constructor() {
9991
+ super(...arguments);
9992
+ this.orderType = void 0;
9993
+ }
9994
+ /**
9995
+ * Builds the general order
9996
+ * Implements template method hook
9997
+ */
9998
+ buildOrder(data) {
9271
9999
  return {
9272
10000
  ...this.baseOrder(data),
9273
10001
  order_price: data.order_price,
9274
10002
  order_quantity: data.order_quantity
9275
10003
  };
9276
10004
  }
9277
- validate(values, configs) {
10005
+ /**
10006
+ * Runs base validations
10007
+ * Implements template method hook
10008
+ */
10009
+ runValidations(values, configs) {
9278
10010
  return super.baseValidate(values, configs);
9279
10011
  }
9280
10012
  };
@@ -9383,7 +10115,8 @@ function calcScaledOrderBatchBody(order, symbolInfo) {
9383
10115
  distribution_type,
9384
10116
  skew,
9385
10117
  reduce_only,
9386
- visible_quantity
10118
+ visible_quantity,
10119
+ margin_mode
9387
10120
  } = order;
9388
10121
  const prices = calcScaledOrderPrices({
9389
10122
  start_price,
@@ -9409,6 +10142,8 @@ function calcScaledOrderBatchBody(order, symbolInfo) {
9409
10142
  order_quantity: qtys[index],
9410
10143
  order_price: price,
9411
10144
  reduce_only,
10145
+ margin_mode: margin_mode || MarginMode.CROSS,
10146
+ // Default to CROSS if not provided for backward compatibility
9412
10147
  // it will be used for identify the scaled order from ws
9413
10148
  client_order_id: `scaled_${index}_${now}`
9414
10149
  };
@@ -9512,7 +10247,11 @@ var ScaledOrderCreator = class extends BaseOrderCreator {
9512
10247
  super(...arguments);
9513
10248
  this.orderType = OrderType.SCALED;
9514
10249
  }
9515
- create(values, config) {
10250
+ /**
10251
+ * Builds the scaled order
10252
+ * Implements template method hook
10253
+ */
10254
+ buildOrder(values, config) {
9516
10255
  const orders = calcScaledOrderBatchBody(values, config.symbol);
9517
10256
  const { total_orders, distribution_type, skew } = values;
9518
10257
  const order = {
@@ -9530,6 +10269,7 @@ var ScaledOrderCreator = class extends BaseOrderCreator {
9530
10269
  "reduce_only",
9531
10270
  "side",
9532
10271
  "order_type",
10272
+ "margin_mode",
9533
10273
  "orders",
9534
10274
  "total_orders",
9535
10275
  "distribution_type",
@@ -9538,7 +10278,11 @@ var ScaledOrderCreator = class extends BaseOrderCreator {
9538
10278
  order
9539
10279
  );
9540
10280
  }
9541
- async validate(values, config) {
10281
+ /**
10282
+ * Runs validations for scaled order
10283
+ * Implements template method hook
10284
+ */
10285
+ runValidations(values, config) {
9542
10286
  const { maxQty, askAndBid, markPrice, symbol } = config;
9543
10287
  const { base_dp, quote_dp } = config.symbol;
9544
10288
  const { order_quantity, total, total_orders, distribution_type, skew } = values;
@@ -9607,22 +10351,22 @@ function validatePrice(values, config) {
9607
10351
  if (!config.markPrice) {
9608
10352
  return errors;
9609
10353
  }
9610
- const { minPrice: minPrice3, maxPrice: maxPrice3 } = getPriceRange({
10354
+ const { minPrice, maxPrice } = getPriceRange({
9611
10355
  side: values.side,
9612
10356
  basePrice: config.markPrice,
9613
10357
  symbolInfo: config.symbol
9614
10358
  });
9615
10359
  const comparePrice = (key, value) => {
9616
10360
  const price = new Decimal(value || 0);
9617
- if (price.lt(minPrice3)) {
10361
+ if (price.lt(minPrice)) {
9618
10362
  errors[key] = OrderValidation.min(
9619
10363
  key,
9620
- new Decimal(minPrice3).todp(quote_dp).toString()
10364
+ new Decimal(minPrice).todp(quote_dp).toString()
9621
10365
  );
9622
- } else if (price.gt(maxPrice3)) {
10366
+ } else if (price.gt(maxPrice)) {
9623
10367
  errors[key] = OrderValidation.max(
9624
10368
  key,
9625
- new Decimal(maxPrice3).todp(quote_dp).toString()
10369
+ new Decimal(maxPrice).todp(quote_dp).toString()
9626
10370
  );
9627
10371
  }
9628
10372
  };
@@ -9630,13 +10374,40 @@ function validatePrice(values, config) {
9630
10374
  comparePrice("end_price", end_price);
9631
10375
  return errors;
9632
10376
  }
9633
- var { maxPrice: maxPrice2, minPrice: minPrice2, scopePrice: scopePrice2 } = order;
10377
+
10378
+ // src/services/orderCreator/validators/TriggerPriceValidator.ts
10379
+ var TriggerPriceValidator = class extends BaseValidator {
10380
+ constructor() {
10381
+ super();
10382
+ this.strategy = new TriggerPriceValidationStrategy();
10383
+ }
10384
+ doValidate(values, config) {
10385
+ return this.strategy.validate(
10386
+ {
10387
+ trigger_price: values.trigger_price
10388
+ },
10389
+ config
10390
+ );
10391
+ }
10392
+ getFieldName() {
10393
+ return "trigger_price";
10394
+ }
10395
+ };
10396
+
10397
+ // src/services/orderCreator/stopLimitOrderCreator.ts
9634
10398
  var StopLimitOrderCreator = class extends BaseOrderCreator {
9635
10399
  constructor() {
9636
10400
  super(...arguments);
10401
+ this.priceValidationStrategy = new PriceValidationStrategy();
10402
+ this.triggerPriceValidationStrategy = new TriggerPriceValidationStrategy();
10403
+ this.validationChain = new ValidationChain().addValidator(new QuantityValidator()).addValidator(new TriggerPriceValidator()).addValidator(new PriceValidator());
9637
10404
  this.orderType = OrderType.STOP_LIMIT;
9638
10405
  }
9639
- create(values, config) {
10406
+ /**
10407
+ * Builds the stop-limit order
10408
+ * Implements template method hook
10409
+ */
10410
+ buildOrder(values, config) {
9640
10411
  this.totalToQuantity(values, config);
9641
10412
  const order = {
9642
10413
  ...this.baseOrder(values),
@@ -9658,84 +10429,82 @@ var StopLimitOrderCreator = class extends BaseOrderCreator {
9658
10429
  "trigger_price_type",
9659
10430
  "side",
9660
10431
  "reduce_only",
10432
+ "margin_mode",
9661
10433
  "visible_quantity"
9662
10434
  ],
9663
10435
  order
9664
10436
  );
9665
10437
  }
9666
- validate(values, config) {
9667
- return this.baseValidate(values, config).then((errors) => {
9668
- const { order_price, trigger_price, side } = values;
9669
- const { symbol } = config;
9670
- const { price_range, price_scope, quote_max, quote_min } = symbol;
9671
- if (!order_price) {
9672
- errors.order_price = OrderValidation.required("order_price");
9673
- }
9674
- if (!trigger_price) {
9675
- errors.trigger_price = OrderValidation.required("trigger_price");
9676
- } else {
9677
- if (trigger_price > quote_max) {
9678
- errors.trigger_price = OrderValidation.max(
9679
- "trigger_price",
9680
- quote_max
9681
- );
9682
- } else if (trigger_price < quote_min || trigger_price == 0) {
9683
- errors.trigger_price = OrderValidation.min(
9684
- "trigger_price",
9685
- quote_min
9686
- );
9687
- } else if (order_price) {
9688
- const price = new Decimal(order_price);
9689
- const maxPriceNumber = maxPrice2(trigger_price, price_range);
9690
- const minPriceNumber = minPrice2(trigger_price, price_range);
9691
- const scropePriceNumbere = scopePrice2(
9692
- trigger_price,
9693
- price_scope,
9694
- side
9695
- );
9696
- const priceRange = side === "BUY" ? {
9697
- min: scropePriceNumbere,
9698
- max: maxPriceNumber
9699
- } : {
9700
- min: minPriceNumber,
9701
- max: scropePriceNumbere
9702
- };
9703
- if (price.gt(quote_max)) {
9704
- errors.order_price = OrderValidation.max("order_price", quote_max);
9705
- } else {
9706
- if (price.gt(priceRange?.max)) {
9707
- errors.order_price = OrderValidation.max(
9708
- "order_price",
9709
- new Decimal(priceRange.max).todp(symbol.quote_dp).toString()
9710
- );
9711
- }
9712
- }
9713
- if (price.lt(quote_min)) {
9714
- errors.order_price = OrderValidation.min("order_price", quote_min);
9715
- } else {
9716
- if (price.lt(priceRange?.min)) {
9717
- errors.order_price = OrderValidation.min(
9718
- "order_price",
9719
- new Decimal(priceRange.min).todp(symbol.quote_dp).toString()
9720
- );
9721
- }
9722
- }
9723
- }
10438
+ /**
10439
+ * Runs validations using validation chain
10440
+ * Implements template method hook
10441
+ */
10442
+ runValidations(values, config) {
10443
+ const orderlyValues = values;
10444
+ const errors = this.baseValidate(orderlyValues, config);
10445
+ const triggerPrice = values.trigger_price;
10446
+ if (!triggerPrice || triggerPrice === 0) {
10447
+ errors.trigger_price = OrderValidation.required("trigger_price");
10448
+ } else {
10449
+ const triggerError = this.triggerPriceValidationStrategy.validate(
10450
+ { trigger_price: triggerPrice },
10451
+ config
10452
+ );
10453
+ if (triggerError) {
10454
+ errors.trigger_price = triggerError;
10455
+ }
10456
+ }
10457
+ const valuesWithFields = values;
10458
+ const orderPrice = valuesWithFields.order_price ?? valuesWithFields.price;
10459
+ const triggerPriceForPriceValidation = triggerPrice;
10460
+ const side = valuesWithFields.side ?? orderlyValues.side;
10461
+ if (!orderPrice) {
10462
+ errors.order_price = OrderValidation.required("order_price");
10463
+ } else if (orderPrice && triggerPriceForPriceValidation && side) {
10464
+ const modifiedConfig = {
10465
+ ...config,
10466
+ markPrice: Number(triggerPriceForPriceValidation)
10467
+ };
10468
+ const priceError = this.priceValidationStrategy.validate(
10469
+ {
10470
+ order_price: orderPrice,
10471
+ side,
10472
+ order_type: OrderType.LIMIT
10473
+ },
10474
+ modifiedConfig
10475
+ );
10476
+ if (priceError) {
10477
+ errors.order_price = priceError;
9724
10478
  }
9725
- return errors;
9726
- });
10479
+ } else if (orderPrice && triggerPriceForPriceValidation) {
10480
+ const { quote_max, quote_min } = config.symbol;
10481
+ const price = Number(orderPrice);
10482
+ if (quote_max && price > quote_max) {
10483
+ errors.order_price = OrderValidation.max("order_price", quote_max);
10484
+ } else if (quote_min && price < quote_min) {
10485
+ errors.order_price = OrderValidation.min("order_price", quote_min);
10486
+ }
10487
+ }
10488
+ return errors;
9727
10489
  }
9728
10490
  };
9729
10491
  var StopMarketOrderCreator = class extends BaseOrderCreator {
9730
- create(values) {
10492
+ constructor() {
10493
+ super(...arguments);
10494
+ this.triggerPriceValidationStrategy = new TriggerPriceValidationStrategy();
10495
+ this.validationChain = new ValidationChain().addValidator(new QuantityValidator()).addValidator(new TriggerPriceValidator());
10496
+ }
10497
+ /**
10498
+ * Builds the stop-market order
10499
+ * Implements template method hook
10500
+ */
10501
+ buildOrder(values) {
9731
10502
  const order = {
9732
10503
  ...this.baseOrder(values),
9733
- // order_price: values.order_price,
9734
10504
  trigger_price: values.trigger_price,
9735
10505
  algo_type: AlgoOrderRootType.STOP,
9736
10506
  type: OrderType.MARKET,
9737
10507
  quantity: values["order_quantity"],
9738
- // price: values["order_price"],
9739
10508
  trigger_price_type: TriggerPriceType.MARK_PRICE
9740
10509
  };
9741
10510
  return pick(
@@ -9745,225 +10514,40 @@ var StopMarketOrderCreator = class extends BaseOrderCreator {
9745
10514
  "algo_type",
9746
10515
  "type",
9747
10516
  "quantity",
9748
- // "price",
9749
10517
  "trigger_price_type",
9750
10518
  "side",
9751
10519
  "reduce_only",
10520
+ "margin_mode",
9752
10521
  "visible_quantity"
9753
10522
  ],
9754
10523
  order
9755
10524
  );
9756
10525
  }
9757
- validate(values, config) {
9758
- return this.baseValidate(values, config).then((errors) => {
9759
- const { trigger_price } = values;
9760
- const { symbol } = config;
9761
- const { quote_max, quote_min } = symbol;
9762
- if (!trigger_price) {
9763
- errors.trigger_price = OrderValidation.required("trigger_price");
9764
- } else if (trigger_price > quote_max) {
9765
- errors.trigger_price = OrderValidation.max("trigger_price", quote_max);
9766
- } else if (trigger_price < quote_min || trigger_price == 0) {
9767
- errors.trigger_price = OrderValidation.min("trigger_price", quote_min);
9768
- }
9769
- return errors;
9770
- });
10526
+ /**
10527
+ * Runs validations using validation chain
10528
+ * Implements template method hook
10529
+ */
10530
+ runValidations(values, config) {
10531
+ const errors = this.baseValidate(values, config);
10532
+ const chainErrors = this.validationChain.validate(values, config);
10533
+ Object.assign(errors, chainErrors);
10534
+ return errors;
9771
10535
  }
9772
10536
  };
9773
- var formatPrice2 = (price, quote_dp) => {
9774
- return new Decimal(price).toDecimalPlaces(quote_dp).toNumber();
9775
- };
10537
+
10538
+ // src/services/orderCreator/baseAlgoCreator.ts
9776
10539
  var BaseAlgoOrderCreator = class {
10540
+ constructor() {
10541
+ this.tpslValidationStrategy = new TPSLValidationStrategy();
10542
+ }
9777
10543
  /**
9778
- * base validate
10544
+ * Validates TP/SL order using TPSLValidationStrategy
10545
+ * Consolidates validation logic from baseBracketOrderCreator
9779
10546
  */
9780
10547
  validate(values, config) {
9781
- const result = /* @__PURE__ */ Object.create(null);
9782
- return Promise.resolve().then(() => {
9783
- const {
9784
- tp_trigger_price,
9785
- sl_trigger_price,
9786
- side,
9787
- // tp_enable,
9788
- // sl_enable,
9789
- tp_order_type,
9790
- sl_order_type,
9791
- tp_order_price,
9792
- sl_order_price
9793
- } = values;
9794
- const qty = Number(values.quantity);
9795
- const maxQty = config.maxQty;
9796
- const orderType = values.order_type;
9797
- const {
9798
- quote_max,
9799
- quote_min,
9800
- price_scope,
9801
- quote_dp,
9802
- base_min,
9803
- min_notional
9804
- } = config.symbol ?? {};
9805
- if (!isNaN(qty) && qty > maxQty) {
9806
- result.quantity = OrderValidation.max("quantity", config.maxQty);
9807
- }
9808
- if (!isNaN(qty) && qty < base_min) {
9809
- result.quantity = OrderValidation.min("quantity", base_min);
9810
- }
9811
- if (Number(tp_trigger_price) < 0) {
9812
- result.tp_trigger_price = OrderValidation.min("tp_trigger_price", 0);
9813
- }
9814
- if (Number(sl_trigger_price) < 0) {
9815
- result.sl_trigger_price = OrderValidation.min("sl_trigger_price", 0);
9816
- }
9817
- if (tp_order_type === OrderType.LIMIT && !tp_order_price) {
9818
- result.tp_order_price = OrderValidation.required("tp_order_price");
9819
- }
9820
- if (sl_order_type === OrderType.LIMIT && !sl_order_price) {
9821
- result.sl_order_price = OrderValidation.required("sl_order_price");
9822
- }
9823
- const mark_price = orderType === OrderType.MARKET || orderType == null ? config.markPrice : values.order_price ? Number(values.order_price) : void 0;
9824
- const tpslSide = side === OrderSide.BUY ? OrderSide.SELL : OrderSide.BUY;
9825
- if (side === OrderSide.BUY && mark_price) {
9826
- if (!!sl_trigger_price && Number(sl_trigger_price) < quote_min) {
9827
- result.sl_trigger_price = OrderValidation.min(
9828
- "sl_trigger_price",
9829
- formatPrice2(quote_min, quote_dp)
9830
- );
9831
- }
9832
- if (!!sl_trigger_price && Number(sl_trigger_price) >= mark_price) {
9833
- result.sl_trigger_price = OrderValidation.max(
9834
- "sl_trigger_price",
9835
- formatPrice2(mark_price, quote_dp)
9836
- );
9837
- }
9838
- if (!!tp_trigger_price && Number(tp_trigger_price) <= mark_price) {
9839
- result.tp_trigger_price = OrderValidation.min(
9840
- "tp_trigger_price",
9841
- formatPrice2(mark_price, quote_dp)
9842
- );
9843
- }
9844
- if (!!tp_trigger_price && Number(tp_trigger_price) > quote_max) {
9845
- result.tp_trigger_price = OrderValidation.max(
9846
- "tp_trigger_price",
9847
- formatPrice2(quote_max, quote_dp)
9848
- );
9849
- }
9850
- if (sl_trigger_price && sl_order_price) {
9851
- const slOrderPriceRange = getPriceRange({
9852
- side: tpslSide,
9853
- basePrice: Number(sl_trigger_price),
9854
- symbolInfo: config.symbol
9855
- });
9856
- if (Number(sl_order_price) < slOrderPriceRange.minPrice) {
9857
- result.sl_order_price = OrderValidation.min(
9858
- "sl_order_price",
9859
- formatPrice2(slOrderPriceRange.minPrice, quote_dp)
9860
- );
9861
- }
9862
- if (Number(sl_order_price) > slOrderPriceRange.maxPrice) {
9863
- result.sl_order_price = OrderValidation.max(
9864
- "sl_order_price",
9865
- formatPrice2(slOrderPriceRange.maxPrice, quote_dp)
9866
- );
9867
- }
9868
- if (Number(sl_trigger_price) < Number(sl_order_price)) {
9869
- result.sl_trigger_price = OrderValidation.priceErrorMax("sl_trigger_price");
9870
- }
9871
- }
9872
- if (tp_trigger_price && tp_order_price) {
9873
- const tpOrderPriceRange = getPriceRange({
9874
- side: tpslSide,
9875
- basePrice: Number(tp_trigger_price),
9876
- symbolInfo: config.symbol
9877
- });
9878
- if (Number(tp_order_price) > tpOrderPriceRange.maxPrice) {
9879
- result.tp_order_price = OrderValidation.max(
9880
- "tp_order_price",
9881
- formatPrice2(tpOrderPriceRange.maxPrice, quote_dp)
9882
- );
9883
- }
9884
- if (Number(tp_order_price) < tpOrderPriceRange.minPrice) {
9885
- result.tp_order_price = OrderValidation.min(
9886
- "tp_order_price",
9887
- formatPrice2(tpOrderPriceRange.minPrice, quote_dp)
9888
- );
9889
- }
9890
- if (Number(tp_trigger_price) > Number(tp_order_price)) {
9891
- result.tp_trigger_price = OrderValidation.priceErrorMin("tp_trigger_price");
9892
- }
9893
- }
9894
- }
9895
- if (side === OrderSide.SELL && mark_price) {
9896
- if (!!sl_trigger_price && Number(sl_trigger_price) > quote_max) {
9897
- result.sl_trigger_price = OrderValidation.max(
9898
- "sl_trigger_price",
9899
- formatPrice2(quote_max, quote_dp)
9900
- );
9901
- }
9902
- if (!!sl_trigger_price && Number(sl_trigger_price) <= mark_price) {
9903
- result.sl_trigger_price = OrderValidation.min(
9904
- "sl_trigger_price",
9905
- formatPrice2(mark_price, quote_dp)
9906
- );
9907
- }
9908
- if (!!tp_trigger_price && Number(tp_trigger_price) >= mark_price) {
9909
- result.tp_trigger_price = OrderValidation.max(
9910
- "tp_trigger_price",
9911
- formatPrice2(mark_price, quote_dp)
9912
- );
9913
- }
9914
- if (!!tp_trigger_price && Number(tp_trigger_price) < quote_min) {
9915
- result.tp_trigger_price = OrderValidation.min(
9916
- "tp_trigger_price",
9917
- formatPrice2(quote_min, quote_dp)
9918
- );
9919
- }
9920
- if (sl_trigger_price && sl_order_price) {
9921
- const slOrderPriceRange = getPriceRange({
9922
- side: tpslSide,
9923
- basePrice: Number(sl_trigger_price),
9924
- symbolInfo: config.symbol
9925
- });
9926
- if (Number(sl_order_price) < slOrderPriceRange.minPrice) {
9927
- result.sl_order_price = OrderValidation.min(
9928
- "sl_order_price",
9929
- formatPrice2(slOrderPriceRange.minPrice, quote_dp)
9930
- );
9931
- }
9932
- if (Number(sl_order_price) > slOrderPriceRange.maxPrice) {
9933
- result.sl_order_price = OrderValidation.max(
9934
- "sl_order_price",
9935
- formatPrice2(slOrderPriceRange.maxPrice, quote_dp)
9936
- );
9937
- }
9938
- if (Number(sl_trigger_price) > Number(sl_order_price)) {
9939
- result.sl_trigger_price = OrderValidation.priceErrorMin("sl_trigger_price");
9940
- }
9941
- }
9942
- if (tp_trigger_price && tp_order_price) {
9943
- const tpOrderPriceRange = getPriceRange({
9944
- side: tpslSide,
9945
- basePrice: Number(tp_trigger_price),
9946
- symbolInfo: config.symbol
9947
- });
9948
- if (Number(tp_order_price) < tpOrderPriceRange.minPrice) {
9949
- result.tp_order_price = OrderValidation.min(
9950
- "tp_order_price",
9951
- formatPrice2(tpOrderPriceRange.minPrice, quote_dp)
9952
- );
9953
- }
9954
- if (Number(tp_order_price) > tpOrderPriceRange.maxPrice) {
9955
- result.tp_order_price = OrderValidation.max(
9956
- "tp_order_price",
9957
- formatPrice2(tpOrderPriceRange.maxPrice, quote_dp)
9958
- );
9959
- }
9960
- if (Number(tp_trigger_price) < Number(tp_order_price)) {
9961
- result.tp_trigger_price = OrderValidation.priceErrorMax("tp_trigger_price");
9962
- }
9963
- }
9964
- }
9965
- return Object.keys(result).length > 0 ? result : null;
9966
- });
10548
+ return Promise.resolve(
10549
+ this.tpslValidationStrategy.validate(values, config)
10550
+ );
9967
10551
  }
9968
10552
  };
9969
10553
 
@@ -10016,7 +10600,9 @@ var TPSLOrderCreator = class extends BaseAlgoOrderCreator {
10016
10600
  reduce_only: true,
10017
10601
  quantity: values.quantity,
10018
10602
  symbol: values.symbol,
10019
- child_orders
10603
+ child_orders,
10604
+ // Include margin_mode for isolated/cross margin support; default CROSS per order entry pattern
10605
+ margin_mode: values.margin_mode || MarginMode.CROSS
10020
10606
  };
10021
10607
  }
10022
10608
  crateUpdateOrder(values, oldValue, config) {
@@ -10118,7 +10704,9 @@ var TPSLPositionOrderCreator = class extends BaseAlgoOrderCreator {
10118
10704
  trigger_price_type: TriggerPriceType.MARK_PRICE,
10119
10705
  // reduce_only: true,
10120
10706
  symbol: values.symbol,
10121
- child_orders
10707
+ child_orders,
10708
+ // Include margin_mode for isolated/cross margin support; default CROSS per order entry pattern
10709
+ margin_mode: values.margin_mode || MarginMode.CROSS
10122
10710
  };
10123
10711
  }
10124
10712
  crateUpdateOrder(values, oldValue, config) {
@@ -10155,7 +10743,11 @@ var TrailingStopOrderCreator = class extends BaseOrderCreator {
10155
10743
  super(...arguments);
10156
10744
  this.orderType = OrderType.TRAILING_STOP;
10157
10745
  }
10158
- create(values, config) {
10746
+ /**
10747
+ * Builds the trailing stop order
10748
+ * Implements template method hook
10749
+ */
10750
+ buildOrder(values, config) {
10159
10751
  const { order_quantity, activated_price, callback_value, callback_rate } = values;
10160
10752
  const order = {
10161
10753
  ...this.baseOrder(values),
@@ -10176,6 +10768,7 @@ var TrailingStopOrderCreator = class extends BaseOrderCreator {
10176
10768
  "quantity",
10177
10769
  "side",
10178
10770
  "reduce_only",
10771
+ "margin_mode",
10179
10772
  "visible_quantity",
10180
10773
  "activated_price",
10181
10774
  "callback_value",
@@ -10184,28 +10777,34 @@ var TrailingStopOrderCreator = class extends BaseOrderCreator {
10184
10777
  order
10185
10778
  );
10186
10779
  }
10187
- async validate(values, config) {
10780
+ /**
10781
+ * Runs validations for trailing stop order
10782
+ * Implements template method hook
10783
+ */
10784
+ runValidations(values, config) {
10188
10785
  const { markPrice, symbol } = config;
10189
10786
  const { quote_dp } = config.symbol;
10190
10787
  const { side, activated_price, callback_value, callback_rate } = values;
10191
- const errors = await this.baseValidate(values, config);
10788
+ const errors = this.baseValidate(values, config);
10192
10789
  if (activated_price) {
10193
- const { minPrice: minPrice3, maxPrice: maxPrice3 } = getPriceRange2({
10790
+ const { minPrice, maxPrice } = getPriceRange({
10194
10791
  side,
10195
- markPrice,
10792
+ basePrice: markPrice,
10196
10793
  symbolInfo: symbol
10197
10794
  });
10198
- const activatedPrice = new Decimal(activated_price);
10199
- if (activatedPrice.lt(minPrice3) || activatedPrice.equals(0)) {
10200
- errors.activated_price = OrderValidation.min(
10201
- "activated_price",
10202
- new Decimal(minPrice3).todp(quote_dp).toString()
10203
- );
10204
- } else if (activatedPrice.gt(maxPrice3)) {
10205
- errors.activated_price = OrderValidation.max(
10206
- "activated_price",
10207
- new Decimal(maxPrice3).todp(quote_dp).toString()
10208
- );
10795
+ if (!isNaN(minPrice) && !isNaN(maxPrice)) {
10796
+ const activatedPrice = new Decimal(activated_price);
10797
+ if (activatedPrice.lt(minPrice) || activatedPrice.equals(0)) {
10798
+ errors.activated_price = OrderValidation.min(
10799
+ "activated_price",
10800
+ new Decimal(minPrice).todp(quote_dp).toString()
10801
+ );
10802
+ } else if (activatedPrice.gt(maxPrice)) {
10803
+ errors.activated_price = OrderValidation.max(
10804
+ "activated_price",
10805
+ new Decimal(maxPrice).todp(quote_dp).toString()
10806
+ );
10807
+ }
10209
10808
  }
10210
10809
  }
10211
10810
  if (!callback_value && !callback_rate) {
@@ -10237,23 +10836,6 @@ var TrailingStopOrderCreator = class extends BaseOrderCreator {
10237
10836
  return errors;
10238
10837
  }
10239
10838
  };
10240
- function getPriceRange2(inputs) {
10241
- const { markPrice, side, symbolInfo } = inputs;
10242
- const { quote_min, quote_max } = symbolInfo;
10243
- const priceRange = side === OrderSide.BUY ? {
10244
- min: quote_min,
10245
- max: markPrice
10246
- } : {
10247
- min: markPrice,
10248
- max: quote_max
10249
- };
10250
- const minPrice3 = Math.max(quote_min, priceRange?.min);
10251
- const maxPrice3 = Math.min(quote_max, priceRange?.max);
10252
- return {
10253
- minPrice: minPrice3,
10254
- maxPrice: maxPrice3
10255
- };
10256
- }
10257
10839
 
10258
10840
  // src/services/orderCreator/factory.ts
10259
10841
  var OrderFactory = class {
@@ -10376,27 +10958,63 @@ var calcEstLiqPrice = (order$1, askAndBid, inputs) => {
10376
10958
  markPrice,
10377
10959
  totalCollateral,
10378
10960
  futures_taker_fee_rate,
10379
- positions: positions3
10961
+ positions: positions3,
10962
+ symbolLeverage,
10963
+ sumUnitaryFunding
10380
10964
  } = inputs;
10381
10965
  const orderFee = order.orderFee({
10382
10966
  qty: quantity,
10383
10967
  price,
10384
10968
  futuresTakeFeeRate: Number(futures_taker_fee_rate) / 1e4
10385
10969
  });
10386
- const liqPrice = order.estLiqPrice({
10387
- markPrice,
10388
- baseIMR: symbolInfo.base_imr,
10389
- baseMMR: symbolInfo.base_mmr,
10390
- totalCollateral,
10391
- positions: positions3 == null ? [] : positions3,
10392
- IMR_Factor: imr_factor,
10393
- orderFee,
10394
- newOrder: {
10395
- qty: quantity,
10396
- price,
10397
- symbol
10970
+ let liqPrice = 0;
10971
+ if (order$1.margin_mode === MarginMode.CROSS) {
10972
+ liqPrice = order.estLiqPrice({
10973
+ markPrice,
10974
+ baseIMR: symbolInfo.base_imr,
10975
+ baseMMR: symbolInfo.base_mmr,
10976
+ totalCollateral,
10977
+ positions: positions3 == null ? [] : positions3,
10978
+ IMR_Factor: imr_factor,
10979
+ orderFee,
10980
+ newOrder: {
10981
+ qty: quantity,
10982
+ price,
10983
+ symbol
10984
+ }
10985
+ });
10986
+ } else {
10987
+ let isolatedPositionMargin = 0, costPosition = 0, positionQty = 0, lastSumUnitaryFunding = 0, leverage = symbolLeverage ?? 1;
10988
+ if (positions3) {
10989
+ const position = positions3.find(
10990
+ (p) => p.symbol === symbol && p.margin_mode === MarginMode.ISOLATED
10991
+ );
10992
+ if (position) {
10993
+ isolatedPositionMargin = position.margin ?? 0;
10994
+ costPosition = position.cost_position ?? 0;
10995
+ positionQty = position.position_qty ?? 0;
10996
+ lastSumUnitaryFunding = position.last_sum_unitary_funding ?? 0;
10997
+ leverage = position.leverage ? Number(position.leverage) : 1;
10998
+ }
10398
10999
  }
10399
- });
11000
+ liqPrice = order.estLiqPriceIsolated({
11001
+ isolatedPositionMargin,
11002
+ costPosition,
11003
+ positionQty,
11004
+ sumUnitaryFunding,
11005
+ lastSumUnitaryFunding,
11006
+ markPrice,
11007
+ baseIMR: symbolInfo.base_imr,
11008
+ baseMMR: symbolInfo.base_mmr,
11009
+ IMR_Factor: imr_factor,
11010
+ leverage,
11011
+ newOrder: {
11012
+ symbol,
11013
+ qty: quantity,
11014
+ price
11015
+ }
11016
+ });
11017
+ }
10400
11018
  if (liqPrice <= 0) return null;
10401
11019
  return liqPrice;
10402
11020
  };
@@ -10454,7 +11072,9 @@ var useTaskProfitAndStopLossInternal = (position, options) => {
10454
11072
  // sl_enable: isEditing
10455
11073
  // ? checkIsEnableTpSL(options?.defaultOrder).sl_enable
10456
11074
  // : options?.tpslEnable?.sl_enable,
10457
- position_type: options?.positionType
11075
+ position_type: options?.positionType,
11076
+ // Use defaultOrder.margin_mode when editing; otherwise position.margin_mode; default CROSS for backward compatibility
11077
+ margin_mode: options?.defaultOrder?.margin_mode ?? position?.margin_mode ?? MarginMode.CROSS
10458
11078
  });
10459
11079
  const symbolInfo = useSymbolsInfo()[position.symbol]();
10460
11080
  const { data: markPrice } = useMarkPrice(order.symbol);
@@ -10757,11 +11377,53 @@ var useMaxLeverage = (symbol) => {
10757
11377
  };
10758
11378
  var useSymbolLeverage = (symbol) => {
10759
11379
  const symbolInfo = useSymbolInfo(symbol);
10760
- const [update, { isMutating }] = useMutation("/v1/client/leverage");
11380
+ const { state } = useAccount();
11381
+ const [updateMutation, { isMutating }] = useMutation("/v1/client/leverage");
10761
11382
  const maxLeverage = useMemo(() => {
10762
11383
  const baseIMR = symbolInfo?.("base_imr");
10763
11384
  return baseIMR ? 1 / baseIMR : 1;
10764
11385
  }, [symbolInfo]);
11386
+ const update = async (data) => {
11387
+ const result = await updateMutation(data);
11388
+ if (result?.success && data.symbol && state.accountId) {
11389
+ const key = ["/v1/client/leverages", state.accountId];
11390
+ mutate(
11391
+ key,
11392
+ (prev) => {
11393
+ if (!prev) {
11394
+ return [
11395
+ {
11396
+ symbol: data.symbol,
11397
+ leverage: data.leverage,
11398
+ margin_mode: data.margin_mode
11399
+ }
11400
+ ];
11401
+ }
11402
+ const index = prev.findIndex(
11403
+ (item) => item.symbol === data.symbol && (item.margin_mode ?? MarginMode.CROSS) === (data.margin_mode ?? MarginMode.CROSS)
11404
+ );
11405
+ if (index === -1) {
11406
+ return [
11407
+ ...prev,
11408
+ {
11409
+ symbol: data.symbol,
11410
+ leverage: data.leverage,
11411
+ margin_mode: data.margin_mode
11412
+ }
11413
+ ];
11414
+ }
11415
+ const next = [...prev];
11416
+ next[index] = {
11417
+ ...next[index],
11418
+ leverage: data.leverage
11419
+ };
11420
+ return next;
11421
+ },
11422
+ { revalidate: false }
11423
+ );
11424
+ }
11425
+ return result;
11426
+ };
10765
11427
  return {
10766
11428
  maxLeverage,
10767
11429
  update,
@@ -11498,8 +12160,8 @@ function useOrderEntry(symbolOrOrder, sideOrOptions, reduceOnly, options) {
11498
12160
  const keys = Object.keys(current);
11499
12161
  for (let i = 0; i < keys.length; i++) {
11500
12162
  const k = keys[i];
11501
- let preveValue = prev[k];
11502
- let currentValue = current[k];
12163
+ const preveValue = prev[k];
12164
+ const currentValue = current[k];
11503
12165
  if (typeof preveValue === "undefined" && typeof currentValue === "undefined")
11504
12166
  continue;
11505
12167
  if (preveValue !== currentValue) {
@@ -11512,7 +12174,12 @@ function useOrderEntry(symbolOrOrder, sideOrOptions, reduceOnly, options) {
11512
12174
  if (!key) return null;
11513
12175
  return { key, value, preValue };
11514
12176
  };
11515
- const maxQty = useMaxQty(symbol, sideValue, isReduceOnly);
12177
+ const { marginMode: symbolMarginMode } = useMarginModeBySymbol(symbol);
12178
+ const marginMode = typeof symbolOrOrder === "object" && symbolOrOrder.margin_mode ? symbolOrOrder.margin_mode : symbolMarginMode;
12179
+ const maxQty = useMaxQty(symbol, sideValue, {
12180
+ reduceOnly: isReduceOnly,
12181
+ marginMode: marginMode ?? MarginMode.CROSS
12182
+ });
11516
12183
  const parseString2Number = (order, key, dp) => {
11517
12184
  if (typeof order[key] !== "string") return;
11518
12185
  if (order[key] && order[key].startsWith(".")) {
@@ -12063,7 +12730,7 @@ var DataPaint = class extends BasePaint {
12063
12730
  );
12064
12731
  const { position, fontSize = 14 } = layout;
12065
12732
  let left = this._ratio(position.left);
12066
- let top = layout.position.top + offsetTop + this.transformTop;
12733
+ const top = layout.position.top + offsetTop + this.transformTop;
12067
12734
  let prevElementBoundingBox = {};
12068
12735
  if (typeof options.data?.position.side !== "undefined") {
12069
12736
  prevElementBoundingBox = this._drawText(options.data.position.side, {
@@ -12094,6 +12761,28 @@ var DataPaint = class extends BasePaint {
12094
12761
  fontFamily: options.fontFamily
12095
12762
  });
12096
12763
  }
12764
+ const marginMode = options.data?.position.marginMode;
12765
+ if (marginMode) {
12766
+ left += (prevElementBoundingBox.width ?? 0) + this._ratio(7);
12767
+ if (prevElementBoundingBox.width) {
12768
+ prevElementBoundingBox = this._drawText("|", {
12769
+ color: "rgba(255,255,255,0.2)",
12770
+ left,
12771
+ top: this._ratio(top),
12772
+ fontSize: this._ratio(fontSize),
12773
+ fontFamily: options.fontFamily
12774
+ });
12775
+ }
12776
+ left += (prevElementBoundingBox.width ?? 0) + this._ratio(7);
12777
+ const marginModeText = marginMode.charAt(0).toUpperCase() + marginMode.slice(1);
12778
+ prevElementBoundingBox = this._drawText(marginModeText, {
12779
+ color: layout.color,
12780
+ left,
12781
+ top: this._ratio(top),
12782
+ fontSize: this._ratio(fontSize),
12783
+ fontFamily: options.fontFamily
12784
+ });
12785
+ }
12097
12786
  if (typeof options.data?.position.leverage !== "undefined") {
12098
12787
  left += (prevElementBoundingBox.width ?? 0) + this._ratio(7);
12099
12788
  if (prevElementBoundingBox.width) {
@@ -12174,8 +12863,8 @@ var DataPaint = class extends BasePaint {
12174
12863
  (options.data?.position.informations.length ?? 0) === 2;
12175
12864
  const col = informations.length > 4 ? 3 : 2;
12176
12865
  informations.forEach((info, index) => {
12177
- let left = position.left + index % col * this.positionInfoCellWidth;
12178
- let top = position.top + Math.floor(index / col) * 38 + this.transformTop;
12866
+ const left = position.left + index % col * this.positionInfoCellWidth;
12867
+ const top = position.top + Math.floor(index / col) * 38 + this.transformTop;
12179
12868
  this._drawText(info.title, {
12180
12869
  left: this._ratio(left),
12181
12870
  top: this._ratio(top),
@@ -17717,95 +18406,111 @@ var initialOrderState = {
17717
18406
  trigger_price: "",
17718
18407
  tp_trigger_price: "",
17719
18408
  sl_trigger_price: "",
17720
- tp_order_type: OrderType.MARKET,
17721
- tp_pnl: "",
17722
- sl_pnl: "",
17723
- tp_offset_percentage: "",
17724
- sl_offset_percentage: "",
17725
- tp_offset: "",
17726
- sl_offset: "",
17727
- sl_order_type: OrderType.MARKET,
17728
18409
  total: "",
17729
- // scaled order
17730
- start_price: "",
17731
- end_price: "",
17732
- totalOrders: "",
17733
- distribution_type: "",
17734
- skew: "",
17735
- // symbol: "",
17736
- // trailing stop order
17737
- activated_price: "",
17738
- callback_value: "",
17739
- callback_rate: ""
18410
+ symbol: ""
17740
18411
  };
17741
- var useOrderStore = (initialOrder) => {
17742
- const [entry, setEntry] = useState(initialOrder);
17743
- const [estLeverage, setEstLeverage] = useState(null);
17744
- const [estLiquidationPrice, setEstLiquidationPrice] = useState(
17745
- null
17746
- );
17747
- const [errors, setErrors] = useState({});
17748
- const updateOrder = (order) => {
17749
- setEntry(
17750
- // if use {...draft, ...order} will cause extra updated when object it not changed
17751
- produce((draft) => {
17752
- Object.assign(draft, order);
17753
- })
17754
- // (prev) => ({ ...prev, ...order })
17755
- );
17756
- };
17757
- const updateOrderByKey = (key, value) => {
17758
- setEntry(
17759
- produce((draft) => {
17760
- draft[key] = value;
17761
- })
17762
- );
17763
- };
17764
- const restoreOrder = (order) => {
17765
- setEntry(produce((draft) => order));
17766
- };
17767
- const updateOrderComputed = (data) => {
17768
- setEstLeverage(data.estLeverage);
17769
- setEstLiquidationPrice(data.estLiquidationPrice);
17770
- };
17771
- const resetOrder = (order) => {
17772
- setEntry(
17773
- produce((draft) => ({
17774
- ...draft,
17775
- ...order ?? initialOrderState
17776
- }))
17777
- );
17778
- };
17779
- const hasTP_SL = () => {
17780
- return typeof entry.tp_trigger_price !== "undefined" || typeof entry.sl_trigger_price !== "undefined";
17781
- };
17782
- return {
17783
- entry,
17784
- estLeverage,
17785
- estLiquidationPrice,
17786
- errors,
18412
+ var useOrderStore = create()(
18413
+ immer((set, get3) => ({
18414
+ entry: {
18415
+ side: OrderSide.BUY,
18416
+ order_type: OrderType.LIMIT,
18417
+ ...initialOrderState
18418
+ },
18419
+ estLeverage: null,
18420
+ estLiquidationPrice: null,
18421
+ errors: {},
17787
18422
  actions: {
17788
- updateOrder,
17789
- updateOrderByKey,
17790
- restoreOrder,
17791
- updateOrderComputed,
17792
- resetOrder,
17793
- hasTP_SL
18423
+ initOrder: (symbol, options) => {
18424
+ set((state) => {
18425
+ state.entry = {
18426
+ ...initialOrderState,
18427
+ symbol,
18428
+ side: options?.side ?? OrderSide.BUY,
18429
+ order_type: options?.order_type ?? OrderType.LIMIT,
18430
+ margin_mode: options?.margin_mode ?? MarginMode.CROSS
18431
+ };
18432
+ state.estLeverage = null;
18433
+ state.estLiquidationPrice = null;
18434
+ state.errors = {};
18435
+ });
18436
+ },
18437
+ hasTP_SL: () => {
18438
+ const order = get3().entry;
18439
+ return typeof order.tp_trigger_price !== "undefined" || typeof order.sl_trigger_price !== "undefined";
18440
+ },
18441
+ updateOrderComputed: (data) => {
18442
+ set(
18443
+ (state) => {
18444
+ state.estLeverage = data.estLeverage;
18445
+ state.estLiquidationPrice = data.estLiquidationPrice;
18446
+ },
18447
+ false
18448
+ // "updateOrderComputed"
18449
+ );
18450
+ },
18451
+ updateOrder: (order) => {
18452
+ set(
18453
+ (state) => {
18454
+ state.entry = {
18455
+ ...state.entry,
18456
+ ...order
18457
+ };
18458
+ },
18459
+ false
18460
+ // "updateOrder"
18461
+ );
18462
+ },
18463
+ updateOrderByKey: (key, value) => {
18464
+ set(
18465
+ (state) => {
18466
+ state.entry[key] = value;
18467
+ },
18468
+ false
18469
+ // "updateOrderByKey"
18470
+ );
18471
+ },
18472
+ restoreOrder: (order) => {
18473
+ set(
18474
+ (state) => {
18475
+ state.entry = order;
18476
+ },
18477
+ false
18478
+ // "restoreOrder"
18479
+ );
18480
+ },
18481
+ resetOrder: (_order) => {
18482
+ set(
18483
+ (state) => {
18484
+ state.entry.order_price = "";
18485
+ state.entry.order_quantity = "";
18486
+ state.entry.trigger_price = "";
18487
+ state.entry.total = "";
18488
+ state.entry.tp_trigger_price = "";
18489
+ state.entry.tp_pnl = "";
18490
+ state.entry.tp_offset = "";
18491
+ state.entry.tp_offset_percentage = "";
18492
+ state.entry.sl_trigger_price = "";
18493
+ state.entry.sl_pnl = "";
18494
+ state.entry.sl_offset = "";
18495
+ state.entry.sl_offset_percentage = "";
18496
+ },
18497
+ true
18498
+ // "resetOrder"
18499
+ );
18500
+ }
17794
18501
  }
17795
- };
17796
- };
17797
-
17798
- // src/next/useOrderEntry/useOrderEntry.internal.ts
18502
+ }))
18503
+ );
17799
18504
  var useOrderEntryNextInternal = (symbol, options = {}) => {
17800
18505
  const { symbolInfo, symbolLeverage } = options;
17801
- const initialOrder = {
17802
- side: OrderSide.BUY,
17803
- order_type: OrderType.LIMIT,
17804
- order_price: "",
17805
- symbol,
17806
- ...options.initialOrder
17807
- };
17808
- const { actions: orderEntryActions, entry: orderEntity } = useOrderStore(initialOrder);
18506
+ const orderEntity = useOrderStore((state) => state.entry);
18507
+ const orderEntryActions = useOrderStore((state) => state.actions);
18508
+ useEffect(() => {
18509
+ orderEntryActions.initOrder(symbol, options.initialOrder);
18510
+ if (options.initialOrder) {
18511
+ orderEntryActions.updateOrder(options.initialOrder);
18512
+ }
18513
+ }, [symbol]);
17809
18514
  const calculate2 = useCallback(
17810
18515
  (values, fieldName, value, markPrice, config) => {
17811
18516
  const fieldHandler = getCalculateHandler(fieldName);
@@ -17819,17 +18524,15 @@ var useOrderEntryNextInternal = (symbol, options = {}) => {
17819
18524
  },
17820
18525
  []
17821
18526
  );
17822
- useEffect(() => {
17823
- orderEntryActions.updateOrderByKey("symbol", symbol);
17824
- }, [orderEntryActions, symbol]);
17825
18527
  const setValue = (key, value, additional) => {
17826
18528
  if (!symbolInfo) {
17827
18529
  orderEntryActions.updateOrderByKey(key, value);
17828
18530
  return;
17829
18531
  }
18532
+ const currentEntry = useOrderStore.getState().entry;
17830
18533
  const { markPrice } = additional ?? { markPrice: 0 };
17831
18534
  let newValues = calculate2(
17832
- { ...orderEntity },
18535
+ { ...currentEntry },
17833
18536
  key,
17834
18537
  value,
17835
18538
  markPrice,
@@ -17910,7 +18613,8 @@ var useOrderEntryNextInternal = (symbol, options = {}) => {
17910
18613
  orderEntryActions.updateOrder(values);
17911
18614
  return;
17912
18615
  }
17913
- let newValues = { ...orderEntity };
18616
+ const currentEntry = useOrderStore.getState().entry;
18617
+ let newValues = { ...currentEntry };
17914
18618
  Object.keys(values).forEach((key) => {
17915
18619
  newValues = calculate2(
17916
18620
  newValues,
@@ -17926,10 +18630,11 @@ var useOrderEntryNextInternal = (symbol, options = {}) => {
17926
18630
  const onMarkPriceUpdated = useCallback(
17927
18631
  (markPrice, baseOn = []) => {
17928
18632
  if (!options.symbolInfo) return;
17929
- let newValues = { ...orderEntity };
18633
+ const currentEntry = useOrderStore.getState().entry;
18634
+ let newValues = { ...currentEntry };
17930
18635
  if (baseOn.length === 0) {
17931
18636
  newValues = calculate2(
17932
- { ...orderEntity },
18637
+ { ...currentEntry },
17933
18638
  "order_price",
17934
18639
  markPrice,
17935
18640
  markPrice,
@@ -17940,7 +18645,7 @@ var useOrderEntryNextInternal = (symbol, options = {}) => {
17940
18645
  newValues = calculate2(
17941
18646
  { ...newValues },
17942
18647
  key,
17943
- orderEntity[key],
18648
+ currentEntry[key],
17944
18649
  markPrice,
17945
18650
  options.symbolInfo
17946
18651
  );
@@ -17961,7 +18666,7 @@ var useOrderEntryNextInternal = (symbol, options = {}) => {
17961
18666
  }
17962
18667
  orderEntryActions.updateOrder(newValues);
17963
18668
  },
17964
- [calculate2, options.symbolInfo, orderEntity, orderEntryActions]
18669
+ [calculate2, options.symbolInfo, orderEntryActions]
17965
18670
  );
17966
18671
  const validate = (order, creator, options2) => {
17967
18672
  return creator?.validate(order, {
@@ -18010,6 +18715,7 @@ var useOrderEntry2 = (symbol, options = {}) => {
18010
18715
  const lastChangedField = useRef();
18011
18716
  const lastOrderTypeExt = useRef();
18012
18717
  const lastLevel = useRef();
18718
+ const fundingRates = useFundingRatesStore();
18013
18719
  const calculateTPSL_baseOn = useRef({
18014
18720
  tp: "",
18015
18721
  sl: ""
@@ -18018,7 +18724,9 @@ var useOrderEntry2 = (symbol, options = {}) => {
18018
18724
  const symbolConfig = useSymbolsInfo();
18019
18725
  const accountInfo = useAccountInfo();
18020
18726
  const positions3 = usePositions();
18021
- const symbolLeverage = useLeverageBySymbol(symbol);
18727
+ const entry = useOrderStore((s) => s.entry);
18728
+ const effectiveMarginMode = options?.initialOrder?.margin_mode ?? entry?.margin_mode ?? MarginMode.CROSS;
18729
+ const symbolLeverage = useLeverageBySymbol(symbol, effectiveMarginMode);
18022
18730
  const symbolInfo = symbolConfig[symbol]();
18023
18731
  const markPrice = actions.getMarkPriceBySymbol(symbol);
18024
18732
  const { orderMetadata } = useOrderlyContext();
@@ -18040,11 +18748,13 @@ var useOrderEntry2 = (symbol, options = {}) => {
18040
18748
  const [doCreateOrder, { isMutating }] = useMutation(
18041
18749
  getCreateOrderUrl(formattedOrder)
18042
18750
  );
18043
- const maxQtyValue = useMaxQty(
18044
- symbol,
18045
- formattedOrder.side,
18046
- formattedOrder.reduce_only
18047
- );
18751
+ const bestAskBid = askAndBid.current?.[0] || [];
18752
+ const referencePriceFromOrder = bestAskBid.length >= 2 && formattedOrder.order_type && formattedOrder.side ? getOrderReferencePriceFromOrder(formattedOrder, bestAskBid) : null;
18753
+ const maxQtyValue = useMaxQty(symbol, formattedOrder.side, {
18754
+ reduceOnly: formattedOrder.reduce_only,
18755
+ marginMode: effectiveMarginMode,
18756
+ currentOrderReferencePrice: referencePriceFromOrder && referencePriceFromOrder > 0 ? referencePriceFromOrder : void 0
18757
+ });
18048
18758
  const maxQty = options.maxQty ?? maxQtyValue;
18049
18759
  const updateOrderPrice = () => {
18050
18760
  const order_type = formattedOrder.order_type;
@@ -18134,6 +18844,9 @@ var useOrderEntry2 = (symbol, options = {}) => {
18134
18844
  };
18135
18845
  }, []);
18136
18846
  useEffect(() => {
18847
+ if (formattedOrder.symbol !== symbol) {
18848
+ return;
18849
+ }
18137
18850
  if ((formattedOrder.order_type === OrderType.MARKET || formattedOrder.order_type === OrderType.STOP_MARKET) && markPrice) {
18138
18851
  const baseOn = /* @__PURE__ */ new Set();
18139
18852
  if (lastChangedField.current) {
@@ -18147,7 +18860,7 @@ var useOrderEntry2 = (symbol, options = {}) => {
18147
18860
  }
18148
18861
  orderEntryActions.onMarkPriceChange(markPrice, Array.from(baseOn));
18149
18862
  }
18150
- }, [markPrice, formattedOrder.order_type]);
18863
+ }, [markPrice, formattedOrder.order_type, formattedOrder.symbol, symbol]);
18151
18864
  const prepareData = useCallback(() => {
18152
18865
  return {
18153
18866
  markPrice: actions.getMarkPriceBySymbol(symbol),
@@ -18256,7 +18969,7 @@ var useOrderEntry2 = (symbol, options = {}) => {
18256
18969
  }
18257
18970
  );
18258
18971
  };
18259
- const { freeCollateral, totalCollateral } = useCollateral();
18972
+ const { freeCollateral, freeCollateralUSDCOnly, totalCollateral } = useCollateral();
18260
18973
  const currentPosition = useMemo(() => {
18261
18974
  const rows = positions3 ?? [];
18262
18975
  const p = Array.isArray(rows) ? rows.find(
@@ -18269,6 +18982,7 @@ var useOrderEntry2 = (symbol, options = {}) => {
18269
18982
  if (!markPrice2 || !accountInfo || !symbolInfo) {
18270
18983
  return null;
18271
18984
  }
18985
+ const sumUnitaryFunding = fundingRates[symbol]?.sum_unitary_funding ?? 0;
18272
18986
  const estLiqPrice2 = calcEstLiqPrice(formattedOrder, askAndBid.current[0], {
18273
18987
  markPrice: markPrice2,
18274
18988
  totalCollateral,
@@ -18276,7 +18990,9 @@ var useOrderEntry2 = (symbol, options = {}) => {
18276
18990
  imr_factor: accountInfo.imr_factor[symbol],
18277
18991
  symbol,
18278
18992
  positions: positions3,
18279
- symbolInfo
18993
+ symbolInfo,
18994
+ sumUnitaryFunding,
18995
+ symbolLeverage
18280
18996
  });
18281
18997
  return estLiqPrice2;
18282
18998
  }, [
@@ -18286,7 +19002,9 @@ var useOrderEntry2 = (symbol, options = {}) => {
18286
19002
  totalCollateral,
18287
19003
  symbol,
18288
19004
  maxQty,
18289
- symbolInfo
19005
+ symbolInfo,
19006
+ fundingRates,
19007
+ symbolLeverage
18290
19008
  ]);
18291
19009
  const estLiqPriceDistance = useMemo(() => {
18292
19010
  if (!estLiqPrice) {
@@ -18421,7 +19139,7 @@ var useOrderEntry2 = (symbol, options = {}) => {
18421
19139
  validator: validateOrder,
18422
19140
  validate: validateOrder
18423
19141
  },
18424
- freeCollateral,
19142
+ freeCollateral: effectiveMarginMode === MarginMode.ISOLATED ? freeCollateralUSDCOnly : freeCollateral,
18425
19143
  setValue: useMemoizedFn(setValue),
18426
19144
  setValues: useMemoizedFn(setValues),
18427
19145
  symbolInfo: symbolInfo || EMPTY_OBJECT,
@@ -18431,93 +19149,6 @@ var useOrderEntry2 = (symbol, options = {}) => {
18431
19149
  symbolLeverage
18432
19150
  };
18433
19151
  };
18434
- var initialOrderState2 = {
18435
- order_price: "",
18436
- order_quantity: "",
18437
- trigger_price: "",
18438
- tp_trigger_price: "",
18439
- sl_trigger_price: "",
18440
- total: "",
18441
- symbol: ""
18442
- };
18443
- var useOrderStore2 = create()(
18444
- immer((set, get3) => ({
18445
- entry: {
18446
- side: OrderSide.BUY,
18447
- order_type: OrderType.LIMIT,
18448
- ...initialOrderState2
18449
- },
18450
- estLeverage: null,
18451
- estLiquidationPrice: null,
18452
- errors: {},
18453
- actions: {
18454
- hasTP_SL: () => {
18455
- const order = get3().entry;
18456
- return typeof order.tp_trigger_price !== "undefined" || typeof order.sl_trigger_price !== "undefined";
18457
- },
18458
- updateOrderComputed: (data) => {
18459
- set(
18460
- (state) => {
18461
- state.estLeverage = data.estLeverage;
18462
- state.estLiquidationPrice = data.estLiquidationPrice;
18463
- },
18464
- false
18465
- // "updateOrderComputed"
18466
- );
18467
- },
18468
- updateOrder: (order) => {
18469
- set(
18470
- (state) => {
18471
- state.entry = {
18472
- ...state.entry,
18473
- ...order
18474
- };
18475
- },
18476
- false
18477
- // "updateOrder"
18478
- );
18479
- },
18480
- updateOrderByKey: (key, value) => {
18481
- set(
18482
- (state) => {
18483
- state.entry[key] = value;
18484
- },
18485
- false
18486
- // "updateOrderByKey"
18487
- );
18488
- },
18489
- restoreOrder: (order) => {
18490
- set(
18491
- (state) => {
18492
- state.entry = order;
18493
- },
18494
- false
18495
- // "restoreOrder"
18496
- );
18497
- },
18498
- resetOrder: (order) => {
18499
- set(
18500
- (state) => {
18501
- state.entry.order_price = "";
18502
- state.entry.order_quantity = "";
18503
- state.entry.trigger_price = "";
18504
- state.entry.total = "";
18505
- state.entry.tp_trigger_price = "";
18506
- state.entry.tp_pnl = "";
18507
- state.entry.tp_offset = "";
18508
- state.entry.tp_offset_percentage = "";
18509
- state.entry.sl_trigger_price = "";
18510
- state.entry.sl_pnl = "";
18511
- state.entry.sl_offset = "";
18512
- state.entry.sl_offset_percentage = "";
18513
- },
18514
- true
18515
- // "resetOrder"
18516
- );
18517
- }
18518
- }
18519
- }))
18520
- );
18521
19152
  var useOrderEntity = (order, options) => {
18522
19153
  const { symbol } = order;
18523
19154
  const { maxQty } = options || {};
@@ -18675,13 +19306,15 @@ var usePositionClose = (options) => {
18675
19306
  symbol,
18676
19307
  order_type: type,
18677
19308
  side,
18678
- reduce_only: true
19309
+ reduce_only: true,
19310
+ // Use position's margin_mode or default to CROSS for backward compatibility
19311
+ margin_mode: position.margin_mode || MarginMode.CROSS
18679
19312
  };
18680
19313
  if (type === OrderType.LIMIT) {
18681
19314
  data.order_price = price;
18682
19315
  }
18683
19316
  return data;
18684
- }, [symbol, price, type, quantity]);
19317
+ }, [symbol, price, type, quantity, position.margin_mode]);
18685
19318
  const maxQty = useMemo(() => {
18686
19319
  if (!position) {
18687
19320
  return 0;
@@ -18883,9 +19516,11 @@ var useTpslPriceChecker = (params) => {
18883
19516
  prevResultRef.current = currentResult;
18884
19517
  return currentResult;
18885
19518
  };
18886
- var useEstLiqPriceBySymbol = (symbol) => {
19519
+ var useEstLiqPriceBySymbol = (symbol, marginMode) => {
18887
19520
  const [data] = usePositionStream(symbol);
18888
- const position = data?.rows?.find((row) => row.symbol === symbol);
19521
+ const position = data?.rows?.find(
19522
+ (row) => row.symbol === symbol && row.margin_mode === marginMode
19523
+ );
18889
19524
  return useMemo(() => {
18890
19525
  return position?.est_liq_price ?? void 0;
18891
19526
  }, [position]);
@@ -18906,7 +19541,63 @@ var useGetEstLiqPrice = (props) => {
18906
19541
  return estLiqPrice;
18907
19542
  }, [estLiqPrice, markPrice, side]);
18908
19543
  };
19544
+ var useFeatureFlag = (key) => {
19545
+ const { data: publicFlags, isLoading: publicLoading } = useQuery("/v1/public/feature_flags", {});
19546
+ const publicFlag = useMemo(() => {
19547
+ if (!publicFlags || publicLoading) {
19548
+ return void 0;
19549
+ }
19550
+ return publicFlags.find((flag) => flag.key === key);
19551
+ }, [publicFlags, publicLoading, key]);
19552
+ const shouldQueryPrivate = useMemo(() => {
19553
+ return publicFlag !== void 0;
19554
+ }, [publicFlag]);
19555
+ const { data: privateFlags, isLoading: privateLoading } = usePrivateQuery(shouldQueryPrivate ? "/v1/feature_flags" : null, {});
19556
+ const privateFlag = useMemo(() => {
19557
+ if (!shouldQueryPrivate || !privateFlags || privateLoading) {
19558
+ return void 0;
19559
+ }
19560
+ return privateFlags.find((flag) => flag.key === key);
19561
+ }, [shouldQueryPrivate, privateFlags, privateLoading, key]);
19562
+ return useMemo(() => {
19563
+ if (publicLoading || shouldQueryPrivate && privateLoading) {
19564
+ return {
19565
+ enabled: false,
19566
+ data: void 0
19567
+ };
19568
+ }
19569
+ if (publicFlag === void 0) {
19570
+ return {
19571
+ enabled: true,
19572
+ data: void 0
19573
+ };
19574
+ }
19575
+ if (privateFlag === void 0) {
19576
+ return {
19577
+ enabled: false,
19578
+ data: void 0
19579
+ };
19580
+ }
19581
+ return {
19582
+ enabled: true,
19583
+ data: privateFlag
19584
+ };
19585
+ }, [
19586
+ publicFlag,
19587
+ privateFlag,
19588
+ publicLoading,
19589
+ shouldQueryPrivate,
19590
+ privateLoading,
19591
+ key
19592
+ ]);
19593
+ };
19594
+
19595
+ // src/feature-flag/flagKeys.ts
19596
+ var FlagKeys = /* @__PURE__ */ ((FlagKeys2) => {
19597
+ FlagKeys2["IsolatedMargin"] = "isolated-margin";
19598
+ return FlagKeys2;
19599
+ })(FlagKeys || {});
18909
19600
 
18910
- export { DefaultLayoutConfig, DistributionId, ENVType2 as ENVType, ERROR_MSG_CODES, EpochStatus, ExtendedConfigStore, MaintenanceStatus, MarketsStorageKey, MarketsType, ORDERLY_ORDERBOOK_DEPTH_KEY, OrderlyConfigProvider, OrderlyContext, OrderlyProvider, StatusProvider, TWType, WalletConnectorContext, WsNetworkStatus, checkNotional, cleanStringStyle, fetcher, findPositionTPSLFromOrders, findTPSLFromOrder, findTPSLOrderPriceFromOrder, getMinNotional, getPriceKey, indexedDBManager, initializeAppDatabase, isCurrentlyClosed, isCurrentlyTrading, noCacheConfig, parseJSON, persistIndexedDB, resetTimestampOffsetState, timestampWaitingMiddleware, useAccount, useAccountInfo2 as useAccountInfo, useAccountInstance, useAccountRewardsHistory, useAllBrokers, useApiKeyManager, useAppStore, useAssetsHistory, useAudioPlayer, useBalanceSubscription, useBalanceTopic, useBoolean, useChain, useChainInfo, useChains, useCheckReferralCode, useCollateral, useCommission, useComputedLTV, useConfig, useConvert, useCurEpochEstimate, useDaily, useDeposit, useDistribution, useDistributionHistory, useEpochInfo, useEstLiqPriceBySymbol, useEventEmitter, useFeeState, useFundingDetails, useFundingFeeHistory, useFundingRate, useFundingRateBySymbol, useFundingRateHistory, useFundingRates, useFundingRatesStore, useGetClaimed, useGetEnv, useGetEstLiqPrice, useGetReferralCode, useGetRwaSymbolCloseTimeInterval, useGetRwaSymbolInfo, useGetRwaSymbolOpenStatus, useGetRwaSymbolOpenTimeInterval, useHoldingStream, useIndexPrice, useIndexPricesStream, useInfiniteQuery, useInitRwaSymbolsRuntime, useInternalTransfer, useKeyStore, useLazyQuery, useLeverage, useLeverageBySymbol, useLocalStorage, useMainTokenStore, useMainnetChainsStore, useMaintenanceStatus, useMarginRatio, useMarkPrice, useMarkPriceBySymbol, useMarkPricesStream, useMarket, useMarketList, useMarketMap, useMarketTradeStream, useMarkets, useMarketsStore, useMarketsStream, useMaxLeverage, useMaxQty, useMaxWithdrawal, useMediaQuery, useMemoizedFn, useMutation, useNetworkInfo, useOdosQuote, useOrderEntity, useOrderEntry2 as useOrderEntry, useOrderEntry as useOrderEntry_deprecated, useOrderStore2 as useOrderStore, useOrderStream, useOrderbookStream, useOrderlyContext, usePortfolio, usePositionActions, usePositionClose, usePositionStream, usePoster, usePreLoadData, usePrivateDataObserver, usePrivateInfiniteQuery, usePrivateQuery, useQuery, useRefereeHistory, useRefereeInfo, useRefereeRebateSummary, useReferralInfo, useReferralRebateSummary, useRestrictedInfo, useRwaSymbolsInfo, useRwaSymbolsInfoStore, useSessionStorage, useSettleSubscription, useSimpleDI, useStatisticsDaily, useStorageChain, useStorageLedgerAddress, useSubAccountAlgoOrderStream, useSubAccountDataObserver, useSubAccountMaxWithdrawal, useSubAccountMutation, useSubAccountQuery, useSubAccountWS, useSwapSupportStore, useSymbolInfo, useSymbolLeverage, useSymbolPriceRange, useSymbolsInfo, useSymbolsInfoStore, useTPSLOrder, useTestTokenStore, useTestnetChainsStore, useTickerStream, useTokenInfo, useTokensInfo, useTpslPriceChecker, useTrack, useTrackingInstance, useTradingRewardsStatus, useTransfer, useTransferHistory, useUpdatedRef, useUserStatistics, useVaultsHistory, useWS, useWalletConnector, useWalletRewardsHistory, useWalletSubscription, useWalletTopic, useWithdraw, useWsStatus, utils_exports as utils, version_default as version };
19601
+ export { DefaultLayoutConfig, DistributionId, ENVType2 as ENVType, ERROR_MSG_CODES, EpochStatus, ExtendedConfigStore, FlagKeys, MaintenanceStatus, MarketsStorageKey, MarketsType, ORDERLY_ORDERBOOK_DEPTH_KEY, OrderlyConfigProvider, OrderlyContext, OrderlyProvider, StatusProvider, TWType, WalletConnectorContext, WsNetworkStatus, checkNotional, cleanStringStyle, fetcher, findPositionTPSLFromOrders, findTPSLFromOrder, findTPSLOrderPriceFromOrder, getMinNotional, getPriceKey, indexedDBManager, initializeAppDatabase, isCurrentlyClosed, isCurrentlyTrading, noCacheConfig, parseJSON, persistIndexedDB, resetTimestampOffsetState, timestampWaitingMiddleware, useAccount, useAccountInfo2 as useAccountInfo, useAccountInstance, useAccountRewardsHistory, useAllBrokers, useApiKeyManager, useAppStore, useAssetsHistory, useAudioPlayer, useBalanceSubscription, useBalanceTopic, useBoolean, useChain, useChainInfo, useChains, useCheckReferralCode, useCollateral, useCommission, useComputedLTV, useConfig, useConvert, useCurEpochEstimate, useDaily, useDeposit, useDistribution, useDistributionHistory, useEpochInfo, useEstLiqPriceBySymbol, useEventEmitter, useFeatureFlag, useFeeState, useFundingDetails, useFundingFeeHistory, useFundingRate, useFundingRateBySymbol, useFundingRateHistory, useFundingRates, useFundingRatesStore, useGetClaimed, useGetEnv, useGetEstLiqPrice, useGetReferralCode, useGetRwaSymbolCloseTimeInterval, useGetRwaSymbolInfo, useGetRwaSymbolOpenStatus, useGetRwaSymbolOpenTimeInterval, useHoldingStream, useIndexPrice, useIndexPricesStream, useInfiniteQuery, useInitRwaSymbolsRuntime, useInternalTransfer, useKeyStore, useLazyQuery, useLeverage, useLeverageBySymbol, useLocalStorage, useMainTokenStore, useMainnetChainsStore, useMaintenanceStatus, useMarginModeBySymbol, useMarginModes, useMarginRatio, useMarkPrice, useMarkPriceBySymbol, useMarkPricesStream, useMarket, useMarketList, useMarketMap, useMarketTradeStream, useMarkets, useMarketsStore, useMarketsStream, useMaxLeverage, useMaxQty, useMaxWithdrawal, useMediaQuery, useMemoizedFn, useMutation, useNetworkInfo, useOdosQuote, useOrderEntity, useOrderEntry2 as useOrderEntry, useOrderEntry as useOrderEntry_deprecated, useOrderStore, useOrderStream, useOrderbookStream, useOrderlyContext, usePortfolio, usePositionActions, usePositionClose, usePositionStream, usePositions, usePoster, usePreLoadData, usePrivateDataObserver, usePrivateInfiniteQuery, usePrivateQuery, useQuery, useRefereeHistory, useRefereeInfo, useRefereeRebateSummary, useReferralInfo, useReferralRebateSummary, useRestrictedInfo, useRwaSymbolsInfo, useRwaSymbolsInfoStore, useSessionStorage, useSettleSubscription, useSimpleDI, useStatisticsDaily, useStorageChain, useStorageLedgerAddress, useSubAccountAlgoOrderStream, useSubAccountDataObserver, useSubAccountMaxWithdrawal, useSubAccountMutation, useSubAccountQuery, useSubAccountWS, useSwapSupportStore, useSymbolInfo, useSymbolLeverage, useSymbolLeverageMap, useSymbolPriceRange, useSymbolsInfo, useSymbolsInfoStore, useTPSLOrder, useTestTokenStore, useTestnetChainsStore, useTickerStream, useTokenInfo, useTokensInfo, useTpslPriceChecker, useTrack, useTrackingInstance, useTradingRewardsStatus, useTransfer, useTransferHistory, useUpdatedRef, useUserStatistics, useVaultsHistory, useWS, useWalletConnector, useWalletRewardsHistory, useWalletSubscription, useWalletTopic, useWithdraw, useWsStatus, utils_exports as utils, version_default as version };
18911
19602
  //# sourceMappingURL=index.mjs.map
18912
19603
  //# sourceMappingURL=index.mjs.map