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