@orderly.network/hooks 2.3.2 → 2.4.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 +21 -3
- package/dist/index.d.ts +21 -3
- package/dist/index.js +995 -555
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +996 -556
- package/dist/index.mjs.map +1 -1
- package/package.json +10 -10
package/dist/index.js
CHANGED
|
@@ -61,9 +61,9 @@ var __export = (target, all) => {
|
|
|
61
61
|
// src/version.ts
|
|
62
62
|
if (typeof window !== "undefined") {
|
|
63
63
|
window.__ORDERLY_VERSION__ = window.__ORDERLY_VERSION__ || {};
|
|
64
|
-
window.__ORDERLY_VERSION__["@orderly.network/hooks"] = "2.
|
|
64
|
+
window.__ORDERLY_VERSION__["@orderly.network/hooks"] = "2.4.0";
|
|
65
65
|
}
|
|
66
|
-
var version_default = "2.
|
|
66
|
+
var version_default = "2.4.0";
|
|
67
67
|
var fetcher = (url, init2 = {}, queryOptions) => net.get(url, init2, queryOptions?.formatter);
|
|
68
68
|
var OrderlyContext = React.createContext({
|
|
69
69
|
// configStore: new MemoryConfigStore(),
|
|
@@ -268,7 +268,8 @@ var useTrack = () => {
|
|
|
268
268
|
page_title: title,
|
|
269
269
|
page_url: url,
|
|
270
270
|
page_domain: origin,
|
|
271
|
-
user_agent: userAgent
|
|
271
|
+
user_agent: userAgent,
|
|
272
|
+
sdk_version: window?.__ORDERLY_VERSION__?.["@orderly.network/net"] ?? ""
|
|
272
273
|
});
|
|
273
274
|
if (eventName === types.TrackerEventName.placeOrderSuccess) {
|
|
274
275
|
Object.assign(params, {
|
|
@@ -4200,7 +4201,7 @@ function fillChainsInfo(chains, filter, chainInfos) {
|
|
|
4200
4201
|
return _chains;
|
|
4201
4202
|
}
|
|
4202
4203
|
function filterAndUpdateChains(chains, chainInfos, filter, isTestNet) {
|
|
4203
|
-
const
|
|
4204
|
+
const chainsMap = /* @__PURE__ */ new Map();
|
|
4204
4205
|
chains.forEach((chain) => {
|
|
4205
4206
|
const _chain = { ...chain };
|
|
4206
4207
|
const networkInfo = chainInfos?.find(
|
|
@@ -4225,10 +4226,10 @@ function filterAndUpdateChains(chains, chainInfos, filter, isTestNet) {
|
|
|
4225
4226
|
return;
|
|
4226
4227
|
}
|
|
4227
4228
|
if (networkInfo) {
|
|
4228
|
-
|
|
4229
|
+
chainsMap.set(chain.network_infos.chain_id, _chain);
|
|
4229
4230
|
}
|
|
4230
4231
|
});
|
|
4231
|
-
return
|
|
4232
|
+
return Array.from(chainsMap.values());
|
|
4232
4233
|
}
|
|
4233
4234
|
function filterByAllowedChains(chains, allowedChains) {
|
|
4234
4235
|
if (!allowedChains) {
|
|
@@ -4912,12 +4913,11 @@ var useSymbolPriceRange = (symbol, side, price) => {
|
|
|
4912
4913
|
};
|
|
4913
4914
|
function getMinNotional(props) {
|
|
4914
4915
|
const { price, base_tick, qty, min_notional, base_dp, quote_dp, quote_tick } = props;
|
|
4915
|
-
if (price
|
|
4916
|
+
if (price && qty && min_notional) {
|
|
4916
4917
|
try {
|
|
4917
|
-
const
|
|
4918
|
-
|
|
4919
|
-
|
|
4920
|
-
let minQty = new utils.Decimal(notional).div(price).toDecimalPlaces(base_dp, utils.Decimal.ROUND_DOWN).add(base_tick ?? 0);
|
|
4918
|
+
const calcMinNotional = new utils.Decimal(price).mul(new utils.Decimal(qty));
|
|
4919
|
+
if (calcMinNotional.lt(min_notional)) {
|
|
4920
|
+
let minQty = new utils.Decimal(min_notional).div(price).toDecimalPlaces(base_dp, utils.Decimal.ROUND_DOWN).add(base_tick ?? 0);
|
|
4921
4921
|
if (base_tick && base_tick > 0) {
|
|
4922
4922
|
minQty = new utils.Decimal(
|
|
4923
4923
|
getRoundedDownDivision(minQty.toNumber(), base_tick)
|
|
@@ -4975,6 +4975,14 @@ var OrderValidation = class {
|
|
|
4975
4975
|
return "TP price";
|
|
4976
4976
|
case "sl_trigger_price":
|
|
4977
4977
|
return "SL price";
|
|
4978
|
+
case "max_price":
|
|
4979
|
+
return "Upper price";
|
|
4980
|
+
case "min_price":
|
|
4981
|
+
return "Lower price";
|
|
4982
|
+
case "total_orders":
|
|
4983
|
+
return "Total orders";
|
|
4984
|
+
case "skew":
|
|
4985
|
+
return "Skew";
|
|
4978
4986
|
default:
|
|
4979
4987
|
return key;
|
|
4980
4988
|
}
|
|
@@ -4999,6 +5007,14 @@ var OrderValidation = class {
|
|
|
4999
5007
|
value
|
|
5000
5008
|
};
|
|
5001
5009
|
}
|
|
5010
|
+
static range(key, min3, max3) {
|
|
5011
|
+
return {
|
|
5012
|
+
type: "range",
|
|
5013
|
+
message: `${this.getLabel(key)} must be in the range of ${min3} to ${max3}`,
|
|
5014
|
+
min: min3,
|
|
5015
|
+
max: max3
|
|
5016
|
+
};
|
|
5017
|
+
}
|
|
5002
5018
|
};
|
|
5003
5019
|
|
|
5004
5020
|
// src/services/orderCreator/baseCreator.ts
|
|
@@ -5201,33 +5217,33 @@ var BaseOrderCreator = class {
|
|
|
5201
5217
|
}
|
|
5202
5218
|
};
|
|
5203
5219
|
|
|
5204
|
-
// src/services/orderCreator/
|
|
5205
|
-
var
|
|
5220
|
+
// src/services/orderCreator/bboOrderCreator.ts
|
|
5221
|
+
var BBOOrderCreator = class extends BaseOrderCreator {
|
|
5222
|
+
constructor() {
|
|
5223
|
+
super(...arguments);
|
|
5224
|
+
this.orderType = types.OrderType.LIMIT;
|
|
5225
|
+
}
|
|
5206
5226
|
create(values2) {
|
|
5207
|
-
const
|
|
5208
|
-
|
|
5209
|
-
|
|
5210
|
-
delete data["trigger_price"];
|
|
5211
|
-
delete data["isStopOrder"];
|
|
5212
|
-
return {
|
|
5213
|
-
...data
|
|
5227
|
+
const order = {
|
|
5228
|
+
...this.baseOrder(values2),
|
|
5229
|
+
level: values2.level
|
|
5214
5230
|
};
|
|
5231
|
+
return ramda.pick(
|
|
5232
|
+
[
|
|
5233
|
+
"symbol",
|
|
5234
|
+
"order_quantity",
|
|
5235
|
+
"visible_quantity",
|
|
5236
|
+
"reduce_only",
|
|
5237
|
+
"side",
|
|
5238
|
+
"order_type",
|
|
5239
|
+
"level"
|
|
5240
|
+
],
|
|
5241
|
+
order
|
|
5242
|
+
);
|
|
5215
5243
|
}
|
|
5216
|
-
validate(values2, configs) {
|
|
5217
|
-
return this.baseValidate(values2, configs).then((
|
|
5218
|
-
|
|
5219
|
-
const estSlippage = Number.isNaN(configs.estSlippage) ? 0 : Number(configs.estSlippage) * 100;
|
|
5220
|
-
if (!isNaN(slippage) && estSlippage > slippage) {
|
|
5221
|
-
return {
|
|
5222
|
-
...result,
|
|
5223
|
-
slippage: {
|
|
5224
|
-
type: "max",
|
|
5225
|
-
message: "Estimated slippage exceeds your maximum allowed slippage.",
|
|
5226
|
-
value: estSlippage
|
|
5227
|
-
}
|
|
5228
|
-
};
|
|
5229
|
-
}
|
|
5230
|
-
return result;
|
|
5244
|
+
async validate(values2, configs) {
|
|
5245
|
+
return this.baseValidate(values2, configs).then((errors) => {
|
|
5246
|
+
return errors;
|
|
5231
5247
|
});
|
|
5232
5248
|
}
|
|
5233
5249
|
};
|
|
@@ -5306,124 +5322,791 @@ var LimitOrderCreator = class extends BaseOrderCreator {
|
|
|
5306
5322
|
});
|
|
5307
5323
|
}
|
|
5308
5324
|
};
|
|
5309
|
-
|
|
5310
|
-
|
|
5311
|
-
|
|
5312
|
-
|
|
5313
|
-
|
|
5325
|
+
async function bracketOrderValidator(values2, config) {
|
|
5326
|
+
const result = /* @__PURE__ */ Object.create(null);
|
|
5327
|
+
await Promise.resolve();
|
|
5328
|
+
const { tp_trigger_price, sl_trigger_price, side } = values2;
|
|
5329
|
+
const qty = Number(values2.quantity);
|
|
5330
|
+
const maxQty = config.maxQty;
|
|
5331
|
+
const type = values2.order_type;
|
|
5332
|
+
const { quote_max, quote_min, price_scope, quote_dp } = config.symbol ?? {};
|
|
5333
|
+
const mark_price = type === types.OrderType.MARKET ? config.markPrice : values2.order_price ? Number(values2.order_price) : void 0;
|
|
5334
|
+
if (!isNaN(qty) && qty > maxQty) {
|
|
5335
|
+
result.quantity = OrderValidation.max("quantity", config.maxQty);
|
|
5314
5336
|
}
|
|
5315
|
-
|
|
5316
|
-
|
|
5317
|
-
const order = {
|
|
5318
|
-
...this.baseOrder(values2),
|
|
5319
|
-
trigger_price: values2.trigger_price,
|
|
5320
|
-
algo_type: types.AlgoOrderRootType.STOP,
|
|
5321
|
-
type: types.OrderType.LIMIT,
|
|
5322
|
-
quantity: values2["order_quantity"],
|
|
5323
|
-
price: values2["order_price"],
|
|
5324
|
-
trigger_price_type: types.TriggerPriceType.MARK_PRICE
|
|
5325
|
-
};
|
|
5326
|
-
return ramda.pick(
|
|
5327
|
-
[
|
|
5328
|
-
"symbol",
|
|
5329
|
-
"trigger_price",
|
|
5330
|
-
"algo_type",
|
|
5331
|
-
"type",
|
|
5332
|
-
"quantity",
|
|
5333
|
-
"price",
|
|
5334
|
-
"trigger_price_type",
|
|
5335
|
-
"side",
|
|
5336
|
-
"reduce_only",
|
|
5337
|
-
"visible_quantity"
|
|
5338
|
-
],
|
|
5339
|
-
order
|
|
5340
|
-
);
|
|
5337
|
+
if (Number(tp_trigger_price) < 0) {
|
|
5338
|
+
result.tp_trigger_price = OrderValidation.min("tp_trigger_price", 0);
|
|
5341
5339
|
}
|
|
5342
|
-
|
|
5343
|
-
|
|
5344
|
-
const { order_price, trigger_price, side } = values2;
|
|
5345
|
-
const { symbol } = config;
|
|
5346
|
-
const { price_range, price_scope, quote_max, quote_min } = symbol;
|
|
5347
|
-
if (!trigger_price) {
|
|
5348
|
-
errors.trigger_price = OrderValidation.required("trigger_price");
|
|
5349
|
-
}
|
|
5350
|
-
if (!order_price) {
|
|
5351
|
-
errors.order_price = OrderValidation.required("order_price");
|
|
5352
|
-
}
|
|
5353
|
-
if (trigger_price > quote_max) {
|
|
5354
|
-
errors.trigger_price = OrderValidation.max("trigger_price", quote_max);
|
|
5355
|
-
} else if (trigger_price < quote_min) {
|
|
5356
|
-
errors.trigger_price = OrderValidation.min("trigger_price", quote_min);
|
|
5357
|
-
} else {
|
|
5358
|
-
if (trigger_price && order_price) {
|
|
5359
|
-
const price = new utils.Decimal(order_price);
|
|
5360
|
-
const maxPriceNumber = maxPrice2(trigger_price, price_range);
|
|
5361
|
-
const minPriceNumber = minPrice2(trigger_price, price_range);
|
|
5362
|
-
const scropePriceNumbere = scopePrice2(
|
|
5363
|
-
trigger_price,
|
|
5364
|
-
price_scope,
|
|
5365
|
-
side
|
|
5366
|
-
);
|
|
5367
|
-
const priceRange = side === "BUY" ? {
|
|
5368
|
-
min: scropePriceNumbere,
|
|
5369
|
-
max: maxPriceNumber
|
|
5370
|
-
} : {
|
|
5371
|
-
min: minPriceNumber,
|
|
5372
|
-
max: scropePriceNumbere
|
|
5373
|
-
};
|
|
5374
|
-
if (price.gt(quote_max)) {
|
|
5375
|
-
errors.order_price = OrderValidation.max("order_price", quote_max);
|
|
5376
|
-
} else {
|
|
5377
|
-
if (price.gt(priceRange?.max)) {
|
|
5378
|
-
errors.order_price = OrderValidation.max(
|
|
5379
|
-
"order_price",
|
|
5380
|
-
new utils.Decimal(priceRange.max).todp(symbol.quote_dp).toString()
|
|
5381
|
-
);
|
|
5382
|
-
}
|
|
5383
|
-
}
|
|
5384
|
-
if (price.lt(quote_min)) {
|
|
5385
|
-
errors.order_price = OrderValidation.min("order_price", quote_min);
|
|
5386
|
-
} else {
|
|
5387
|
-
if (price.lt(priceRange?.min)) {
|
|
5388
|
-
errors.order_price = OrderValidation.min(
|
|
5389
|
-
"order_price",
|
|
5390
|
-
new utils.Decimal(priceRange.min).todp(symbol.quote_dp).toString()
|
|
5391
|
-
);
|
|
5392
|
-
}
|
|
5393
|
-
}
|
|
5394
|
-
}
|
|
5395
|
-
}
|
|
5396
|
-
return errors;
|
|
5397
|
-
});
|
|
5340
|
+
if (Number(sl_trigger_price) < 0) {
|
|
5341
|
+
result.sl_trigger_price = OrderValidation.min("sl_trigger_price", 0);
|
|
5398
5342
|
}
|
|
5399
|
-
|
|
5343
|
+
if (side === types.OrderSide.BUY && mark_price) {
|
|
5344
|
+
const slTriggerPriceScope = new utils.Decimal(mark_price * (1 - price_scope)).toDecimalPlaces(quote_dp, utils.Decimal.ROUND_DOWN).toNumber();
|
|
5345
|
+
if (!!sl_trigger_price && Number(sl_trigger_price) < slTriggerPriceScope) {
|
|
5346
|
+
result.sl_trigger_price = OrderValidation.min(
|
|
5347
|
+
"sl_trigger_price",
|
|
5348
|
+
slTriggerPriceScope
|
|
5349
|
+
);
|
|
5350
|
+
}
|
|
5351
|
+
if (!!tp_trigger_price && Number(tp_trigger_price) <= mark_price) {
|
|
5352
|
+
result.tp_trigger_price = OrderValidation.min(
|
|
5353
|
+
"tp_trigger_price",
|
|
5354
|
+
mark_price
|
|
5355
|
+
);
|
|
5356
|
+
}
|
|
5357
|
+
if (!!tp_trigger_price && Number(tp_trigger_price) > quote_max) {
|
|
5358
|
+
result.tp_trigger_price = OrderValidation.max(
|
|
5359
|
+
"tp_trigger_price",
|
|
5360
|
+
quote_max
|
|
5361
|
+
);
|
|
5362
|
+
}
|
|
5363
|
+
if (!!sl_trigger_price && Number(sl_trigger_price) < quote_min) {
|
|
5364
|
+
result.sl_trigger_price = OrderValidation.min(
|
|
5365
|
+
"sl_trigger_price",
|
|
5366
|
+
quote_min
|
|
5367
|
+
);
|
|
5368
|
+
}
|
|
5369
|
+
}
|
|
5370
|
+
if (side === types.OrderSide.SELL && mark_price) {
|
|
5371
|
+
const slTriggerPriceScope = new utils.Decimal(mark_price * (1 + price_scope)).toDecimalPlaces(quote_dp, utils.Decimal.ROUND_DOWN).toNumber();
|
|
5372
|
+
if (!!sl_trigger_price && Number(sl_trigger_price) > slTriggerPriceScope) {
|
|
5373
|
+
result.sl_trigger_price = OrderValidation.max(
|
|
5374
|
+
"sl_trigger_price",
|
|
5375
|
+
slTriggerPriceScope
|
|
5376
|
+
);
|
|
5377
|
+
}
|
|
5378
|
+
if (!!tp_trigger_price && Number(tp_trigger_price) >= mark_price) {
|
|
5379
|
+
result.tp_trigger_price = OrderValidation.max(
|
|
5380
|
+
"tp_trigger_price",
|
|
5381
|
+
mark_price
|
|
5382
|
+
);
|
|
5383
|
+
}
|
|
5384
|
+
if (!!tp_trigger_price && Number(tp_trigger_price) > quote_max) {
|
|
5385
|
+
result.tp_trigger_price = OrderValidation.max(
|
|
5386
|
+
"tp_trigger_price",
|
|
5387
|
+
quote_max
|
|
5388
|
+
);
|
|
5389
|
+
}
|
|
5390
|
+
if (!!sl_trigger_price && Number(sl_trigger_price) < quote_min) {
|
|
5391
|
+
result.sl_trigger_price = OrderValidation.min(
|
|
5392
|
+
"sl_trigger_price",
|
|
5393
|
+
quote_min
|
|
5394
|
+
);
|
|
5395
|
+
}
|
|
5396
|
+
}
|
|
5397
|
+
return Object.keys(result).length > 0 ? result : null;
|
|
5398
|
+
}
|
|
5400
5399
|
|
|
5401
|
-
// src/services/orderCreator/
|
|
5402
|
-
var
|
|
5403
|
-
|
|
5400
|
+
// src/services/orderCreator/bracketLimitOrderCreator.ts
|
|
5401
|
+
var BracketLimitOrderCreator = class extends LimitOrderCreator {
|
|
5402
|
+
// orderType: OrderType;
|
|
5403
|
+
create(values2, config) {
|
|
5404
|
+
const order = super.create(values2, config);
|
|
5404
5405
|
return {
|
|
5405
|
-
...
|
|
5406
|
-
|
|
5407
|
-
|
|
5406
|
+
...order,
|
|
5407
|
+
quantity: order.order_quantity,
|
|
5408
|
+
type: order.order_type,
|
|
5409
|
+
price: order.order_price
|
|
5408
5410
|
};
|
|
5409
5411
|
}
|
|
5410
|
-
validate(values2,
|
|
5411
|
-
|
|
5412
|
+
async validate(values2, config) {
|
|
5413
|
+
const value = await super.validate(values2, config);
|
|
5414
|
+
const bracketData = await bracketOrderValidator(values2, config);
|
|
5415
|
+
return { ...value, ...bracketData };
|
|
5412
5416
|
}
|
|
5413
5417
|
};
|
|
5414
|
-
|
|
5418
|
+
|
|
5419
|
+
// src/services/orderCreator/marketOrderCreator.ts
|
|
5420
|
+
var MarketOrderCreator = class extends BaseOrderCreator {
|
|
5415
5421
|
create(values2) {
|
|
5416
|
-
const
|
|
5417
|
-
|
|
5418
|
-
|
|
5419
|
-
|
|
5420
|
-
|
|
5421
|
-
|
|
5422
|
-
|
|
5423
|
-
// price: values["order_price"],
|
|
5424
|
-
trigger_price_type: types.TriggerPriceType.MARK_PRICE
|
|
5422
|
+
const data = this.baseOrder(values2);
|
|
5423
|
+
delete data["order_price"];
|
|
5424
|
+
delete data["total"];
|
|
5425
|
+
delete data["trigger_price"];
|
|
5426
|
+
delete data["isStopOrder"];
|
|
5427
|
+
return {
|
|
5428
|
+
...data
|
|
5425
5429
|
};
|
|
5426
|
-
|
|
5430
|
+
}
|
|
5431
|
+
validate(values2, configs) {
|
|
5432
|
+
return this.baseValidate(values2, configs).then((result) => {
|
|
5433
|
+
const slippage = Number(values2.slippage);
|
|
5434
|
+
const estSlippage = Number.isNaN(configs.estSlippage) ? 0 : Number(configs.estSlippage) * 100;
|
|
5435
|
+
if (!isNaN(slippage) && estSlippage > slippage) {
|
|
5436
|
+
return {
|
|
5437
|
+
...result,
|
|
5438
|
+
slippage: {
|
|
5439
|
+
type: "max",
|
|
5440
|
+
message: "Estimated slippage exceeds your maximum allowed slippage.",
|
|
5441
|
+
value: estSlippage
|
|
5442
|
+
}
|
|
5443
|
+
};
|
|
5444
|
+
}
|
|
5445
|
+
return result;
|
|
5446
|
+
});
|
|
5447
|
+
}
|
|
5448
|
+
};
|
|
5449
|
+
|
|
5450
|
+
// src/services/orderCreator/bracketMarketOrderCreator.ts
|
|
5451
|
+
var BracketMarketOrderCreator = class extends MarketOrderCreator {
|
|
5452
|
+
constructor() {
|
|
5453
|
+
super(...arguments);
|
|
5454
|
+
this.orderType = types.OrderType.MARKET;
|
|
5455
|
+
}
|
|
5456
|
+
create(values2) {
|
|
5457
|
+
const order = super.create(values2);
|
|
5458
|
+
return {
|
|
5459
|
+
...order,
|
|
5460
|
+
quantity: order.order_quantity,
|
|
5461
|
+
type: order.order_type,
|
|
5462
|
+
price: order.order_price
|
|
5463
|
+
};
|
|
5464
|
+
}
|
|
5465
|
+
async validate(values2, config) {
|
|
5466
|
+
const value = await super.validate(values2, config);
|
|
5467
|
+
const bracketData = await bracketOrderValidator(values2, config);
|
|
5468
|
+
return { ...value, ...bracketData };
|
|
5469
|
+
}
|
|
5470
|
+
};
|
|
5471
|
+
|
|
5472
|
+
// src/services/orderCreator/fokCreator.ts
|
|
5473
|
+
var FOKOrderCreator = class extends LimitOrderCreator {
|
|
5474
|
+
};
|
|
5475
|
+
|
|
5476
|
+
// src/services/orderCreator/generalCreator.ts
|
|
5477
|
+
var GeneralOrderCreator = class extends BaseOrderCreator {
|
|
5478
|
+
create(data) {
|
|
5479
|
+
return {
|
|
5480
|
+
...this.baseOrder(data),
|
|
5481
|
+
order_price: data.order_price,
|
|
5482
|
+
order_quantity: data.order_quantity
|
|
5483
|
+
};
|
|
5484
|
+
}
|
|
5485
|
+
validate(values2, configs) {
|
|
5486
|
+
return super.baseValidate(values2, configs);
|
|
5487
|
+
}
|
|
5488
|
+
};
|
|
5489
|
+
|
|
5490
|
+
// src/services/orderCreator/iocCreator.ts
|
|
5491
|
+
var IOCOrderCreator = class extends LimitOrderCreator {
|
|
5492
|
+
};
|
|
5493
|
+
|
|
5494
|
+
// src/services/orderCreator/postOnlyCreator.ts
|
|
5495
|
+
var PostOnlyOrderCreator = class extends LimitOrderCreator {
|
|
5496
|
+
};
|
|
5497
|
+
var getCreateOrderUrl = (order) => {
|
|
5498
|
+
const isAlgoOrder = order?.order_type === types.OrderType.STOP_LIMIT || order?.order_type === types.OrderType.STOP_MARKET || order?.order_type === types.OrderType.CLOSE_POSITION || order.algo_type && order.algo_type === types.AlgoOrderRootType.BRACKET || isBracketOrder(order);
|
|
5499
|
+
if (order.order_type === types.OrderType.SCALED) {
|
|
5500
|
+
return "/v1/batch-order";
|
|
5501
|
+
}
|
|
5502
|
+
return isAlgoOrder ? "/v1/algo/order" : "/v1/order";
|
|
5503
|
+
};
|
|
5504
|
+
var getOrderCreator = (order) => {
|
|
5505
|
+
let type;
|
|
5506
|
+
if (isBracketOrder(order)) {
|
|
5507
|
+
type = `${types.AlgoOrderRootType.BRACKET}:${order.order_type}`;
|
|
5508
|
+
} else if (order.order_type === types.OrderType.LIMIT) {
|
|
5509
|
+
type = order.order_type_ext || order.order_type;
|
|
5510
|
+
} else {
|
|
5511
|
+
type = order.order_type;
|
|
5512
|
+
}
|
|
5513
|
+
return OrderFactory.create(type);
|
|
5514
|
+
};
|
|
5515
|
+
var tpslFields = [
|
|
5516
|
+
"tp_trigger_price",
|
|
5517
|
+
"sl_trigger_price",
|
|
5518
|
+
"tp_pnl",
|
|
5519
|
+
"sl_pnl",
|
|
5520
|
+
"tp_offset",
|
|
5521
|
+
"sl_offset",
|
|
5522
|
+
"tp_offset_percentage",
|
|
5523
|
+
"sl_offset_percentage"
|
|
5524
|
+
];
|
|
5525
|
+
var isBracketOrder = (order) => {
|
|
5526
|
+
return !!order.tp_trigger_price || !!order.sl_trigger_price;
|
|
5527
|
+
};
|
|
5528
|
+
var hasTPSL = (order) => {
|
|
5529
|
+
return tpslFields.some((field) => !!order[field]);
|
|
5530
|
+
};
|
|
5531
|
+
function getOrderPrice(order, askAndBid) {
|
|
5532
|
+
const orderPrice = Number(order.order_price);
|
|
5533
|
+
if (order.order_type === types.OrderType.MARKET || order.order_type === types.OrderType.STOP_MARKET) {
|
|
5534
|
+
if (order.side === types.OrderSide.BUY) {
|
|
5535
|
+
return askAndBid[0];
|
|
5536
|
+
} else {
|
|
5537
|
+
return askAndBid[1];
|
|
5538
|
+
}
|
|
5539
|
+
} else {
|
|
5540
|
+
if (order.side === types.OrderSide.BUY) {
|
|
5541
|
+
if (orderPrice >= askAndBid[0]) {
|
|
5542
|
+
return askAndBid[0];
|
|
5543
|
+
} else {
|
|
5544
|
+
return orderPrice;
|
|
5545
|
+
}
|
|
5546
|
+
} else {
|
|
5547
|
+
if (orderPrice <= askAndBid[1]) {
|
|
5548
|
+
return askAndBid[1];
|
|
5549
|
+
} else {
|
|
5550
|
+
return orderPrice;
|
|
5551
|
+
}
|
|
5552
|
+
}
|
|
5553
|
+
}
|
|
5554
|
+
}
|
|
5555
|
+
var getPriceAndQty = (order, symbolInfo, askAndBid) => {
|
|
5556
|
+
let quantity = Number(order.order_quantity);
|
|
5557
|
+
const orderPrice = Number(order.order_price);
|
|
5558
|
+
if (isNaN(quantity) || quantity <= 0) {
|
|
5559
|
+
return null;
|
|
5560
|
+
}
|
|
5561
|
+
if (askAndBid.length === 0) {
|
|
5562
|
+
return null;
|
|
5563
|
+
}
|
|
5564
|
+
if ((order.order_type === types.OrderType.LIMIT || order.order_type === types.OrderType.STOP_LIMIT) && isNaN(orderPrice)) {
|
|
5565
|
+
return null;
|
|
5566
|
+
}
|
|
5567
|
+
let price;
|
|
5568
|
+
if (order.order_type === types.OrderType.SCALED) {
|
|
5569
|
+
price = calcScaledOrderAvgOrderPrice(order, symbolInfo, askAndBid);
|
|
5570
|
+
const orders = calcScaledOrderBatchBody(order, symbolInfo);
|
|
5571
|
+
const sumQtys = orders.reduce((acc, order2) => {
|
|
5572
|
+
return acc.plus(new utils.Decimal(order2.order_quantity));
|
|
5573
|
+
}, utils.zero);
|
|
5574
|
+
quantity = sumQtys.todp(symbolInfo.base_dp).toNumber();
|
|
5575
|
+
if (!quantity || isNaN(quantity)) {
|
|
5576
|
+
return null;
|
|
5577
|
+
}
|
|
5578
|
+
} else {
|
|
5579
|
+
price = getOrderPrice(order, askAndBid);
|
|
5580
|
+
}
|
|
5581
|
+
if (!price || isNaN(price)) {
|
|
5582
|
+
return null;
|
|
5583
|
+
}
|
|
5584
|
+
if (order.side === types.OrderSide.SELL) {
|
|
5585
|
+
quantity = -quantity;
|
|
5586
|
+
}
|
|
5587
|
+
return { price, quantity };
|
|
5588
|
+
};
|
|
5589
|
+
var calcEstLiqPrice = (order, askAndBid, inputs) => {
|
|
5590
|
+
const { symbolInfo } = inputs;
|
|
5591
|
+
const result = getPriceAndQty(order, symbolInfo, askAndBid);
|
|
5592
|
+
if (!result)
|
|
5593
|
+
return null;
|
|
5594
|
+
const { price, quantity } = result;
|
|
5595
|
+
if (!price || !quantity)
|
|
5596
|
+
return null;
|
|
5597
|
+
const {
|
|
5598
|
+
symbol,
|
|
5599
|
+
imr_factor,
|
|
5600
|
+
markPrice,
|
|
5601
|
+
totalCollateral,
|
|
5602
|
+
futures_taker_fee_rate,
|
|
5603
|
+
positions: positions3
|
|
5604
|
+
} = inputs;
|
|
5605
|
+
const orderFee = perp.order.orderFee({
|
|
5606
|
+
qty: quantity,
|
|
5607
|
+
price,
|
|
5608
|
+
futuresTakeFeeRate: Number(futures_taker_fee_rate) / 1e4
|
|
5609
|
+
});
|
|
5610
|
+
const liqPrice = perp.order.estLiqPrice({
|
|
5611
|
+
markPrice,
|
|
5612
|
+
baseIMR: symbolInfo.base_imr,
|
|
5613
|
+
baseMMR: symbolInfo.base_mmr,
|
|
5614
|
+
totalCollateral,
|
|
5615
|
+
positions: positions3 == null ? [] : positions3,
|
|
5616
|
+
IMR_Factor: imr_factor,
|
|
5617
|
+
orderFee,
|
|
5618
|
+
newOrder: {
|
|
5619
|
+
qty: quantity,
|
|
5620
|
+
price,
|
|
5621
|
+
symbol
|
|
5622
|
+
}
|
|
5623
|
+
});
|
|
5624
|
+
if (liqPrice <= 0)
|
|
5625
|
+
return null;
|
|
5626
|
+
return liqPrice;
|
|
5627
|
+
};
|
|
5628
|
+
var calcEstLeverage = (order, askAndBid, inputs) => {
|
|
5629
|
+
const { totalCollateral, positions: positions3, symbol, symbolInfo } = inputs;
|
|
5630
|
+
const result = getPriceAndQty(order, symbolInfo, askAndBid);
|
|
5631
|
+
if (!result)
|
|
5632
|
+
return null;
|
|
5633
|
+
const { price, quantity } = result;
|
|
5634
|
+
if (!price || !quantity)
|
|
5635
|
+
return null;
|
|
5636
|
+
return perp.order.estLeverage({
|
|
5637
|
+
totalCollateral,
|
|
5638
|
+
positions: positions3,
|
|
5639
|
+
newOrder: {
|
|
5640
|
+
symbol,
|
|
5641
|
+
qty: result.quantity,
|
|
5642
|
+
price: result.price
|
|
5643
|
+
}
|
|
5644
|
+
});
|
|
5645
|
+
};
|
|
5646
|
+
function isBBOOrder(options) {
|
|
5647
|
+
const { order_type, order_type_ext } = options;
|
|
5648
|
+
return order_type === types.OrderType.LIMIT && [types.OrderType.ASK, types.OrderType.BID].includes(order_type_ext);
|
|
5649
|
+
}
|
|
5650
|
+
function calcScaledOrderPrices(inputs) {
|
|
5651
|
+
const { min_price, max_price, total_orders, quote_dp } = inputs;
|
|
5652
|
+
if (!min_price || !max_price || !total_orders) {
|
|
5653
|
+
return [];
|
|
5654
|
+
}
|
|
5655
|
+
const minPrice3 = new utils.Decimal(min_price);
|
|
5656
|
+
const maxPrice3 = new utils.Decimal(max_price);
|
|
5657
|
+
const totalOrders = Number(total_orders);
|
|
5658
|
+
const priceStep = maxPrice3.minus(minPrice3).div(totalOrders - 1);
|
|
5659
|
+
const prices = [];
|
|
5660
|
+
for (let i = 0; i < totalOrders; i++) {
|
|
5661
|
+
prices[i] = minPrice3.plus(priceStep.mul(i)).todp(quote_dp).toString();
|
|
5662
|
+
}
|
|
5663
|
+
return prices;
|
|
5664
|
+
}
|
|
5665
|
+
function getScaledOrderSkew(inputs) {
|
|
5666
|
+
const { skew, distribution_type, total_orders } = inputs;
|
|
5667
|
+
if (distribution_type === types.DistributionType.FLAT) {
|
|
5668
|
+
return 1;
|
|
5669
|
+
} else if (distribution_type === types.DistributionType.ASCENDING) {
|
|
5670
|
+
return total_orders;
|
|
5671
|
+
} else if (distribution_type === types.DistributionType.DESCENDING) {
|
|
5672
|
+
return 1 / total_orders;
|
|
5673
|
+
}
|
|
5674
|
+
return skew;
|
|
5675
|
+
}
|
|
5676
|
+
function calcScaledOrderWeights(inputs) {
|
|
5677
|
+
const { total_orders, distribution_type, skew } = inputs;
|
|
5678
|
+
const weights = [];
|
|
5679
|
+
if (!total_orders || !distribution_type || distribution_type === types.DistributionType.CUSTOM && (!skew || skew <= 0 || skew > 100)) {
|
|
5680
|
+
return {
|
|
5681
|
+
weights: [],
|
|
5682
|
+
sumWeights: 0,
|
|
5683
|
+
minWeight: 0
|
|
5684
|
+
};
|
|
5685
|
+
}
|
|
5686
|
+
const totalOrders = Number(total_orders);
|
|
5687
|
+
const skewNum = getScaledOrderSkew({
|
|
5688
|
+
skew,
|
|
5689
|
+
distribution_type,
|
|
5690
|
+
total_orders: totalOrders
|
|
5691
|
+
});
|
|
5692
|
+
for (let i = 0; i < totalOrders; i++) {
|
|
5693
|
+
weights[i] = 1 + (skewNum - 1) * i / (totalOrders - 1);
|
|
5694
|
+
}
|
|
5695
|
+
const sumWeights = weights.reduce((acc, cur) => acc + cur, 0);
|
|
5696
|
+
const minWeight = weights.reduce(
|
|
5697
|
+
(min3, current) => current < min3 ? current : min3,
|
|
5698
|
+
weights?.[0]
|
|
5699
|
+
);
|
|
5700
|
+
return {
|
|
5701
|
+
weights,
|
|
5702
|
+
sumWeights,
|
|
5703
|
+
minWeight
|
|
5704
|
+
};
|
|
5705
|
+
}
|
|
5706
|
+
function calcScaledOrderQtys(inputs) {
|
|
5707
|
+
const {
|
|
5708
|
+
order_quantity = 0,
|
|
5709
|
+
total_orders = 0,
|
|
5710
|
+
distribution_type,
|
|
5711
|
+
skew,
|
|
5712
|
+
base_dp,
|
|
5713
|
+
base_tick
|
|
5714
|
+
} = inputs;
|
|
5715
|
+
const qtys = [];
|
|
5716
|
+
if (!order_quantity || !total_orders) {
|
|
5717
|
+
return [];
|
|
5718
|
+
}
|
|
5719
|
+
const { weights, sumWeights } = calcScaledOrderWeights({
|
|
5720
|
+
total_orders,
|
|
5721
|
+
distribution_type,
|
|
5722
|
+
skew
|
|
5723
|
+
});
|
|
5724
|
+
for (let i = 0; i < total_orders; i++) {
|
|
5725
|
+
let qty = new utils.Decimal(order_quantity).mul(weights[i]).div(sumWeights);
|
|
5726
|
+
if (base_tick > 1) {
|
|
5727
|
+
qty = qty.div(base_tick).todp(0, utils.Decimal.ROUND_DOWN).mul(base_tick);
|
|
5728
|
+
} else {
|
|
5729
|
+
qty = qty.todp(base_dp);
|
|
5730
|
+
}
|
|
5731
|
+
qtys[i] = qty.toString();
|
|
5732
|
+
}
|
|
5733
|
+
return qtys;
|
|
5734
|
+
}
|
|
5735
|
+
function calcScaledOrderBatchBody(order, symbolInfo) {
|
|
5736
|
+
if (!validateScaledOrderInput(order)) {
|
|
5737
|
+
return [];
|
|
5738
|
+
}
|
|
5739
|
+
try {
|
|
5740
|
+
const { base_dp, quote_dp, base_tick } = symbolInfo;
|
|
5741
|
+
const {
|
|
5742
|
+
symbol,
|
|
5743
|
+
side,
|
|
5744
|
+
order_quantity,
|
|
5745
|
+
min_price,
|
|
5746
|
+
max_price,
|
|
5747
|
+
total_orders,
|
|
5748
|
+
distribution_type,
|
|
5749
|
+
skew,
|
|
5750
|
+
reduce_only,
|
|
5751
|
+
visible_quantity
|
|
5752
|
+
} = order;
|
|
5753
|
+
const prices = calcScaledOrderPrices({
|
|
5754
|
+
min_price,
|
|
5755
|
+
max_price,
|
|
5756
|
+
total_orders,
|
|
5757
|
+
quote_dp
|
|
5758
|
+
});
|
|
5759
|
+
const qtys = calcScaledOrderQtys({
|
|
5760
|
+
side,
|
|
5761
|
+
order_quantity,
|
|
5762
|
+
total_orders,
|
|
5763
|
+
distribution_type,
|
|
5764
|
+
skew,
|
|
5765
|
+
base_dp,
|
|
5766
|
+
base_tick
|
|
5767
|
+
});
|
|
5768
|
+
const now = Date.now();
|
|
5769
|
+
const orders = prices.map((price, index) => {
|
|
5770
|
+
const subOrder = {
|
|
5771
|
+
symbol,
|
|
5772
|
+
side,
|
|
5773
|
+
// this order type is scaled order, so we need to set the order type to limit
|
|
5774
|
+
order_type: types.OrderType.LIMIT,
|
|
5775
|
+
order_quantity: qtys[index],
|
|
5776
|
+
order_price: price,
|
|
5777
|
+
reduce_only,
|
|
5778
|
+
// it will be used for identify the scaled order from ws
|
|
5779
|
+
client_order_id: `scaled_${index}_${now}`
|
|
5780
|
+
};
|
|
5781
|
+
if (visible_quantity === 0) {
|
|
5782
|
+
subOrder.visible_quantity = visible_quantity;
|
|
5783
|
+
}
|
|
5784
|
+
return subOrder;
|
|
5785
|
+
});
|
|
5786
|
+
return orders;
|
|
5787
|
+
} catch (error) {
|
|
5788
|
+
return [];
|
|
5789
|
+
}
|
|
5790
|
+
}
|
|
5791
|
+
function calcScaledOrderAvgOrderPrice(order, symbolInfo, askAndBid) {
|
|
5792
|
+
if (!validateScaledOrderInput(order)) {
|
|
5793
|
+
return null;
|
|
5794
|
+
}
|
|
5795
|
+
try {
|
|
5796
|
+
const orders = calcScaledOrderBatchBody(order, symbolInfo);
|
|
5797
|
+
const sumQtys = orders.reduce((acc, order2) => {
|
|
5798
|
+
return acc.plus(new utils.Decimal(order2.order_quantity));
|
|
5799
|
+
}, utils.zero);
|
|
5800
|
+
const totalNational = orders.reduce((acc, order2) => {
|
|
5801
|
+
const orderPrice = getOrderPrice(order2, askAndBid);
|
|
5802
|
+
return acc.plus(new utils.Decimal(orderPrice).mul(order2.order_quantity));
|
|
5803
|
+
}, utils.zero);
|
|
5804
|
+
return totalNational.div(sumQtys).todp(symbolInfo.quote_dp).toNumber();
|
|
5805
|
+
} catch (error) {
|
|
5806
|
+
return null;
|
|
5807
|
+
}
|
|
5808
|
+
}
|
|
5809
|
+
function validateScaledOrderInput(order) {
|
|
5810
|
+
const {
|
|
5811
|
+
min_price,
|
|
5812
|
+
max_price,
|
|
5813
|
+
order_quantity,
|
|
5814
|
+
total_orders,
|
|
5815
|
+
distribution_type,
|
|
5816
|
+
skew
|
|
5817
|
+
} = order;
|
|
5818
|
+
if (!min_price || !max_price || !order_quantity || !total_orders || !distribution_type || distribution_type === types.DistributionType.CUSTOM && (!skew || skew <= 0 || skew > 100) || total_orders < 2 || total_orders > 20) {
|
|
5819
|
+
return false;
|
|
5820
|
+
}
|
|
5821
|
+
return true;
|
|
5822
|
+
}
|
|
5823
|
+
function calcScaledOrderMinTotalAmount(order, symbolInfo, askAndBid) {
|
|
5824
|
+
try {
|
|
5825
|
+
const minTotalAmount_baseMin = calcScaledOrderMinTotalAmountByBaseMin(
|
|
5826
|
+
order,
|
|
5827
|
+
symbolInfo
|
|
5828
|
+
);
|
|
5829
|
+
const minTotalAmount_minNotional = calcScaledOrderMinTotalAmountByMinNotional(order, symbolInfo, askAndBid);
|
|
5830
|
+
const minTotalAmount = Math.max(
|
|
5831
|
+
minTotalAmount_baseMin,
|
|
5832
|
+
minTotalAmount_minNotional
|
|
5833
|
+
);
|
|
5834
|
+
return minTotalAmount;
|
|
5835
|
+
} catch (error) {
|
|
5836
|
+
return null;
|
|
5837
|
+
}
|
|
5838
|
+
}
|
|
5839
|
+
function calcScaledOrderMinTotalAmountByBaseMin(order, symbolInfo) {
|
|
5840
|
+
const { total_orders, distribution_type, skew } = order;
|
|
5841
|
+
const { base_min, base_dp } = symbolInfo;
|
|
5842
|
+
const { sumWeights, minWeight } = calcScaledOrderWeights({
|
|
5843
|
+
total_orders,
|
|
5844
|
+
distribution_type,
|
|
5845
|
+
skew
|
|
5846
|
+
});
|
|
5847
|
+
const minTotalAmount = new utils.Decimal(base_min).mul(new utils.Decimal(sumWeights).div(minWeight)).todp(base_dp, utils.Decimal.ROUND_UP).toNumber();
|
|
5848
|
+
return minTotalAmount;
|
|
5849
|
+
}
|
|
5850
|
+
function calcScaledOrderMinTotalAmountByMinNotional(order, symbolInfo, askAndBid) {
|
|
5851
|
+
const { base_dp, min_notional } = symbolInfo;
|
|
5852
|
+
const orders = calcScaledOrderBatchBody(order, symbolInfo);
|
|
5853
|
+
const { total_orders, distribution_type, skew } = order;
|
|
5854
|
+
const { weights, sumWeights } = calcScaledOrderWeights({
|
|
5855
|
+
total_orders,
|
|
5856
|
+
distribution_type,
|
|
5857
|
+
skew
|
|
5858
|
+
});
|
|
5859
|
+
const minQtys = orders.map((order2, i) => {
|
|
5860
|
+
const orderPrice = getOrderPrice(order2, askAndBid);
|
|
5861
|
+
return new utils.Decimal(min_notional).mul(sumWeights).div(new utils.Decimal(weights[i]).mul(orderPrice));
|
|
5862
|
+
});
|
|
5863
|
+
const max_minQty = minQtys.reduce(
|
|
5864
|
+
(max3, current) => current.gt(max3) ? current : max3,
|
|
5865
|
+
minQtys?.[0]
|
|
5866
|
+
);
|
|
5867
|
+
return max_minQty.todp(base_dp, utils.Decimal.ROUND_UP).toNumber();
|
|
5868
|
+
}
|
|
5869
|
+
|
|
5870
|
+
// src/services/orderCreator/scaledOrderCreator.ts
|
|
5871
|
+
var ScaledOrderCreator = class extends BaseOrderCreator {
|
|
5872
|
+
constructor() {
|
|
5873
|
+
super(...arguments);
|
|
5874
|
+
this.orderType = types.OrderType.SCALED;
|
|
5875
|
+
}
|
|
5876
|
+
create(values2, config) {
|
|
5877
|
+
const orders = calcScaledOrderBatchBody(values2, config.symbol);
|
|
5878
|
+
const { total_orders, distribution_type, skew } = values2;
|
|
5879
|
+
const order = {
|
|
5880
|
+
...this.baseOrder(values2),
|
|
5881
|
+
total_orders,
|
|
5882
|
+
distribution_type,
|
|
5883
|
+
skew,
|
|
5884
|
+
orders
|
|
5885
|
+
};
|
|
5886
|
+
return ramda.pick(
|
|
5887
|
+
[
|
|
5888
|
+
"symbol",
|
|
5889
|
+
"order_quantity",
|
|
5890
|
+
"visible_quantity",
|
|
5891
|
+
"reduce_only",
|
|
5892
|
+
"side",
|
|
5893
|
+
"order_type",
|
|
5894
|
+
"orders",
|
|
5895
|
+
"total_orders",
|
|
5896
|
+
"distribution_type",
|
|
5897
|
+
"skew"
|
|
5898
|
+
],
|
|
5899
|
+
order
|
|
5900
|
+
);
|
|
5901
|
+
}
|
|
5902
|
+
validatePrice(values2, config) {
|
|
5903
|
+
const errors = {};
|
|
5904
|
+
const { side, min_price, max_price } = values2;
|
|
5905
|
+
const { price_range, price_scope, quote_max, quote_min, quote_dp } = config.symbol;
|
|
5906
|
+
const maxPriceNumber = perp.order.maxPrice(config.markPrice, price_range);
|
|
5907
|
+
const minPriceNumber = perp.order.minPrice(config.markPrice, price_range);
|
|
5908
|
+
const scopePriceNumber = perp.order.scopePrice(
|
|
5909
|
+
config.markPrice,
|
|
5910
|
+
price_scope,
|
|
5911
|
+
side
|
|
5912
|
+
);
|
|
5913
|
+
const priceRange = side === types.OrderSide.BUY ? {
|
|
5914
|
+
min: scopePriceNumber,
|
|
5915
|
+
max: maxPriceNumber
|
|
5916
|
+
} : {
|
|
5917
|
+
min: minPriceNumber,
|
|
5918
|
+
max: scopePriceNumber
|
|
5919
|
+
};
|
|
5920
|
+
const minPrice3 = Number(min_price || 0);
|
|
5921
|
+
const maxPrice3 = Number(max_price || 0);
|
|
5922
|
+
if (!min_price) {
|
|
5923
|
+
errors.min_price = OrderValidation.required("min_price");
|
|
5924
|
+
} else {
|
|
5925
|
+
if (minPrice3 < priceRange?.min) {
|
|
5926
|
+
errors.min_price = OrderValidation.min(
|
|
5927
|
+
"min_price",
|
|
5928
|
+
new utils.Decimal(priceRange.min).todp(quote_dp).toString()
|
|
5929
|
+
);
|
|
5930
|
+
} else if (minPrice3 < quote_min) {
|
|
5931
|
+
errors.min_price = OrderValidation.min("min_price", quote_min);
|
|
5932
|
+
} else if (minPrice3 > maxPrice3) {
|
|
5933
|
+
errors.min_price = OrderValidation.max("min_price", max_price);
|
|
5934
|
+
}
|
|
5935
|
+
}
|
|
5936
|
+
if (!max_price) {
|
|
5937
|
+
errors.max_price = OrderValidation.required("max_price");
|
|
5938
|
+
} else {
|
|
5939
|
+
if (maxPrice3 < priceRange?.min) {
|
|
5940
|
+
errors.max_price = OrderValidation.min(
|
|
5941
|
+
"max_price",
|
|
5942
|
+
new utils.Decimal(priceRange.min).todp(quote_dp).toString()
|
|
5943
|
+
);
|
|
5944
|
+
} else if (maxPrice3 > priceRange?.max) {
|
|
5945
|
+
errors.max_price = OrderValidation.max(
|
|
5946
|
+
"max_price",
|
|
5947
|
+
new utils.Decimal(priceRange.max).todp(quote_dp).toString()
|
|
5948
|
+
);
|
|
5949
|
+
} else if (maxPrice3 > quote_max) {
|
|
5950
|
+
errors.max_price = OrderValidation.max("max_price", quote_max);
|
|
5951
|
+
}
|
|
5952
|
+
}
|
|
5953
|
+
return errors;
|
|
5954
|
+
}
|
|
5955
|
+
async validate(values2, config) {
|
|
5956
|
+
const { base_dp } = config.symbol;
|
|
5957
|
+
const { maxQty, askAndBid } = config;
|
|
5958
|
+
const { order_quantity, total_orders, distribution_type, skew } = values2;
|
|
5959
|
+
const errors = this.validatePrice(values2, config);
|
|
5960
|
+
if (!total_orders) {
|
|
5961
|
+
errors.total_orders = OrderValidation.required("total_orders");
|
|
5962
|
+
} else {
|
|
5963
|
+
const totalOrdersNum = Number(total_orders);
|
|
5964
|
+
if (totalOrdersNum < 2 || totalOrdersNum > 20) {
|
|
5965
|
+
errors.total_orders = OrderValidation.range("total_orders", 2, 20);
|
|
5966
|
+
}
|
|
5967
|
+
}
|
|
5968
|
+
if (distribution_type === types.DistributionType.CUSTOM) {
|
|
5969
|
+
if (!skew) {
|
|
5970
|
+
errors.skew = OrderValidation.required("skew");
|
|
5971
|
+
} else {
|
|
5972
|
+
const skewNum = Number(skew);
|
|
5973
|
+
if (skewNum <= 0) {
|
|
5974
|
+
errors.skew = OrderValidation.min("skew", 0);
|
|
5975
|
+
} else if (skewNum > 100) {
|
|
5976
|
+
errors.skew = OrderValidation.max("skew", 100);
|
|
5977
|
+
}
|
|
5978
|
+
}
|
|
5979
|
+
}
|
|
5980
|
+
if (!order_quantity) {
|
|
5981
|
+
errors.order_quantity = OrderValidation.required("order_quantity");
|
|
5982
|
+
} else {
|
|
5983
|
+
const qty = new utils.Decimal(order_quantity);
|
|
5984
|
+
if (qty.gt(maxQty)) {
|
|
5985
|
+
errors.order_quantity = OrderValidation.max(
|
|
5986
|
+
"order_quantity",
|
|
5987
|
+
new utils.Decimal(maxQty).todp(base_dp).toString()
|
|
5988
|
+
);
|
|
5989
|
+
} else if (!errors.skew && !errors.total_orders) {
|
|
5990
|
+
const minTotalAmount = calcScaledOrderMinTotalAmount(
|
|
5991
|
+
values2,
|
|
5992
|
+
config.symbol,
|
|
5993
|
+
askAndBid
|
|
5994
|
+
);
|
|
5995
|
+
if (minTotalAmount && qty.lt(minTotalAmount)) {
|
|
5996
|
+
errors.order_quantity = OrderValidation.min(
|
|
5997
|
+
"order_quantity",
|
|
5998
|
+
minTotalAmount
|
|
5999
|
+
);
|
|
6000
|
+
}
|
|
6001
|
+
}
|
|
6002
|
+
}
|
|
6003
|
+
return errors;
|
|
6004
|
+
}
|
|
6005
|
+
};
|
|
6006
|
+
var { maxPrice: maxPrice2, minPrice: minPrice2, scopePrice: scopePrice2 } = perp.order;
|
|
6007
|
+
var StopLimitOrderCreator = class extends BaseOrderCreator {
|
|
6008
|
+
constructor() {
|
|
6009
|
+
super(...arguments);
|
|
6010
|
+
this.orderType = types.OrderType.STOP_LIMIT;
|
|
6011
|
+
}
|
|
6012
|
+
create(values2, config) {
|
|
6013
|
+
this.totalToQuantity(values2, config);
|
|
6014
|
+
const order = {
|
|
6015
|
+
...this.baseOrder(values2),
|
|
6016
|
+
trigger_price: values2.trigger_price,
|
|
6017
|
+
algo_type: types.AlgoOrderRootType.STOP,
|
|
6018
|
+
type: types.OrderType.LIMIT,
|
|
6019
|
+
quantity: values2["order_quantity"],
|
|
6020
|
+
price: values2["order_price"],
|
|
6021
|
+
trigger_price_type: types.TriggerPriceType.MARK_PRICE
|
|
6022
|
+
};
|
|
6023
|
+
return ramda.pick(
|
|
6024
|
+
[
|
|
6025
|
+
"symbol",
|
|
6026
|
+
"trigger_price",
|
|
6027
|
+
"algo_type",
|
|
6028
|
+
"type",
|
|
6029
|
+
"quantity",
|
|
6030
|
+
"price",
|
|
6031
|
+
"trigger_price_type",
|
|
6032
|
+
"side",
|
|
6033
|
+
"reduce_only",
|
|
6034
|
+
"visible_quantity"
|
|
6035
|
+
],
|
|
6036
|
+
order
|
|
6037
|
+
);
|
|
6038
|
+
}
|
|
6039
|
+
validate(values2, config) {
|
|
6040
|
+
return this.baseValidate(values2, config).then((errors) => {
|
|
6041
|
+
const { order_price, trigger_price, side } = values2;
|
|
6042
|
+
const { symbol } = config;
|
|
6043
|
+
const { price_range, price_scope, quote_max, quote_min } = symbol;
|
|
6044
|
+
if (!trigger_price) {
|
|
6045
|
+
errors.trigger_price = OrderValidation.required("trigger_price");
|
|
6046
|
+
}
|
|
6047
|
+
if (!order_price) {
|
|
6048
|
+
errors.order_price = OrderValidation.required("order_price");
|
|
6049
|
+
}
|
|
6050
|
+
if (trigger_price > quote_max) {
|
|
6051
|
+
errors.trigger_price = OrderValidation.max("trigger_price", quote_max);
|
|
6052
|
+
} else if (trigger_price < quote_min) {
|
|
6053
|
+
errors.trigger_price = OrderValidation.min("trigger_price", quote_min);
|
|
6054
|
+
} else {
|
|
6055
|
+
if (trigger_price && order_price) {
|
|
6056
|
+
const price = new utils.Decimal(order_price);
|
|
6057
|
+
const maxPriceNumber = maxPrice2(trigger_price, price_range);
|
|
6058
|
+
const minPriceNumber = minPrice2(trigger_price, price_range);
|
|
6059
|
+
const scropePriceNumbere = scopePrice2(
|
|
6060
|
+
trigger_price,
|
|
6061
|
+
price_scope,
|
|
6062
|
+
side
|
|
6063
|
+
);
|
|
6064
|
+
const priceRange = side === "BUY" ? {
|
|
6065
|
+
min: scropePriceNumbere,
|
|
6066
|
+
max: maxPriceNumber
|
|
6067
|
+
} : {
|
|
6068
|
+
min: minPriceNumber,
|
|
6069
|
+
max: scropePriceNumbere
|
|
6070
|
+
};
|
|
6071
|
+
if (price.gt(quote_max)) {
|
|
6072
|
+
errors.order_price = OrderValidation.max("order_price", quote_max);
|
|
6073
|
+
} else {
|
|
6074
|
+
if (price.gt(priceRange?.max)) {
|
|
6075
|
+
errors.order_price = OrderValidation.max(
|
|
6076
|
+
"order_price",
|
|
6077
|
+
new utils.Decimal(priceRange.max).todp(symbol.quote_dp).toString()
|
|
6078
|
+
);
|
|
6079
|
+
}
|
|
6080
|
+
}
|
|
6081
|
+
if (price.lt(quote_min)) {
|
|
6082
|
+
errors.order_price = OrderValidation.min("order_price", quote_min);
|
|
6083
|
+
} else {
|
|
6084
|
+
if (price.lt(priceRange?.min)) {
|
|
6085
|
+
errors.order_price = OrderValidation.min(
|
|
6086
|
+
"order_price",
|
|
6087
|
+
new utils.Decimal(priceRange.min).todp(symbol.quote_dp).toString()
|
|
6088
|
+
);
|
|
6089
|
+
}
|
|
6090
|
+
}
|
|
6091
|
+
}
|
|
6092
|
+
}
|
|
6093
|
+
return errors;
|
|
6094
|
+
});
|
|
6095
|
+
}
|
|
6096
|
+
};
|
|
6097
|
+
var StopMarketOrderCreator = class extends BaseOrderCreator {
|
|
6098
|
+
create(values2) {
|
|
6099
|
+
const order = {
|
|
6100
|
+
...this.baseOrder(values2),
|
|
6101
|
+
// order_price: values.order_price,
|
|
6102
|
+
trigger_price: values2.trigger_price,
|
|
6103
|
+
algo_type: types.AlgoOrderRootType.STOP,
|
|
6104
|
+
type: types.OrderType.MARKET,
|
|
6105
|
+
quantity: values2["order_quantity"],
|
|
6106
|
+
// price: values["order_price"],
|
|
6107
|
+
trigger_price_type: types.TriggerPriceType.MARK_PRICE
|
|
6108
|
+
};
|
|
6109
|
+
return ramda.pick(
|
|
5427
6110
|
[
|
|
5428
6111
|
"symbol",
|
|
5429
6112
|
"trigger_price",
|
|
@@ -5456,18 +6139,6 @@ var StopMarketOrderCreator = class extends BaseOrderCreator {
|
|
|
5456
6139
|
});
|
|
5457
6140
|
}
|
|
5458
6141
|
};
|
|
5459
|
-
|
|
5460
|
-
// src/services/orderCreator/postOnlyCreator.ts
|
|
5461
|
-
var PostOnlyOrderCreator = class extends LimitOrderCreator {
|
|
5462
|
-
};
|
|
5463
|
-
|
|
5464
|
-
// src/services/orderCreator/fokCreator.ts
|
|
5465
|
-
var FOKOrderCreator = class extends LimitOrderCreator {
|
|
5466
|
-
};
|
|
5467
|
-
|
|
5468
|
-
// src/services/orderCreator/iocCreator.ts
|
|
5469
|
-
var IOCOrderCreator = class extends LimitOrderCreator {
|
|
5470
|
-
};
|
|
5471
6142
|
var BaseAlgoOrderCreator = class {
|
|
5472
6143
|
/**
|
|
5473
6144
|
* base validate
|
|
@@ -5671,216 +6342,58 @@ var TPSLPositionOrderCreator = class extends BaseAlgoOrderCreator {
|
|
|
5671
6342
|
type: types.OrderType.CLOSE_POSITION,
|
|
5672
6343
|
trigger_price: tp_trigger_price,
|
|
5673
6344
|
trigger_price_type: types.TriggerPriceType.MARK_PRICE,
|
|
5674
|
-
symbol: values2.symbol,
|
|
5675
|
-
is_activated: !!values2.tp_trigger_price
|
|
5676
|
-
});
|
|
5677
|
-
}
|
|
5678
|
-
if (typeof values2.sl_trigger_price !== "undefined") {
|
|
5679
|
-
const sl_trigger_price = !!values2.sl_trigger_price ? new utils.Decimal(values2.sl_trigger_price).todp(config.symbol.quote_dp).toNumber() : values2.sl_trigger_price;
|
|
5680
|
-
child_orders.push({
|
|
5681
|
-
algo_type: types.AlgoOrderType.STOP_LOSS,
|
|
5682
|
-
reduce_only: true,
|
|
5683
|
-
side,
|
|
5684
|
-
type: types.OrderType.CLOSE_POSITION,
|
|
5685
|
-
trigger_price: sl_trigger_price,
|
|
5686
|
-
trigger_price_type: types.TriggerPriceType.MARK_PRICE,
|
|
5687
|
-
symbol: values2.symbol,
|
|
5688
|
-
is_activated: !!values2.sl_trigger_price
|
|
5689
|
-
});
|
|
5690
|
-
}
|
|
5691
|
-
return {
|
|
5692
|
-
algo_type: types.AlgoOrderRootType.POSITIONAL_TP_SL,
|
|
5693
|
-
trigger_price_type: types.TriggerPriceType.MARK_PRICE,
|
|
5694
|
-
// reduce_only: true,
|
|
5695
|
-
symbol: values2.symbol,
|
|
5696
|
-
child_orders
|
|
5697
|
-
};
|
|
5698
|
-
}
|
|
5699
|
-
crateUpdateOrder(values2, oldValue, config) {
|
|
5700
|
-
const data = this.create(values2, config);
|
|
5701
|
-
const newData = [];
|
|
5702
|
-
data.child_orders.forEach((order) => {
|
|
5703
|
-
const oldOrder = oldValue.child_orders?.find(
|
|
5704
|
-
(oldOrder2) => oldOrder2.algo_type === order.algo_type
|
|
5705
|
-
);
|
|
5706
|
-
if (oldOrder) {
|
|
5707
|
-
if (!order.is_activated) {
|
|
5708
|
-
newData.push({
|
|
5709
|
-
is_activated: false,
|
|
5710
|
-
order_id: Number(oldOrder.algo_order_id)
|
|
5711
|
-
});
|
|
5712
|
-
} else if (oldOrder.trigger_price !== order.trigger_price) {
|
|
5713
|
-
newData.push({
|
|
5714
|
-
trigger_price: order.trigger_price,
|
|
5715
|
-
order_id: Number(oldOrder.algo_order_id)
|
|
5716
|
-
});
|
|
5717
|
-
}
|
|
5718
|
-
}
|
|
5719
|
-
});
|
|
5720
|
-
return [
|
|
5721
|
-
{
|
|
5722
|
-
child_orders: newData
|
|
5723
|
-
},
|
|
5724
|
-
data
|
|
5725
|
-
];
|
|
5726
|
-
}
|
|
5727
|
-
};
|
|
5728
|
-
async function bracketOrderValidator(values2, config) {
|
|
5729
|
-
const result = /* @__PURE__ */ Object.create(null);
|
|
5730
|
-
await Promise.resolve();
|
|
5731
|
-
const { tp_trigger_price, sl_trigger_price, side } = values2;
|
|
5732
|
-
const qty = Number(values2.quantity);
|
|
5733
|
-
const maxQty = config.maxQty;
|
|
5734
|
-
const type = values2.order_type;
|
|
5735
|
-
const { quote_max, quote_min, price_scope, quote_dp } = config.symbol ?? {};
|
|
5736
|
-
const mark_price = type === types.OrderType.MARKET ? config.markPrice : values2.order_price ? Number(values2.order_price) : void 0;
|
|
5737
|
-
if (!isNaN(qty) && qty > maxQty) {
|
|
5738
|
-
result.quantity = OrderValidation.max("quantity", config.maxQty);
|
|
5739
|
-
}
|
|
5740
|
-
if (Number(tp_trigger_price) < 0) {
|
|
5741
|
-
result.tp_trigger_price = OrderValidation.min("tp_trigger_price", 0);
|
|
5742
|
-
}
|
|
5743
|
-
if (Number(sl_trigger_price) < 0) {
|
|
5744
|
-
result.sl_trigger_price = OrderValidation.min("sl_trigger_price", 0);
|
|
5745
|
-
}
|
|
5746
|
-
if (side === types.OrderSide.BUY && mark_price) {
|
|
5747
|
-
const slTriggerPriceScope = new utils.Decimal(mark_price * (1 - price_scope)).toDecimalPlaces(quote_dp, utils.Decimal.ROUND_DOWN).toNumber();
|
|
5748
|
-
if (!!sl_trigger_price && Number(sl_trigger_price) < slTriggerPriceScope) {
|
|
5749
|
-
result.sl_trigger_price = OrderValidation.min(
|
|
5750
|
-
"sl_trigger_price",
|
|
5751
|
-
slTriggerPriceScope
|
|
5752
|
-
);
|
|
5753
|
-
}
|
|
5754
|
-
if (!!tp_trigger_price && Number(tp_trigger_price) <= mark_price) {
|
|
5755
|
-
result.tp_trigger_price = OrderValidation.min(
|
|
5756
|
-
"tp_trigger_price",
|
|
5757
|
-
mark_price
|
|
5758
|
-
);
|
|
5759
|
-
}
|
|
5760
|
-
if (!!tp_trigger_price && Number(tp_trigger_price) > quote_max) {
|
|
5761
|
-
result.tp_trigger_price = OrderValidation.max(
|
|
5762
|
-
"tp_trigger_price",
|
|
5763
|
-
quote_max
|
|
5764
|
-
);
|
|
5765
|
-
}
|
|
5766
|
-
if (!!sl_trigger_price && Number(sl_trigger_price) < quote_min) {
|
|
5767
|
-
result.sl_trigger_price = OrderValidation.min(
|
|
5768
|
-
"sl_trigger_price",
|
|
5769
|
-
quote_min
|
|
5770
|
-
);
|
|
5771
|
-
}
|
|
5772
|
-
}
|
|
5773
|
-
if (side === types.OrderSide.SELL && mark_price) {
|
|
5774
|
-
const slTriggerPriceScope = new utils.Decimal(mark_price * (1 + price_scope)).toDecimalPlaces(quote_dp, utils.Decimal.ROUND_DOWN).toNumber();
|
|
5775
|
-
if (!!sl_trigger_price && Number(sl_trigger_price) > slTriggerPriceScope) {
|
|
5776
|
-
result.sl_trigger_price = OrderValidation.max(
|
|
5777
|
-
"sl_trigger_price",
|
|
5778
|
-
slTriggerPriceScope
|
|
5779
|
-
);
|
|
5780
|
-
}
|
|
5781
|
-
if (!!tp_trigger_price && Number(tp_trigger_price) >= mark_price) {
|
|
5782
|
-
result.tp_trigger_price = OrderValidation.max(
|
|
5783
|
-
"tp_trigger_price",
|
|
5784
|
-
mark_price
|
|
5785
|
-
);
|
|
5786
|
-
}
|
|
5787
|
-
if (!!tp_trigger_price && Number(tp_trigger_price) > quote_max) {
|
|
5788
|
-
result.tp_trigger_price = OrderValidation.max(
|
|
5789
|
-
"tp_trigger_price",
|
|
5790
|
-
quote_max
|
|
5791
|
-
);
|
|
5792
|
-
}
|
|
5793
|
-
if (!!sl_trigger_price && Number(sl_trigger_price) < quote_min) {
|
|
5794
|
-
result.sl_trigger_price = OrderValidation.min(
|
|
5795
|
-
"sl_trigger_price",
|
|
5796
|
-
quote_min
|
|
5797
|
-
);
|
|
5798
|
-
}
|
|
5799
|
-
}
|
|
5800
|
-
return Object.keys(result).length > 0 ? result : null;
|
|
5801
|
-
}
|
|
5802
|
-
|
|
5803
|
-
// src/services/orderCreator/bracketLimitOrderCreator.ts
|
|
5804
|
-
var BracketLimitOrderCreator = class extends LimitOrderCreator {
|
|
5805
|
-
// orderType: OrderType;
|
|
5806
|
-
create(values2, config) {
|
|
5807
|
-
const order = super.create(values2, config);
|
|
5808
|
-
return {
|
|
5809
|
-
...order,
|
|
5810
|
-
quantity: order.order_quantity,
|
|
5811
|
-
type: order.order_type,
|
|
5812
|
-
price: order.order_price
|
|
5813
|
-
};
|
|
5814
|
-
}
|
|
5815
|
-
async validate(values2, config) {
|
|
5816
|
-
const value = await super.validate(values2, config);
|
|
5817
|
-
const bracketData = await bracketOrderValidator(values2, config);
|
|
5818
|
-
return { ...value, ...bracketData };
|
|
5819
|
-
}
|
|
5820
|
-
};
|
|
5821
|
-
var BracketMarketOrderCreator = class extends MarketOrderCreator {
|
|
5822
|
-
constructor() {
|
|
5823
|
-
super(...arguments);
|
|
5824
|
-
this.orderType = types.OrderType.MARKET;
|
|
5825
|
-
}
|
|
5826
|
-
create(values2) {
|
|
5827
|
-
const order = super.create(values2);
|
|
6345
|
+
symbol: values2.symbol,
|
|
6346
|
+
is_activated: !!values2.tp_trigger_price
|
|
6347
|
+
});
|
|
6348
|
+
}
|
|
6349
|
+
if (typeof values2.sl_trigger_price !== "undefined") {
|
|
6350
|
+
const sl_trigger_price = !!values2.sl_trigger_price ? new utils.Decimal(values2.sl_trigger_price).todp(config.symbol.quote_dp).toNumber() : values2.sl_trigger_price;
|
|
6351
|
+
child_orders.push({
|
|
6352
|
+
algo_type: types.AlgoOrderType.STOP_LOSS,
|
|
6353
|
+
reduce_only: true,
|
|
6354
|
+
side,
|
|
6355
|
+
type: types.OrderType.CLOSE_POSITION,
|
|
6356
|
+
trigger_price: sl_trigger_price,
|
|
6357
|
+
trigger_price_type: types.TriggerPriceType.MARK_PRICE,
|
|
6358
|
+
symbol: values2.symbol,
|
|
6359
|
+
is_activated: !!values2.sl_trigger_price
|
|
6360
|
+
});
|
|
6361
|
+
}
|
|
5828
6362
|
return {
|
|
5829
|
-
|
|
5830
|
-
|
|
5831
|
-
|
|
5832
|
-
|
|
5833
|
-
|
|
5834
|
-
}
|
|
5835
|
-
async validate(values2, config) {
|
|
5836
|
-
const value = await super.validate(values2, config);
|
|
5837
|
-
const bracketData = await bracketOrderValidator(values2, config);
|
|
5838
|
-
return { ...value, ...bracketData };
|
|
5839
|
-
}
|
|
5840
|
-
};
|
|
5841
|
-
var BBOOrderCreator = class extends BaseOrderCreator {
|
|
5842
|
-
create(values2) {
|
|
5843
|
-
const order = {
|
|
5844
|
-
...this.baseOrder(values2),
|
|
5845
|
-
level: values2.level
|
|
6363
|
+
algo_type: types.AlgoOrderRootType.POSITIONAL_TP_SL,
|
|
6364
|
+
trigger_price_type: types.TriggerPriceType.MARK_PRICE,
|
|
6365
|
+
// reduce_only: true,
|
|
6366
|
+
symbol: values2.symbol,
|
|
6367
|
+
child_orders
|
|
5846
6368
|
};
|
|
5847
|
-
return ramda.pick(
|
|
5848
|
-
[
|
|
5849
|
-
"symbol",
|
|
5850
|
-
"order_quantity",
|
|
5851
|
-
"visible_quantity",
|
|
5852
|
-
"reduce_only",
|
|
5853
|
-
"side",
|
|
5854
|
-
"order_type",
|
|
5855
|
-
"level"
|
|
5856
|
-
],
|
|
5857
|
-
order
|
|
5858
|
-
);
|
|
5859
6369
|
}
|
|
5860
|
-
|
|
5861
|
-
|
|
5862
|
-
|
|
5863
|
-
|
|
5864
|
-
const
|
|
5865
|
-
|
|
5866
|
-
|
|
5867
|
-
|
|
5868
|
-
|
|
5869
|
-
|
|
5870
|
-
|
|
5871
|
-
|
|
5872
|
-
|
|
5873
|
-
|
|
5874
|
-
|
|
5875
|
-
|
|
5876
|
-
|
|
5877
|
-
|
|
5878
|
-
|
|
5879
|
-
value: minNotional
|
|
5880
|
-
};
|
|
6370
|
+
crateUpdateOrder(values2, oldValue, config) {
|
|
6371
|
+
const data = this.create(values2, config);
|
|
6372
|
+
const newData = [];
|
|
6373
|
+
data.child_orders.forEach((order) => {
|
|
6374
|
+
const oldOrder = oldValue.child_orders?.find(
|
|
6375
|
+
(oldOrder2) => oldOrder2.algo_type === order.algo_type
|
|
6376
|
+
);
|
|
6377
|
+
if (oldOrder) {
|
|
6378
|
+
if (!order.is_activated) {
|
|
6379
|
+
newData.push({
|
|
6380
|
+
is_activated: false,
|
|
6381
|
+
order_id: Number(oldOrder.algo_order_id)
|
|
6382
|
+
});
|
|
6383
|
+
} else if (oldOrder.trigger_price !== order.trigger_price) {
|
|
6384
|
+
newData.push({
|
|
6385
|
+
trigger_price: order.trigger_price,
|
|
6386
|
+
order_id: Number(oldOrder.algo_order_id)
|
|
6387
|
+
});
|
|
6388
|
+
}
|
|
5881
6389
|
}
|
|
5882
|
-
return errors;
|
|
5883
6390
|
});
|
|
6391
|
+
return [
|
|
6392
|
+
{
|
|
6393
|
+
child_orders: newData
|
|
6394
|
+
},
|
|
6395
|
+
data
|
|
6396
|
+
];
|
|
5884
6397
|
}
|
|
5885
6398
|
};
|
|
5886
6399
|
|
|
@@ -5909,6 +6422,8 @@ var OrderFactory = class {
|
|
|
5909
6422
|
return new StopLimitOrderCreator();
|
|
5910
6423
|
case types.OrderType.STOP_MARKET:
|
|
5911
6424
|
return new StopMarketOrderCreator();
|
|
6425
|
+
case types.OrderType.SCALED:
|
|
6426
|
+
return new ScaledOrderCreator();
|
|
5912
6427
|
case types.AlgoOrderRootType.TP_SL:
|
|
5913
6428
|
return new TPSLOrderCreator();
|
|
5914
6429
|
case types.AlgoOrderRootType.POSITIONAL_TP_SL:
|
|
@@ -7172,6 +7687,9 @@ var usePrivateDataObserver = (options) => {
|
|
|
7172
7687
|
return () => unsubscribe?.();
|
|
7173
7688
|
}, [account7.accountId]);
|
|
7174
7689
|
const isHoldingInit = React.useRef(false);
|
|
7690
|
+
React.useEffect(() => {
|
|
7691
|
+
isHoldingInit.current = false;
|
|
7692
|
+
}, [state.accountId]);
|
|
7175
7693
|
React.useEffect(() => {
|
|
7176
7694
|
if (!holding) {
|
|
7177
7695
|
return;
|
|
@@ -14531,137 +15049,6 @@ function getQueryParamsFromObject(obj) {
|
|
|
14531
15049
|
}
|
|
14532
15050
|
return queryParams.toString();
|
|
14533
15051
|
}
|
|
14534
|
-
var getCreateOrderUrl = (order) => {
|
|
14535
|
-
const isAlgoOrder = order?.order_type === types.OrderType.STOP_LIMIT || order?.order_type === types.OrderType.STOP_MARKET || order?.order_type === types.OrderType.CLOSE_POSITION || order.algo_type && order.algo_type === types.AlgoOrderRootType.BRACKET || isBracketOrder(order);
|
|
14536
|
-
return isAlgoOrder ? "/v1/algo/order" : "/v1/order";
|
|
14537
|
-
};
|
|
14538
|
-
var getOrderCreator = (order) => {
|
|
14539
|
-
let type;
|
|
14540
|
-
if (isBracketOrder(order)) {
|
|
14541
|
-
type = `${types.AlgoOrderRootType.BRACKET}:${order.order_type}`;
|
|
14542
|
-
} else if (order.order_type === types.OrderType.LIMIT) {
|
|
14543
|
-
type = order.order_type_ext || order.order_type;
|
|
14544
|
-
} else {
|
|
14545
|
-
type = order.order_type;
|
|
14546
|
-
}
|
|
14547
|
-
return OrderFactory.create(type);
|
|
14548
|
-
};
|
|
14549
|
-
var tpslFields = [
|
|
14550
|
-
"tp_trigger_price",
|
|
14551
|
-
"sl_trigger_price",
|
|
14552
|
-
"tp_pnl",
|
|
14553
|
-
"sl_pnl",
|
|
14554
|
-
"tp_offset",
|
|
14555
|
-
"sl_offset",
|
|
14556
|
-
"tp_offset_percentage",
|
|
14557
|
-
"sl_offset_percentage"
|
|
14558
|
-
];
|
|
14559
|
-
var isBracketOrder = (order) => {
|
|
14560
|
-
return !!order.tp_trigger_price || !!order.sl_trigger_price;
|
|
14561
|
-
};
|
|
14562
|
-
var hasTPSL = (order) => {
|
|
14563
|
-
return tpslFields.some((field) => !!order[field]);
|
|
14564
|
-
};
|
|
14565
|
-
var getPriceAndQty = (symbolOrOrder, askAndBid) => {
|
|
14566
|
-
let quantity = Number(symbolOrOrder.order_quantity);
|
|
14567
|
-
const orderPrice = Number(symbolOrOrder.order_price);
|
|
14568
|
-
if (isNaN(quantity) || quantity <= 0) {
|
|
14569
|
-
return null;
|
|
14570
|
-
}
|
|
14571
|
-
if (askAndBid.length === 0) {
|
|
14572
|
-
return null;
|
|
14573
|
-
}
|
|
14574
|
-
if ((symbolOrOrder.order_type === types.OrderType.LIMIT || symbolOrOrder.order_type === types.OrderType.STOP_LIMIT) && isNaN(orderPrice))
|
|
14575
|
-
return null;
|
|
14576
|
-
let price;
|
|
14577
|
-
if (symbolOrOrder.order_type === types.OrderType.MARKET || symbolOrOrder.order_type === types.OrderType.STOP_MARKET) {
|
|
14578
|
-
if (symbolOrOrder.side === types.OrderSide.BUY) {
|
|
14579
|
-
price = askAndBid[0];
|
|
14580
|
-
} else {
|
|
14581
|
-
price = askAndBid[1];
|
|
14582
|
-
}
|
|
14583
|
-
} else {
|
|
14584
|
-
if (symbolOrOrder.side === types.OrderSide.BUY) {
|
|
14585
|
-
if (orderPrice >= askAndBid[0]) {
|
|
14586
|
-
price = askAndBid[0];
|
|
14587
|
-
} else {
|
|
14588
|
-
price = orderPrice;
|
|
14589
|
-
}
|
|
14590
|
-
} else {
|
|
14591
|
-
if (orderPrice <= askAndBid[1]) {
|
|
14592
|
-
price = askAndBid[1];
|
|
14593
|
-
} else {
|
|
14594
|
-
price = orderPrice;
|
|
14595
|
-
}
|
|
14596
|
-
}
|
|
14597
|
-
}
|
|
14598
|
-
if (symbolOrOrder.side === types.OrderSide.SELL) {
|
|
14599
|
-
quantity = -quantity;
|
|
14600
|
-
}
|
|
14601
|
-
return { price, quantity };
|
|
14602
|
-
};
|
|
14603
|
-
var calcEstLiqPrice = (order, askAndBid, inputs) => {
|
|
14604
|
-
const result = getPriceAndQty(order, askAndBid);
|
|
14605
|
-
if (!result)
|
|
14606
|
-
return null;
|
|
14607
|
-
const { price, quantity } = result;
|
|
14608
|
-
if (!price || !quantity)
|
|
14609
|
-
return null;
|
|
14610
|
-
const {
|
|
14611
|
-
symbol,
|
|
14612
|
-
baseIMR,
|
|
14613
|
-
baseMMR,
|
|
14614
|
-
imr_factor,
|
|
14615
|
-
markPrice,
|
|
14616
|
-
totalCollateral,
|
|
14617
|
-
futures_taker_fee_rate,
|
|
14618
|
-
positions: positions3
|
|
14619
|
-
} = inputs;
|
|
14620
|
-
const orderFee = perp.order.orderFee({
|
|
14621
|
-
qty: quantity,
|
|
14622
|
-
price,
|
|
14623
|
-
futuresTakeFeeRate: Number(futures_taker_fee_rate) / 1e4
|
|
14624
|
-
});
|
|
14625
|
-
const liqPrice = perp.order.estLiqPrice({
|
|
14626
|
-
markPrice,
|
|
14627
|
-
baseIMR,
|
|
14628
|
-
baseMMR,
|
|
14629
|
-
totalCollateral,
|
|
14630
|
-
positions: positions3 == null ? [] : positions3,
|
|
14631
|
-
IMR_Factor: imr_factor,
|
|
14632
|
-
orderFee,
|
|
14633
|
-
newOrder: {
|
|
14634
|
-
qty: quantity,
|
|
14635
|
-
price,
|
|
14636
|
-
symbol
|
|
14637
|
-
}
|
|
14638
|
-
});
|
|
14639
|
-
if (liqPrice <= 0)
|
|
14640
|
-
return null;
|
|
14641
|
-
return liqPrice;
|
|
14642
|
-
};
|
|
14643
|
-
var calcEstLeverage = (order, askAndBid, inputs) => {
|
|
14644
|
-
const result = getPriceAndQty(order, askAndBid);
|
|
14645
|
-
const { totalCollateral, positions: positions3, symbol } = inputs;
|
|
14646
|
-
if (!result)
|
|
14647
|
-
return null;
|
|
14648
|
-
const { price, quantity } = result;
|
|
14649
|
-
if (!price || !quantity)
|
|
14650
|
-
return null;
|
|
14651
|
-
return perp.order.estLeverage({
|
|
14652
|
-
totalCollateral,
|
|
14653
|
-
positions: positions3,
|
|
14654
|
-
newOrder: {
|
|
14655
|
-
symbol,
|
|
14656
|
-
qty: result.quantity,
|
|
14657
|
-
price: result.price
|
|
14658
|
-
}
|
|
14659
|
-
});
|
|
14660
|
-
};
|
|
14661
|
-
function isBBOOrder(options) {
|
|
14662
|
-
const { order_type, order_type_ext } = options;
|
|
14663
|
-
return order_type === types.OrderType.LIMIT && [types.OrderType.ASK, types.OrderType.BID].includes(order_type_ext);
|
|
14664
|
-
}
|
|
14665
15052
|
var initialOrderState = {
|
|
14666
15053
|
order_price: "",
|
|
14667
15054
|
order_quantity: "",
|
|
@@ -14674,7 +15061,12 @@ var initialOrderState = {
|
|
|
14674
15061
|
sl_offset_percentage: "",
|
|
14675
15062
|
tp_offset: "",
|
|
14676
15063
|
sl_offset: "",
|
|
14677
|
-
total: ""
|
|
15064
|
+
total: "",
|
|
15065
|
+
min_price: "",
|
|
15066
|
+
max_price: "",
|
|
15067
|
+
totalOrders: "",
|
|
15068
|
+
distribution_type: "",
|
|
15069
|
+
skew: ""
|
|
14678
15070
|
// symbol: "",
|
|
14679
15071
|
};
|
|
14680
15072
|
var useOrderStore = (initialOrder) => {
|
|
@@ -14911,12 +15303,9 @@ var useOrderEntryNextInternal = (symbol, options = {}) => {
|
|
|
14911
15303
|
[calculate2, options.symbolInfo, orderEntity, orderEntryActions]
|
|
14912
15304
|
);
|
|
14913
15305
|
const validate = (order, creator, options2) => {
|
|
14914
|
-
const { markPrice, maxQty, estSlippage } = options2;
|
|
14915
15306
|
return creator?.validate(order, {
|
|
14916
|
-
|
|
14917
|
-
|
|
14918
|
-
markPrice,
|
|
14919
|
-
estSlippage
|
|
15307
|
+
...options2,
|
|
15308
|
+
symbol: symbolInfo
|
|
14920
15309
|
});
|
|
14921
15310
|
};
|
|
14922
15311
|
const generateOrder = (creator, options2) => {
|
|
@@ -15098,7 +15487,8 @@ var useOrderEntry2 = (symbol, options = {}) => {
|
|
|
15098
15487
|
return {
|
|
15099
15488
|
markPrice: actions.getMarkPriceBySymbol(symbol),
|
|
15100
15489
|
maxQty,
|
|
15101
|
-
estSlippage
|
|
15490
|
+
estSlippage,
|
|
15491
|
+
askAndBid: askAndBid.current?.[0] || []
|
|
15102
15492
|
};
|
|
15103
15493
|
}, [maxQty, symbol, estSlippage]);
|
|
15104
15494
|
const interactiveValidate = (order) => {
|
|
@@ -15198,25 +15588,36 @@ var useOrderEntry2 = (symbol, options = {}) => {
|
|
|
15198
15588
|
const { freeCollateral, totalCollateral } = useCollateral();
|
|
15199
15589
|
const estLiqPrice = React.useMemo(() => {
|
|
15200
15590
|
const markPrice2 = actions.getMarkPriceBySymbol(symbol);
|
|
15201
|
-
if (!markPrice2 || !accountInfo)
|
|
15591
|
+
if (!markPrice2 || !accountInfo || !symbolInfo) {
|
|
15202
15592
|
return null;
|
|
15593
|
+
}
|
|
15203
15594
|
const orderQuantity = Number(formattedOrder.order_quantity);
|
|
15204
15595
|
if (orderQuantity === 0 || orderQuantity > maxQty) {
|
|
15205
15596
|
return null;
|
|
15206
15597
|
}
|
|
15207
15598
|
const estLiqPrice2 = calcEstLiqPrice(formattedOrder, askAndBid.current[0], {
|
|
15208
|
-
baseIMR: symbolInfo?.base_imr,
|
|
15209
|
-
baseMMR: symbolInfo?.base_mmr,
|
|
15210
15599
|
markPrice: markPrice2,
|
|
15211
15600
|
totalCollateral,
|
|
15212
15601
|
futures_taker_fee_rate: accountInfo.futures_taker_fee_rate,
|
|
15213
15602
|
imr_factor: accountInfo.imr_factor[symbol],
|
|
15214
15603
|
symbol,
|
|
15215
|
-
positions: positions3
|
|
15604
|
+
positions: positions3,
|
|
15605
|
+
symbolInfo
|
|
15216
15606
|
});
|
|
15217
15607
|
return estLiqPrice2;
|
|
15218
|
-
}, [
|
|
15608
|
+
}, [
|
|
15609
|
+
formattedOrder,
|
|
15610
|
+
accountInfo,
|
|
15611
|
+
positions3,
|
|
15612
|
+
totalCollateral,
|
|
15613
|
+
symbol,
|
|
15614
|
+
maxQty,
|
|
15615
|
+
symbolInfo
|
|
15616
|
+
]);
|
|
15219
15617
|
const estLeverage = React.useMemo(() => {
|
|
15618
|
+
if (!symbolInfo) {
|
|
15619
|
+
return null;
|
|
15620
|
+
}
|
|
15220
15621
|
const orderQuantity = Number(formattedOrder.order_quantity);
|
|
15221
15622
|
if (orderQuantity === 0 || orderQuantity > maxQty) {
|
|
15222
15623
|
return null;
|
|
@@ -15224,9 +15625,18 @@ var useOrderEntry2 = (symbol, options = {}) => {
|
|
|
15224
15625
|
return calcEstLeverage(formattedOrder, askAndBid.current[0], {
|
|
15225
15626
|
totalCollateral,
|
|
15226
15627
|
positions: positions3,
|
|
15227
|
-
symbol
|
|
15628
|
+
symbol,
|
|
15629
|
+
symbolInfo
|
|
15228
15630
|
});
|
|
15229
|
-
}, [
|
|
15631
|
+
}, [
|
|
15632
|
+
formattedOrder,
|
|
15633
|
+
accountInfo,
|
|
15634
|
+
positions3,
|
|
15635
|
+
totalCollateral,
|
|
15636
|
+
symbol,
|
|
15637
|
+
maxQty,
|
|
15638
|
+
symbolInfo
|
|
15639
|
+
]);
|
|
15230
15640
|
const resetErrors = () => {
|
|
15231
15641
|
setMeta(
|
|
15232
15642
|
immer$1.produce((draft) => {
|
|
@@ -15263,14 +15673,31 @@ var useOrderEntry2 = (symbol, options = {}) => {
|
|
|
15263
15673
|
throw new types.SDKError("Order validation failed");
|
|
15264
15674
|
}
|
|
15265
15675
|
const order = generateOrder(creator, prepareData());
|
|
15266
|
-
const
|
|
15676
|
+
const isScaledOrder = order.order_type === types.OrderType.SCALED;
|
|
15677
|
+
const params = isScaledOrder ? { orders: order.orders } : order;
|
|
15678
|
+
const result = await doCreateOrder(params);
|
|
15267
15679
|
if (result.success) {
|
|
15268
|
-
|
|
15680
|
+
let trackParams = {
|
|
15269
15681
|
side: order.side,
|
|
15270
15682
|
order_type: order.order_type,
|
|
15271
15683
|
tp_sl: hasTPSL(formattedOrder),
|
|
15272
15684
|
symbol: order.symbol
|
|
15273
|
-
}
|
|
15685
|
+
};
|
|
15686
|
+
if (isScaledOrder) {
|
|
15687
|
+
const skew = getScaledOrderSkew({
|
|
15688
|
+
skew: order.skew,
|
|
15689
|
+
distribution_type: order.distribution_type,
|
|
15690
|
+
total_orders: order.total_orders
|
|
15691
|
+
});
|
|
15692
|
+
trackParams = {
|
|
15693
|
+
...trackParams,
|
|
15694
|
+
order_type: "scaled",
|
|
15695
|
+
distribution_type: order.distribution_type,
|
|
15696
|
+
skew: new utils.Decimal(skew).todp(2).toNumber(),
|
|
15697
|
+
total_orders: order.total_orders
|
|
15698
|
+
};
|
|
15699
|
+
}
|
|
15700
|
+
track2(types.TrackerEventName.placeOrderSuccess, trackParams);
|
|
15274
15701
|
}
|
|
15275
15702
|
if (result.success && resetOnSuccess) {
|
|
15276
15703
|
reset();
|
|
@@ -15455,6 +15882,7 @@ var useOrderEntity = (order, options) => {
|
|
|
15455
15882
|
symbolInfo
|
|
15456
15883
|
};
|
|
15457
15884
|
};
|
|
15885
|
+
var canUnblockRegions = ["United States"];
|
|
15458
15886
|
var useRestrictedInfo = (options) => {
|
|
15459
15887
|
const {
|
|
15460
15888
|
enableDefault = false,
|
|
@@ -15462,63 +15890,70 @@ var useRestrictedInfo = (options) => {
|
|
|
15462
15890
|
customRestrictedRegions = [],
|
|
15463
15891
|
content
|
|
15464
15892
|
} = options || {};
|
|
15465
|
-
const apiBaseUrl = useConfig("apiBaseUrl");
|
|
15466
|
-
const [invalidWebCity, setInvalidWebCity] = React.useState([]);
|
|
15467
|
-
const [invalidWebCountry, setInvalidWebCountry] = React.useState([]);
|
|
15468
|
-
const [invalidRegions, setInvalidRegions] = React.useState([]);
|
|
15469
|
-
const [allInvalidAreas, setAllInvalidAreas] = React.useState([]);
|
|
15470
|
-
const [city, setCity] = React.useState("");
|
|
15471
|
-
const [region, setRegion] = React.useState("");
|
|
15472
15893
|
const [ip, setIp] = React.useState("");
|
|
15894
|
+
const [allInvalidAreas, setAllInvalidAreas] = React.useState([]);
|
|
15473
15895
|
const [restrictedOpen, setRestrictedOpen] = React.useState(false);
|
|
15896
|
+
const [canUnblock, setCanUnblock] = React.useState(false);
|
|
15897
|
+
const [accessRestricted, setAccessRestricted] = useLocalStorage("orderly_access_restricted", void 0);
|
|
15898
|
+
const { data: ipInfo } = useQuery("/v1/ip_info");
|
|
15899
|
+
const { data: restrictedAreas } = useQuery(
|
|
15900
|
+
"/v1/restricted_areas"
|
|
15901
|
+
);
|
|
15474
15902
|
React.useEffect(() => {
|
|
15475
|
-
|
|
15476
|
-
|
|
15477
|
-
|
|
15478
|
-
|
|
15479
|
-
|
|
15480
|
-
|
|
15481
|
-
|
|
15482
|
-
|
|
15483
|
-
|
|
15484
|
-
|
|
15485
|
-
|
|
15486
|
-
|
|
15487
|
-
|
|
15488
|
-
|
|
15489
|
-
|
|
15490
|
-
|
|
15491
|
-
|
|
15492
|
-
|
|
15493
|
-
|
|
15494
|
-
|
|
15495
|
-
|
|
15496
|
-
|
|
15497
|
-
|
|
15498
|
-
|
|
15499
|
-
|
|
15500
|
-
|
|
15501
|
-
setIp(ip2);
|
|
15502
|
-
if (combinedInvalidRegions.includes(
|
|
15503
|
-
ipData?.data?.city?.replace(/\s+/g, "").toLocaleLowerCase()
|
|
15504
|
-
) || combinedInvalidRegions.includes(
|
|
15505
|
-
ipData?.data?.region?.replace(/\s+/g, "").toLocaleLowerCase()
|
|
15506
|
-
) || customRestrictedIps.includes(ipData?.data?.ip)) {
|
|
15507
|
-
setRestrictedOpen(true);
|
|
15508
|
-
}
|
|
15903
|
+
if (!restrictedAreas || !ipInfo) {
|
|
15904
|
+
return;
|
|
15905
|
+
}
|
|
15906
|
+
try {
|
|
15907
|
+
const { invalid_web_country, invalid_web_city } = restrictedAreas;
|
|
15908
|
+
const invalidCountries = invalid_web_country?.toLowerCase().replace(/\s+/g, "").split(",");
|
|
15909
|
+
const invalidCities = invalid_web_city?.toLowerCase().replace(/\s+/g, "").split(",");
|
|
15910
|
+
const formattedCustomRegions = customRestrictedRegions?.map(
|
|
15911
|
+
(item) => formatRegion(item)
|
|
15912
|
+
);
|
|
15913
|
+
const combinedInvalidRegions = [
|
|
15914
|
+
...formattedCustomRegions,
|
|
15915
|
+
...enableDefault ? [...invalidCountries, ...invalidCities] : []
|
|
15916
|
+
];
|
|
15917
|
+
const allInvalidAreas2 = [
|
|
15918
|
+
enableDefault ? invalid_web_country : "",
|
|
15919
|
+
enableDefault ? invalid_web_city : "",
|
|
15920
|
+
customRestrictedRegions?.join(", ")
|
|
15921
|
+
].filter((item) => !!item);
|
|
15922
|
+
const { city, region, ip: ip2 } = ipInfo;
|
|
15923
|
+
const formattedCity = formatRegion(city);
|
|
15924
|
+
const formattedRegion = formatRegion(region);
|
|
15925
|
+
const showRestricted = accessRestricted && (combinedInvalidRegions.includes(formattedCity) || combinedInvalidRegions.includes(formattedRegion) || customRestrictedIps.includes(ip2));
|
|
15926
|
+
for (const item of canUnblockRegions) {
|
|
15927
|
+
if (formatRegion(item) === formatRegion(region)) {
|
|
15928
|
+
setCanUnblock(true);
|
|
15509
15929
|
}
|
|
15510
|
-
} catch (error) {
|
|
15511
15930
|
}
|
|
15512
|
-
|
|
15513
|
-
|
|
15514
|
-
|
|
15931
|
+
setIp(ip2);
|
|
15932
|
+
setAllInvalidAreas(allInvalidAreas2);
|
|
15933
|
+
setRestrictedOpen(showRestricted);
|
|
15934
|
+
} catch (error) {
|
|
15935
|
+
}
|
|
15936
|
+
}, [
|
|
15937
|
+
ipInfo,
|
|
15938
|
+
restrictedAreas,
|
|
15939
|
+
enableDefault,
|
|
15940
|
+
customRestrictedIps,
|
|
15941
|
+
customRestrictedRegions,
|
|
15942
|
+
accessRestricted
|
|
15943
|
+
]);
|
|
15515
15944
|
return {
|
|
15516
15945
|
ip,
|
|
15517
15946
|
invalidRegions: allInvalidAreas,
|
|
15518
15947
|
restrictedOpen,
|
|
15519
|
-
content
|
|
15948
|
+
content,
|
|
15949
|
+
canUnblock,
|
|
15950
|
+
accessRestricted,
|
|
15951
|
+
setAccessRestricted
|
|
15520
15952
|
};
|
|
15521
15953
|
};
|
|
15954
|
+
function formatRegion(region) {
|
|
15955
|
+
return region?.replace(/\s+/g, "").toLowerCase();
|
|
15956
|
+
}
|
|
15522
15957
|
var usePositionClose = (options) => {
|
|
15523
15958
|
const { position, order: initialOrder } = options;
|
|
15524
15959
|
const { type, quantity, price } = initialOrder;
|
|
@@ -15526,6 +15961,10 @@ var usePositionClose = (options) => {
|
|
|
15526
15961
|
const [errors, setErrors] = React.useState(null);
|
|
15527
15962
|
const symbolsInfo = useSymbolsInfo();
|
|
15528
15963
|
const { data: markPrices } = useMarkPricesStream();
|
|
15964
|
+
const markPricesRef = React.useRef(markPrices);
|
|
15965
|
+
React.useEffect(() => {
|
|
15966
|
+
markPricesRef.current = markPrices;
|
|
15967
|
+
}, [markPrices]);
|
|
15529
15968
|
const [doCreateOrder, { isMutating }] = useSubAccountMutation(
|
|
15530
15969
|
"/v1/order",
|
|
15531
15970
|
"POST",
|
|
@@ -15574,11 +16013,12 @@ var usePositionClose = (options) => {
|
|
|
15574
16013
|
const errors2 = await creator.validate(data, {
|
|
15575
16014
|
symbol: symbolsInfo[symbol](),
|
|
15576
16015
|
maxQty,
|
|
15577
|
-
|
|
16016
|
+
// use ref to avoid re-render when markPrices change
|
|
16017
|
+
markPrice: markPricesRef.current[symbol]
|
|
15578
16018
|
});
|
|
15579
16019
|
return errors2;
|
|
15580
16020
|
},
|
|
15581
|
-
[
|
|
16021
|
+
[maxQty, symbol, symbolsInfo]
|
|
15582
16022
|
);
|
|
15583
16023
|
React.useEffect(() => {
|
|
15584
16024
|
validate(closeOrderData).then((errors2) => {
|