ccxt 4.1.24 → 4.1.25

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.
Files changed (54) hide show
  1. package/README.md +3 -3
  2. package/dist/ccxt.browser.js +1172 -200
  3. package/dist/ccxt.browser.min.js +4 -4
  4. package/dist/cjs/ccxt.js +1 -1
  5. package/dist/cjs/src/ace.js +1 -1
  6. package/dist/cjs/src/base/Exchange.js +7 -3
  7. package/dist/cjs/src/base/functions/crypto.js +11 -2
  8. package/dist/cjs/src/base/functions/generic.js +5 -3
  9. package/dist/cjs/src/base/functions.js +1 -0
  10. package/dist/cjs/src/binance.js +108 -5
  11. package/dist/cjs/src/bitget.js +289 -21
  12. package/dist/cjs/src/bybit.js +132 -15
  13. package/dist/cjs/src/cryptocom.js +262 -15
  14. package/dist/cjs/src/gate.js +191 -88
  15. package/dist/cjs/src/krakenfutures.js +86 -20
  16. package/dist/cjs/src/oceanex.js +0 -12
  17. package/dist/cjs/src/okx.js +60 -1
  18. package/dist/cjs/src/pro/bybit.js +1 -1
  19. package/dist/cjs/src/static_dependencies/noble-curves/abstract/edwards.js +8 -6
  20. package/dist/cjs/src/wavesexchange.js +6 -6
  21. package/js/ccxt.d.ts +1 -1
  22. package/js/ccxt.js +1 -1
  23. package/js/src/abstract/gate.d.ts +2 -7
  24. package/js/src/abstract/gateio.d.ts +2 -7
  25. package/js/src/ace.js +1 -1
  26. package/js/src/base/Exchange.d.ts +4 -2
  27. package/js/src/base/Exchange.js +7 -3
  28. package/js/src/base/functions/crypto.d.ts +3 -2
  29. package/js/src/base/functions/crypto.js +11 -3
  30. package/js/src/base/functions/generic.d.ts +1 -1
  31. package/js/src/base/functions/generic.js +5 -3
  32. package/js/src/base/types.d.ts +8 -0
  33. package/js/src/binance.d.ts +2 -1
  34. package/js/src/binance.js +108 -5
  35. package/js/src/bitget.d.ts +15 -1
  36. package/js/src/bitget.js +289 -21
  37. package/js/src/bybit.d.ts +4 -2
  38. package/js/src/bybit.js +132 -15
  39. package/js/src/cryptocom.d.ts +4 -1
  40. package/js/src/cryptocom.js +262 -15
  41. package/js/src/gate.d.ts +3 -1
  42. package/js/src/gate.js +191 -88
  43. package/js/src/krakenfutures.d.ts +3 -1
  44. package/js/src/krakenfutures.js +86 -20
  45. package/js/src/oceanex.d.ts +0 -1
  46. package/js/src/oceanex.js +0 -12
  47. package/js/src/okx.d.ts +2 -1
  48. package/js/src/okx.js +60 -1
  49. package/js/src/pro/bybit.js +1 -1
  50. package/js/src/static_dependencies/noble-curves/abstract/edwards.d.ts +1 -0
  51. package/js/src/static_dependencies/noble-curves/abstract/edwards.js +5 -3
  52. package/js/src/wavesexchange.js +7 -7
  53. package/package.json +1 -1
  54. package/skip-tests.json +2 -3
package/js/src/gate.js CHANGED
@@ -82,6 +82,7 @@ export default class gate extends Exchange {
82
82
  'cancelOrder': true,
83
83
  'createMarketOrder': true,
84
84
  'createOrder': true,
85
+ 'createOrders': true,
85
86
  'createPostOnlyOrder': true,
86
87
  'createReduceOnlyOrder': true,
87
88
  'createStopLimitOrder': true,
@@ -287,8 +288,6 @@ export default class gate extends Exchange {
287
288
  },
288
289
  'portfolio': {
289
290
  'get': {
290
- 'spot/currency_pairs': 20 / 15,
291
- 'spot/currency_pairs/{currency_pair}': 20 / 15,
292
291
  'accounts': 20 / 15,
293
292
  'account_mode': 20 / 15,
294
293
  'borrowable': 20 / 15,
@@ -296,19 +295,10 @@ export default class gate extends Exchange {
296
295
  'loans': 20 / 15,
297
296
  'loan_records': 20 / 15,
298
297
  'interest_records': 20 / 15,
299
- 'spot/orders': 20 / 15,
300
- 'spot/orders/{order_id}': 20 / 15,
301
298
  },
302
299
  'post': {
303
300
  'account_mode': 20 / 15,
304
- 'loans': 200 / 15,
305
- 'spot/orders': 20 / 15,
306
- },
307
- 'delete': {
308
- 'spot/orders/{order_id}': 20 / 15,
309
- },
310
- 'patch': {
311
- 'spot/orders/{order_id}': 20 / 15,
301
+ 'loans': 200 / 15, // 15r/10s cost = 20 / 1.5 = 13.33
312
302
  },
313
303
  },
314
304
  'spot': {
@@ -331,6 +321,7 @@ export default class gate extends Exchange {
331
321
  'orders': 0.4,
332
322
  'cancel_batch_orders': 20 / 75,
333
323
  'countdown_cancel_all': 20 / 75,
324
+ 'amend_batch_orders': 0.4,
334
325
  'price_orders': 0.4,
335
326
  },
336
327
  'delete': {
@@ -501,6 +492,9 @@ export default class gate extends Exchange {
501
492
  'post': {
502
493
  'uni/lends': 20 / 15,
503
494
  },
495
+ 'put': {
496
+ 'uni/interest_reinvest': 20 / 15,
497
+ },
504
498
  'patch': {
505
499
  'uni/lends': 20 / 15,
506
500
  },
@@ -3665,6 +3659,156 @@ export default class gate extends Exchange {
3665
3659
  * @returns {object|undefined} [An order structure]{@link https://github.com/ccxt/ccxt/wiki/Manual#order-structure}
3666
3660
  */
3667
3661
  await this.loadMarkets();
3662
+ const market = this.market(symbol);
3663
+ const trigger = this.safeValue(params, 'trigger');
3664
+ const triggerPrice = this.safeValue2(params, 'triggerPrice', 'stopPrice');
3665
+ const stopLossPrice = this.safeValue(params, 'stopLossPrice', triggerPrice);
3666
+ const takeProfitPrice = this.safeValue(params, 'takeProfitPrice');
3667
+ const isStopLossOrder = stopLossPrice !== undefined;
3668
+ const isTakeProfitOrder = takeProfitPrice !== undefined;
3669
+ const isStopOrder = isStopLossOrder || isTakeProfitOrder;
3670
+ const nonTriggerOrder = !isStopOrder && (trigger === undefined);
3671
+ const orderRequest = this.createOrderRequest(symbol, type, side, amount, price, params);
3672
+ let response = undefined;
3673
+ if (market['spot'] || market['margin']) {
3674
+ if (nonTriggerOrder) {
3675
+ response = await this.privateSpotPostOrders(orderRequest);
3676
+ }
3677
+ else {
3678
+ response = await this.privateSpotPostPriceOrders(orderRequest);
3679
+ }
3680
+ }
3681
+ else if (market['swap']) {
3682
+ if (nonTriggerOrder) {
3683
+ response = await this.privateFuturesPostSettleOrders(orderRequest);
3684
+ }
3685
+ else {
3686
+ response = await this.privateFuturesPostSettlePriceOrders(orderRequest);
3687
+ }
3688
+ }
3689
+ else if (market['future']) {
3690
+ if (nonTriggerOrder) {
3691
+ response = await this.privateDeliveryPostSettleOrders(orderRequest);
3692
+ }
3693
+ else {
3694
+ response = await this.privateDeliveryPostSettlePriceOrders(orderRequest);
3695
+ }
3696
+ }
3697
+ else {
3698
+ response = await this.privateOptionsPostOrders(orderRequest);
3699
+ }
3700
+ // const response = await this[method] (this.deepExtend (request, params));
3701
+ //
3702
+ // spot
3703
+ //
3704
+ // {
3705
+ // "id": "95282841887",
3706
+ // "text": "apiv4",
3707
+ // "create_time": "1637383156",
3708
+ // "update_time": "1637383156",
3709
+ // "create_time_ms": 1637383156017,
3710
+ // "update_time_ms": 1637383156017,
3711
+ // "status": "open",
3712
+ // "currency_pair": "ETH_USDT",
3713
+ // "type": "limit",
3714
+ // "account": "spot",
3715
+ // "side": "buy",
3716
+ // "amount": "0.01",
3717
+ // "price": "3500",
3718
+ // "time_in_force": "gtc",
3719
+ // "iceberg": "0",
3720
+ // "left": "0.01",
3721
+ // "fill_price": "0",
3722
+ // "filled_total": "0",
3723
+ // "fee": "0",
3724
+ // "fee_currency": "ETH",
3725
+ // "point_fee": "0",
3726
+ // "gt_fee": "0",
3727
+ // "gt_discount": false,
3728
+ // "rebated_fee": "0",
3729
+ // "rebated_fee_currency": "USDT"
3730
+ // }
3731
+ //
3732
+ // spot conditional
3733
+ //
3734
+ // {"id": 5891843}
3735
+ //
3736
+ // futures, perpetual swaps and options
3737
+ //
3738
+ // {
3739
+ // "id": 95938572327,
3740
+ // "contract": "ETH_USDT",
3741
+ // "mkfr": "0",
3742
+ // "tkfr": "0.0005",
3743
+ // "tif": "gtc",
3744
+ // "is_reduce_only": false,
3745
+ // "create_time": 1637384600.08,
3746
+ // "price": "3000",
3747
+ // "size": 1,
3748
+ // "refr": "0",
3749
+ // "left": 1,
3750
+ // "text": "api",
3751
+ // "fill_price": "0",
3752
+ // "user": 2436035,
3753
+ // "status": "open",
3754
+ // "is_liq": false,
3755
+ // "refu": 0,
3756
+ // "is_close": false,
3757
+ // "iceberg": 0
3758
+ // }
3759
+ //
3760
+ // futures and perpetual swaps conditionals
3761
+ //
3762
+ // {"id": 7615567}
3763
+ //
3764
+ return this.parseOrder(response, market);
3765
+ }
3766
+ async createOrders(orders, params = {}) {
3767
+ /**
3768
+ * @method
3769
+ * @name gate#createOrders
3770
+ * @description create a list of trade orders
3771
+ * @see https://www.gate.io/docs/developers/apiv4/en/#get-a-single-order-2
3772
+ * @see https://www.gate.io/docs/developers/apiv4/en/#create-a-batch-of-orders
3773
+ * @param {Array} orders list of orders to create, each object should contain the parameters required by createOrder, namely symbol, type, side, amount, price and params
3774
+ * @returns {object} an [order structure]{@link https://github.com/ccxt/ccxt/wiki/Manual#order-structure}
3775
+ */
3776
+ await this.loadMarkets();
3777
+ const ordersRequests = [];
3778
+ const orderSymbols = [];
3779
+ for (let i = 0; i < orders.length; i++) {
3780
+ const rawOrder = orders[i];
3781
+ const marketId = this.safeString(rawOrder, 'symbol');
3782
+ orderSymbols.push(marketId);
3783
+ const type = this.safeString(rawOrder, 'type');
3784
+ const side = this.safeString(rawOrder, 'side');
3785
+ const amount = this.safeValue(rawOrder, 'amount');
3786
+ const price = this.safeValue(rawOrder, 'price');
3787
+ const orderParams = this.safeValue(rawOrder, 'params', {});
3788
+ const extendedParams = this.extend(orderParams, params); // the request does not accept extra params since it's a list, so we're extending each order with the common params
3789
+ const triggerValue = this.safeValueN(orderParams, ['triggerPrice', 'stopPrice', 'takeProfitPrice', 'stopLossPrice']);
3790
+ if (triggerValue !== undefined) {
3791
+ throw new NotSupported(this.id + ' createOrders() does not support advanced order properties (stopPrice, takeProfitPrice, stopLossPrice)');
3792
+ }
3793
+ extendedParams['textIsRequired'] = true; // Gate.io requires a text parameter for each order here
3794
+ const orderRequest = this.createOrderRequest(marketId, type, side, amount, price, extendedParams);
3795
+ ordersRequests.push(orderRequest);
3796
+ }
3797
+ const symbols = this.marketSymbols(orderSymbols, undefined, false, true, true);
3798
+ const market = this.market(symbols[0]);
3799
+ if (market['future'] || market['option']) {
3800
+ throw new NotSupported(this.id + ' createOrders() does not support futures or options markets');
3801
+ }
3802
+ let response = undefined;
3803
+ if (market['spot']) {
3804
+ response = await this.privateSpotPostBatchOrders(ordersRequests);
3805
+ }
3806
+ else if (market['swap']) {
3807
+ response = await this.privateFuturesPostSettleBatchOrders(ordersRequests);
3808
+ }
3809
+ return this.parseOrders(response);
3810
+ }
3811
+ createOrderRequest(symbol, type, side, amount, price = undefined, params = {}) {
3668
3812
  const market = this.market(symbol);
3669
3813
  const contract = market['contract'];
3670
3814
  const trigger = this.safeValue(params, 'trigger');
@@ -3677,7 +3821,6 @@ export default class gate extends Exchange {
3677
3821
  if (isStopLossOrder && isTakeProfitOrder) {
3678
3822
  throw new ExchangeError(this.id + ' createOrder() stopLossPrice and takeProfitPrice cannot both be defined');
3679
3823
  }
3680
- let methodTail = 'Orders';
3681
3824
  const reduceOnly = this.safeValue(params, 'reduceOnly');
3682
3825
  const exchangeSpecificTimeInForce = this.safeStringLowerN(params, ['timeInForce', 'tif', 'time_in_force']);
3683
3826
  let postOnly = undefined;
@@ -3790,6 +3933,7 @@ export default class gate extends Exchange {
3790
3933
  }
3791
3934
  }
3792
3935
  let clientOrderId = this.safeString2(params, 'text', 'clientOrderId');
3936
+ const textIsRequired = this.safeValue(params, 'textIsRequired', false);
3793
3937
  if (clientOrderId !== undefined) {
3794
3938
  // user-defined, must follow the rules if not empty
3795
3939
  // prefixed with t-
@@ -3798,12 +3942,18 @@ export default class gate extends Exchange {
3798
3942
  if (clientOrderId.length > 28) {
3799
3943
  throw new BadRequest(this.id + ' createOrder () clientOrderId or text param must be up to 28 characters');
3800
3944
  }
3801
- params = this.omit(params, ['text', 'clientOrderId']);
3945
+ params = this.omit(params, ['text', 'clientOrderId', 'textIsRequired']);
3802
3946
  if (clientOrderId[0] !== 't') {
3803
3947
  clientOrderId = 't-' + clientOrderId;
3804
3948
  }
3805
3949
  request['text'] = clientOrderId;
3806
3950
  }
3951
+ else {
3952
+ if (textIsRequired) {
3953
+ // batchOrders requires text in the request
3954
+ request['text'] = 't-' + this.uuid16();
3955
+ }
3956
+ }
3807
3957
  }
3808
3958
  else {
3809
3959
  if (market['option']) {
@@ -3897,80 +4047,8 @@ export default class gate extends Exchange {
3897
4047
  };
3898
4048
  }
3899
4049
  }
3900
- methodTail = 'PriceOrders';
3901
4050
  }
3902
- const method = this.getSupportedMapping(market['type'], {
3903
- 'spot': 'privateSpotPost' + methodTail,
3904
- 'margin': 'privateSpotPost' + methodTail,
3905
- 'swap': 'privateFuturesPostSettle' + methodTail,
3906
- 'future': 'privateDeliveryPostSettle' + methodTail,
3907
- 'option': 'privateOptionsPostOrders',
3908
- });
3909
- const response = await this[method](this.deepExtend(request, params));
3910
- //
3911
- // spot
3912
- //
3913
- // {
3914
- // "id": "95282841887",
3915
- // "text": "apiv4",
3916
- // "create_time": "1637383156",
3917
- // "update_time": "1637383156",
3918
- // "create_time_ms": 1637383156017,
3919
- // "update_time_ms": 1637383156017,
3920
- // "status": "open",
3921
- // "currency_pair": "ETH_USDT",
3922
- // "type": "limit",
3923
- // "account": "spot",
3924
- // "side": "buy",
3925
- // "amount": "0.01",
3926
- // "price": "3500",
3927
- // "time_in_force": "gtc",
3928
- // "iceberg": "0",
3929
- // "left": "0.01",
3930
- // "fill_price": "0",
3931
- // "filled_total": "0",
3932
- // "fee": "0",
3933
- // "fee_currency": "ETH",
3934
- // "point_fee": "0",
3935
- // "gt_fee": "0",
3936
- // "gt_discount": false,
3937
- // "rebated_fee": "0",
3938
- // "rebated_fee_currency": "USDT"
3939
- // }
3940
- //
3941
- // spot conditional
3942
- //
3943
- // {"id": 5891843}
3944
- //
3945
- // futures, perpetual swaps and options
3946
- //
3947
- // {
3948
- // "id": 95938572327,
3949
- // "contract": "ETH_USDT",
3950
- // "mkfr": "0",
3951
- // "tkfr": "0.0005",
3952
- // "tif": "gtc",
3953
- // "is_reduce_only": false,
3954
- // "create_time": 1637384600.08,
3955
- // "price": "3000",
3956
- // "size": 1,
3957
- // "refr": "0",
3958
- // "left": 1,
3959
- // "text": "api",
3960
- // "fill_price": "0",
3961
- // "user": 2436035,
3962
- // "status": "open",
3963
- // "is_liq": false,
3964
- // "refu": 0,
3965
- // "is_close": false,
3966
- // "iceberg": 0
3967
- // }
3968
- //
3969
- // futures and perpetual swaps conditionals
3970
- //
3971
- // {"id": 7615567}
3972
- //
3973
- return this.parseOrder(response, market);
4051
+ return this.extend(request, params);
3974
4052
  }
3975
4053
  async editOrder(id, symbol, type, side, amount = undefined, price = undefined, params = {}) {
3976
4054
  /**
@@ -4196,6 +4274,22 @@ export default class gate extends Exchange {
4196
4274
  // "order_type": ""
4197
4275
  // }
4198
4276
  //
4277
+ // {
4278
+ // "text": "t-d18baf9ac44d82e2",
4279
+ // "succeeded": false,
4280
+ // "label": "BALANCE_NOT_ENOUGH",
4281
+ // "message": "Not enough balance"
4282
+ // }
4283
+ //
4284
+ const succeeded = this.safeValue(order, 'succeeded', true);
4285
+ if (!succeeded) {
4286
+ // cancelOrders response
4287
+ return this.safeOrder({
4288
+ 'clientOrderId': this.safeString(order, 'text'),
4289
+ 'info': order,
4290
+ 'status': 'rejected',
4291
+ });
4292
+ }
4199
4293
  const put = this.safeValue2(order, 'put', 'initial', {});
4200
4294
  const trigger = this.safeValue(order, 'trigger', {});
4201
4295
  let contract = this.safeString(put, 'contract');
@@ -5635,7 +5729,16 @@ export default class gate extends Exchange {
5635
5729
  const authentication = api[0]; // public, private
5636
5730
  const type = api[1]; // spot, margin, future, delivery
5637
5731
  let query = this.omit(params, this.extractParams(path));
5638
- path = this.implodeParams(path, params);
5732
+ if (Array.isArray(params)) {
5733
+ // endpoints like createOrders use an array instead of an object
5734
+ // so we infer the settle from one of the elements
5735
+ // they have to be all the same so relying on the first one is fine
5736
+ const first = this.safeValue(params, 0, {});
5737
+ path = this.implodeParams(path, first);
5738
+ }
5739
+ else {
5740
+ path = this.implodeParams(path, params);
5741
+ }
5639
5742
  const endPart = (path === '') ? '' : ('/' + path);
5640
5743
  let entirePath = '/' + type + endPart;
5641
5744
  if ((type === 'subAccounts') || (type === 'withdrawals')) {
@@ -1,5 +1,5 @@
1
1
  import Exchange from './abstract/krakenfutures.js';
2
- import { Int, OrderSide, OrderType, OHLCV, Trade, FundingRateHistory } from './base/types.js';
2
+ import { Int, OrderSide, OrderType, OHLCV, Trade, FundingRateHistory, OrderRequest } from './base/types.js';
3
3
  /**
4
4
  * @class krakenfutures
5
5
  * @extends Exchange
@@ -14,7 +14,9 @@ export default class krakenfutures extends Exchange {
14
14
  parseOHLCV(ohlcv: any, market?: any): number[];
15
15
  fetchTrades(symbol: string, since?: Int, limit?: Int, params?: {}): Promise<Trade[]>;
16
16
  parseTrade(trade: any, market?: any): Trade;
17
+ createOrderRequest(symbol: string, type: OrderType, side: OrderSide, amount: any, price?: any, params?: {}): any;
17
18
  createOrder(symbol: string, type: OrderType, side: OrderSide, amount: any, price?: any, params?: {}): Promise<import("./base/types.js").Order>;
19
+ createOrders(orders: OrderRequest[], params?: {}): Promise<import("./base/types.js").Order[]>;
18
20
  editOrder(id: string, symbol: any, type: any, side: any, amount?: any, price?: any, params?: {}): Promise<import("./base/types.js").Order>;
19
21
  cancelOrder(id: string, symbol?: string, params?: {}): Promise<any>;
20
22
  cancelOrders(ids: string[], symbol?: string, params?: {}): Promise<import("./base/types.js").Order[]>;
@@ -827,24 +827,7 @@ export default class krakenfutures extends Exchange {
827
827
  'fee': undefined,
828
828
  });
829
829
  }
830
- async createOrder(symbol, type, side, amount, price = undefined, params = {}) {
831
- /**
832
- * @method
833
- * @name krakenfutures#createOrder
834
- * @description Create an order on the exchange
835
- * @param {string} symbol market symbol
836
- * @param {string} type One of 'limit', 'market', 'take_profit'
837
- * @param {string} side buy or sell
838
- * @param {int} amount Contract quantity
839
- * @param {float} [price] Limit order price
840
- * @param {float} [params.stopPrice] The stop price associated with a stop or take profit order, Required if orderType is stp or take_profit, Must not have more than 2 decimal places, Note that for stop orders, limitPrice denotes the worst price at which the stop or take_profit order can get filled at. If no limitPrice is provided the stop or take_profit order will trigger a market order,
841
- * @param {bool} [params.reduceOnly] Set as true if you wish the order to only reduce an existing position, Any order which increases an existing position will be rejected, Default false,
842
- * @param {bool} [params.postOnly] Set as true if you wish to make a postOnly order, Default false
843
- * @param {string} [params.triggerSignal] If placing a stp or take_profit, the signal used for trigger, One of: 'mark', 'index', 'last', last is market price
844
- * @param {string} [params.cliOrdId] UUID The order identity that is specified from the user, It must be globally unique
845
- * @param {string} [params.clientOrderId] UUID The order identity that is specified from the user, It must be globally unique
846
- */
847
- await this.loadMarkets();
830
+ createOrderRequest(symbol, type, side, amount, price = undefined, params = {}) {
848
831
  type = this.safeString(params, 'orderType', type);
849
832
  const timeInForce = this.safeString(params, 'timeInForce');
850
833
  const stopPrice = this.safeString(params, 'stopPrice');
@@ -882,7 +865,28 @@ export default class krakenfutures extends Exchange {
882
865
  if (clientOrderId !== undefined) {
883
866
  request['cliOrdId'] = clientOrderId;
884
867
  }
885
- const response = await this.privatePostSendorder(this.extend(request, params));
868
+ return this.extend(request, params);
869
+ }
870
+ async createOrder(symbol, type, side, amount, price = undefined, params = {}) {
871
+ /**
872
+ * @method
873
+ * @name krakenfutures#createOrder
874
+ * @description Create an order on the exchange
875
+ * @param {string} symbol market symbol
876
+ * @param {string} type One of 'limit', 'market', 'take_profit'
877
+ * @param {string} side buy or sell
878
+ * @param {int} amount Contract quantity
879
+ * @param {float} [price] Limit order price
880
+ * @param {float} [params.stopPrice] The stop price associated with a stop or take profit order, Required if orderType is stp or take_profit, Must not have more than 2 decimal places, Note that for stop orders, limitPrice denotes the worst price at which the stop or take_profit order can get filled at. If no limitPrice is provided the stop or take_profit order will trigger a market order,
881
+ * @param {bool} [params.reduceOnly] Set as true if you wish the order to only reduce an existing position, Any order which increases an existing position will be rejected, Default false,
882
+ * @param {bool} [params.postOnly] Set as true if you wish to make a postOnly order, Default false
883
+ * @param {string} [params.triggerSignal] If placing a stp or take_profit, the signal used for trigger, One of: 'mark', 'index', 'last', last is market price
884
+ * @param {string} [params.cliOrdId] UUID The order identity that is specified from the user, It must be globally unique
885
+ * @param {string} [params.clientOrderId] UUID The order identity that is specified from the user, It must be globally unique
886
+ */
887
+ await this.loadMarkets();
888
+ const orderRequest = this.createOrderRequest(symbol, type, side, amount, price, params);
889
+ const response = await this.privatePostSendorder(orderRequest);
886
890
  //
887
891
  // {
888
892
  // "result": "success",
@@ -918,6 +922,57 @@ export default class krakenfutures extends Exchange {
918
922
  this.verifyOrderActionSuccess(status, 'createOrder', ['filled']);
919
923
  return this.parseOrder(sendStatus);
920
924
  }
925
+ async createOrders(orders, params = {}) {
926
+ /**
927
+ * @method
928
+ * @name krakenfutures#createOrders
929
+ * @description create a list of trade orders
930
+ * @see https://docs.futures.kraken.com/#http-api-trading-v3-api-order-management-batch-order-management
931
+ * @param {array} orders list of orders to create, each object should contain the parameters required by createOrder, namely symbol, type, side, amount, price and params
932
+ * @returns {object} an [order structure]{@link https://github.com/ccxt/ccxt/wiki/Manual#order-structure}
933
+ */
934
+ await this.loadMarkets();
935
+ const ordersRequests = [];
936
+ for (let i = 0; i < orders.length; i++) {
937
+ const rawOrder = orders[i];
938
+ const marketId = this.safeString(rawOrder, 'symbol');
939
+ const type = this.safeString(rawOrder, 'type');
940
+ const side = this.safeString(rawOrder, 'side');
941
+ const amount = this.safeValue(rawOrder, 'amount');
942
+ const price = this.safeValue(rawOrder, 'price');
943
+ const orderParams = this.safeValue(rawOrder, 'params', {});
944
+ const extendedParams = this.extend(orderParams, params); // the request does not accept extra params since it's a list, so we're extending each order with the common params
945
+ if (!('order_tag' in extendedParams)) {
946
+ // order tag is mandatory so we will generate one if not provided
947
+ extendedParams['order_tag'] = this.sum(i, 1).toString(); // sequential counter
948
+ }
949
+ extendedParams['order'] = 'send';
950
+ const orderRequest = this.createOrderRequest(marketId, type, side, amount, price, extendedParams);
951
+ ordersRequests.push(orderRequest);
952
+ }
953
+ const request = {
954
+ 'batchOrder': ordersRequests,
955
+ };
956
+ const response = await this.privatePostBatchorder(this.extend(request, params));
957
+ //
958
+ // {
959
+ // "result": "success",
960
+ // "serverTime": "2023-10-24T08:40:57.339Z",
961
+ // "batchStatus": [
962
+ // {
963
+ // "status": "requiredArgumentMissing",
964
+ // "orderEvents": []
965
+ // },
966
+ // {
967
+ // "status": "requiredArgumentMissing",
968
+ // "orderEvents": []
969
+ // }
970
+ // ]
971
+ // }
972
+ //
973
+ const data = this.safeValue(response, 'batchStatus', []);
974
+ return this.parseOrders(data);
975
+ }
921
976
  async editOrder(id, symbol, type, side, amount = undefined, price = undefined, params = {}) {
922
977
  /**
923
978
  * @method
@@ -1304,14 +1359,25 @@ export default class krakenfutures extends Exchange {
1304
1359
  // "lastUpdateTime": "2019-09-05T17:01:17.410Z"
1305
1360
  // }
1306
1361
  //
1362
+ // createOrders error
1363
+ // {
1364
+ // "status": "requiredArgumentMissing",
1365
+ // "orderEvents": []
1366
+ // }
1367
+ //
1307
1368
  const orderEvents = this.safeValue(order, 'orderEvents', []);
1369
+ const errorStatus = this.safeString(order, 'status');
1370
+ const orderEventsLength = orderEvents.length;
1371
+ if (('orderEvents' in order) && (errorStatus !== undefined) && (orderEventsLength === 0)) {
1372
+ // creteOrders error response
1373
+ return this.safeOrder({ 'info': order, 'status': 'rejected' });
1374
+ }
1308
1375
  let details = undefined;
1309
1376
  let isPrior = false;
1310
1377
  let fixed = false;
1311
1378
  let statusId = undefined;
1312
1379
  let price = undefined;
1313
1380
  let trades = [];
1314
- const orderEventsLength = orderEvents.length;
1315
1381
  if (orderEventsLength) {
1316
1382
  const executions = [];
1317
1383
  for (let i = 0; i < orderEvents.length; i++) {
@@ -28,7 +28,6 @@ export default class oceanex extends Exchange {
28
28
  fetchOHLCV(symbol: string, timeframe?: string, since?: Int, limit?: Int, params?: {}): Promise<import("./base/types.js").OHLCV[]>;
29
29
  parseOrder(order: any, market?: any): Order;
30
30
  parseOrderStatus(status: any): string;
31
- createOrders(symbol: string, orders: any, params?: {}): Promise<Order[]>;
32
31
  cancelOrder(id: string, symbol?: string, params?: {}): Promise<Order>;
33
32
  cancelOrders(ids: any, symbol?: string, params?: {}): Promise<Order[]>;
34
33
  cancelAllOrders(symbol?: string, params?: {}): Promise<Order[]>;
package/js/src/oceanex.js CHANGED
@@ -864,18 +864,6 @@ export default class oceanex extends Exchange {
864
864
  };
865
865
  return this.safeString(statuses, status, status);
866
866
  }
867
- async createOrders(symbol, orders, params = {}) {
868
- await this.loadMarkets();
869
- const market = this.market(symbol);
870
- const request = {
871
- 'market': market['id'],
872
- 'orders': orders,
873
- };
874
- // orders: [{"side":"buy", "volume":.2, "price":1001}, {"side":"sell", "volume":0.2, "price":1002}]
875
- const response = await this.privatePostOrdersMulti(this.extend(request, params));
876
- const data = response['data'];
877
- return this.parseOrders(data);
878
- }
879
867
  async cancelOrder(id, symbol = undefined, params = {}) {
880
868
  /**
881
869
  * @method
package/js/src/okx.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import Exchange from './abstract/okx.js';
2
- import { Int, OrderSide, OrderType, Trade, OHLCV, Order, FundingRateHistory } from './base/types.js';
2
+ import { Int, OrderSide, OrderType, Trade, OHLCV, Order, FundingRateHistory, OrderRequest } from './base/types.js';
3
3
  /**
4
4
  * @class okx
5
5
  * @extends Exchange
@@ -98,6 +98,7 @@ export default class okx extends Exchange {
98
98
  fetchBalance(params?: {}): Promise<import("./base/types.js").Balances>;
99
99
  createOrderRequest(symbol: string, type: OrderType, side: OrderSide, amount: any, price?: any, params?: {}): any;
100
100
  createOrder(symbol: string, type: OrderType, side: OrderSide, amount: any, price?: any, params?: {}): Promise<Order>;
101
+ createOrders(orders: OrderRequest[], params?: {}): Promise<Order[]>;
101
102
  editOrderRequest(id: string, symbol: any, type: any, side: any, amount?: any, price?: any, params?: {}): any;
102
103
  editOrder(id: string, symbol: any, type: any, side: any, amount?: any, price?: any, params?: {}): Promise<Order>;
103
104
  cancelOrder(id: string, symbol?: string, params?: {}): Promise<any>;
package/js/src/okx.js CHANGED
@@ -39,6 +39,7 @@ export default class okx extends Exchange {
39
39
  'cancelOrders': true,
40
40
  'createDepositAddress': false,
41
41
  'createOrder': true,
42
+ 'createOrders': true,
42
43
  'createPostOnlyOrder': true,
43
44
  'createReduceOnlyOrder': true,
44
45
  'createStopLimitOrder': true,
@@ -2772,6 +2773,55 @@ export default class okx extends Exchange {
2772
2773
  order['side'] = side;
2773
2774
  return order;
2774
2775
  }
2776
+ async createOrders(orders, params = {}) {
2777
+ /**
2778
+ * @method
2779
+ * @name okx#createOrders
2780
+ * @description create a list of trade orders
2781
+ * @see https://www.okx.com/docs-v5/en/#order-book-trading-trade-post-place-multiple-orders
2782
+ * @param {array} orders list of orders to create, each object should contain the parameters required by createOrder, namely symbol, type, side, amount, price and params
2783
+ * @returns {object} an [order structure]{@link https://github.com/ccxt/ccxt/wiki/Manual#order-structure}
2784
+ */
2785
+ await this.loadMarkets();
2786
+ const ordersRequests = [];
2787
+ for (let i = 0; i < orders.length; i++) {
2788
+ const rawOrder = orders[i];
2789
+ const marketId = this.safeString(rawOrder, 'symbol');
2790
+ const type = this.safeString(rawOrder, 'type');
2791
+ const side = this.safeString(rawOrder, 'side');
2792
+ const amount = this.safeValue(rawOrder, 'amount');
2793
+ const price = this.safeValue(rawOrder, 'price');
2794
+ const orderParams = this.safeValue(rawOrder, 'params', {});
2795
+ const extendedParams = this.extend(orderParams, params); // the request does not accept extra params since it's a list, so we're extending each order with the common params
2796
+ const orderRequest = this.createOrderRequest(marketId, type, side, amount, price, extendedParams);
2797
+ ordersRequests.push(orderRequest);
2798
+ }
2799
+ const response = await this.privatePostTradeBatchOrders(ordersRequests);
2800
+ // {
2801
+ // "code": "0",
2802
+ // "data": [
2803
+ // {
2804
+ // "clOrdId": "e847386590ce4dBCc7f2a1b4c4509f82",
2805
+ // "ordId": "636305438765568000",
2806
+ // "sCode": "0",
2807
+ // "sMsg": "Order placed",
2808
+ // "tag": "e847386590ce4dBC"
2809
+ // },
2810
+ // {
2811
+ // "clOrdId": "e847386590ce4dBC0b9993fe642d8f62",
2812
+ // "ordId": "636305438765568001",
2813
+ // "sCode": "0",
2814
+ // "sMsg": "Order placed",
2815
+ // "tag": "e847386590ce4dBC"
2816
+ // }
2817
+ // ],
2818
+ // "inTime": "1697979038584486",
2819
+ // "msg": "",
2820
+ // "outTime": "1697979038586493"
2821
+ // }
2822
+ const data = this.safeValue(response, 'data', []);
2823
+ return this.parseOrders(data);
2824
+ }
2775
2825
  editOrderRequest(id, symbol, type, side, amount = undefined, price = undefined, params = {}) {
2776
2826
  const market = this.market(symbol);
2777
2827
  const request = {
@@ -3150,6 +3200,15 @@ export default class okx extends Exchange {
3150
3200
  // "uly": "BTC-USDT"
3151
3201
  // }
3152
3202
  //
3203
+ const scode = this.safeString(order, 'sCode');
3204
+ if ((scode !== undefined) && (scode !== '0')) {
3205
+ return this.safeOrder({
3206
+ 'id': this.safeString(order, 'ordId'),
3207
+ 'clientOrderId': this.safeString(order, 'clOrdId'),
3208
+ 'status': 'rejected',
3209
+ 'info': order,
3210
+ });
3211
+ }
3153
3212
  const id = this.safeString2(order, 'algoId', 'ordId');
3154
3213
  const timestamp = this.safeInteger(order, 'cTime');
3155
3214
  const lastUpdateTimestamp = this.safeInteger(order, 'uTime');
@@ -6892,7 +6951,7 @@ export default class okx extends Exchange {
6892
6951
  // }
6893
6952
  //
6894
6953
  const code = this.safeString(response, 'code');
6895
- if (code !== '0') {
6954
+ if ((code !== '0') && (code !== '2')) { // 2 means that bulk operation partially succeeded
6896
6955
  const feedback = this.id + ' ' + body;
6897
6956
  const data = this.safeValue(response, 'data', []);
6898
6957
  for (let i = 0; i < data.length; i++) {