ccxt 4.2.7 → 4.2.9

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/cjs/ccxt.js CHANGED
@@ -169,7 +169,7 @@ var woo$1 = require('./src/pro/woo.js');
169
169
 
170
170
  //-----------------------------------------------------------------------------
171
171
  // this is updated by vss.js when building
172
- const version = '4.2.7';
172
+ const version = '4.2.9';
173
173
  Exchange["default"].ccxtVersion = version;
174
174
  const exchanges = {
175
175
  'ace': ace,
@@ -4414,6 +4414,8 @@ class binance extends binance$1 {
4414
4414
  * @param {string} [params.marginMode] 'cross' or 'isolated', for spot margin trading
4415
4415
  * @param {boolean} [params.sor] *spot only* whether to use SOR (Smart Order Routing) or not, default is false
4416
4416
  * @param {boolean} [params.test] *spot only* whether to use the test endpoint or not, default is false
4417
+ * @param {float} [params.trailingPercent] the percent to trail away from the current market price
4418
+ * @param {float} [params.trailingTriggerPrice] the price to trigger a trailing order, default uses the price argument
4417
4419
  * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
4418
4420
  */
4419
4421
  await this.loadMarkets();
@@ -4462,6 +4464,8 @@ class binance extends binance$1 {
4462
4464
  * @param {float|undefined} price the price at which the order is to be fullfilled, in units of the quote currency, ignored in market orders
4463
4465
  * @param {object} params extra parameters specific to the exchange API endpoint
4464
4466
  * @param {string|undefined} params.marginMode 'cross' or 'isolated', for spot margin trading
4467
+ * @param {float} [params.trailingPercent] the percent to trail away from the current market price
4468
+ * @param {float} [params.trailingTriggerPrice] the price to trigger a trailing order, default uses the price argument
4465
4469
  * @returns {object} request to be sent to the exchange
4466
4470
  */
4467
4471
  const market = this.market(symbol);
@@ -4475,9 +4479,12 @@ class binance extends binance$1 {
4475
4479
  const stopLossPrice = this.safeValue(params, 'stopLossPrice', triggerPrice); // fallback to stopLoss
4476
4480
  const takeProfitPrice = this.safeValue(params, 'takeProfitPrice');
4477
4481
  const trailingDelta = this.safeValue(params, 'trailingDelta');
4482
+ const trailingTriggerPrice = this.safeString2(params, 'trailingTriggerPrice', 'activationPrice', price);
4483
+ const trailingPercent = this.safeString2(params, 'trailingPercent', 'callbackRate');
4484
+ const isTrailingPercentOrder = trailingPercent !== undefined;
4478
4485
  const isStopLoss = stopLossPrice !== undefined || trailingDelta !== undefined;
4479
4486
  const isTakeProfit = takeProfitPrice !== undefined;
4480
- params = this.omit(params, ['type', 'newClientOrderId', 'clientOrderId', 'postOnly', 'stopLossPrice', 'takeProfitPrice', 'stopPrice', 'triggerPrice']);
4487
+ params = this.omit(params, ['type', 'newClientOrderId', 'clientOrderId', 'postOnly', 'stopLossPrice', 'takeProfitPrice', 'stopPrice', 'triggerPrice', 'trailingTriggerPrice', 'trailingPercent']);
4481
4488
  const [marginMode, query] = this.handleMarginModeAndParams('createOrder', params);
4482
4489
  const request = {
4483
4490
  'symbol': market['id'],
@@ -4498,7 +4505,14 @@ class binance extends binance$1 {
4498
4505
  }
4499
4506
  let uppercaseType = type.toUpperCase();
4500
4507
  let stopPrice = undefined;
4501
- if (isStopLoss) {
4508
+ if (isTrailingPercentOrder) {
4509
+ uppercaseType = 'TRAILING_STOP_MARKET';
4510
+ request['callbackRate'] = trailingPercent;
4511
+ if (trailingTriggerPrice !== undefined) {
4512
+ request['activationPrice'] = this.priceToPrecision(symbol, trailingTriggerPrice);
4513
+ }
4514
+ }
4515
+ else if (isStopLoss) {
4502
4516
  stopPrice = stopLossPrice;
4503
4517
  if (isMarketOrder) {
4504
4518
  // spot STOP_LOSS market orders are not a valid order type
@@ -4642,9 +4656,8 @@ class binance extends binance$1 {
4642
4656
  }
4643
4657
  else if (uppercaseType === 'TRAILING_STOP_MARKET') {
4644
4658
  quantityIsRequired = true;
4645
- const callbackRate = this.safeNumber(query, 'callbackRate');
4646
- if (callbackRate === undefined) {
4647
- throw new errors.InvalidOrder(this.id + ' createOrder() requires a callbackRate extra param for a ' + type + ' order');
4659
+ if (trailingPercent === undefined) {
4660
+ throw new errors.InvalidOrder(this.id + ' createOrder() requires a trailingPercent param for a ' + type + ' order');
4648
4661
  }
4649
4662
  }
4650
4663
  if (quantityIsRequired) {
@@ -352,6 +352,7 @@ class bingx extends bingx$1 {
352
352
  '80014': errors.BadRequest,
353
353
  '80016': errors.OrderNotFound,
354
354
  '80017': errors.OrderNotFound,
355
+ '100414': errors.AccountSuspended,
355
356
  '100437': errors.BadRequest, // {"code":100437,"msg":"The withdrawal amount is lower than the minimum limit, please re-enter.","timestamp":1689258588845}
356
357
  },
357
358
  'broad': {},
@@ -1895,12 +1896,26 @@ class bingx extends bingx$1 {
1895
1896
  // }
1896
1897
  //
1897
1898
  if (typeof response === 'string') {
1899
+ // broken api engine : order-ids are too long numbers (i.e. 1742930526912864656)
1900
+ // and JSON.parse can not handle them in JS, so we have to use .parseJson
1901
+ // however, when order has an attached SL/TP, their value types need extra parsing
1902
+ response = this.fixStringifiedJsonMembers(response);
1898
1903
  response = this.parseJson(response);
1899
1904
  }
1900
1905
  const data = this.safeValue(response, 'data', {});
1901
1906
  const order = this.safeValue(data, 'order', data);
1902
1907
  return this.parseOrder(order, market);
1903
1908
  }
1909
+ fixStringifiedJsonMembers(content) {
1910
+ // when stringified json has members with their values also stringified, like:
1911
+ // '{"code":0, "data":{"order":{"orderId":1742968678528512345,"symbol":"BTC-USDT", "takeProfit":"{\"type\":\"TAKE_PROFIT\",\"stopPrice\":43320.1}","reduceOnly":false}}}'
1912
+ // we can fix with below manipulations
1913
+ // @ts-ignore
1914
+ let modifiedContent = content.replaceAll('\\', '');
1915
+ modifiedContent = modifiedContent.replaceAll('"{', '{');
1916
+ modifiedContent = modifiedContent.replaceAll('}"', '}');
1917
+ return modifiedContent;
1918
+ }
1904
1919
  async createOrders(orders, params = {}) {
1905
1920
  /**
1906
1921
  * @method
@@ -306,7 +306,11 @@ class bitmart extends bitmart$1 {
306
306
  '30012': errors.AuthenticationError,
307
307
  '30013': errors.RateLimitExceeded,
308
308
  '30014': errors.ExchangeNotAvailable,
309
- // funding account errors
309
+ '30016': errors.OnMaintenance,
310
+ '30017': errors.RateLimitExceeded,
311
+ '30018': errors.BadRequest,
312
+ '30019': errors.PermissionDenied,
313
+ // funding account & sub account errors
310
314
  '60000': errors.BadRequest,
311
315
  '60001': errors.BadRequest,
312
316
  '60002': errors.BadRequest,
@@ -323,13 +327,31 @@ class bitmart extends bitmart$1 {
323
327
  '60020': errors.PermissionDenied,
324
328
  '60021': errors.PermissionDenied,
325
329
  '60022': errors.PermissionDenied,
330
+ '60026': errors.PermissionDenied,
331
+ '60027': errors.PermissionDenied,
332
+ '60028': errors.AccountSuspended,
333
+ '60029': errors.AccountSuspended,
326
334
  '60030': errors.BadRequest,
327
335
  '60031': errors.BadRequest,
328
336
  '60050': errors.ExchangeError,
329
337
  '60051': errors.ExchangeError,
330
338
  '61001': errors.InsufficientFunds,
331
339
  '61003': errors.BadRequest,
332
- // spot errors
340
+ '61004': errors.BadRequest,
341
+ '61005': errors.BadRequest,
342
+ '61006': errors.NotSupported,
343
+ '61007': errors.ExchangeError,
344
+ '61008': errors.ExchangeError,
345
+ // spot public errors
346
+ '70000': errors.ExchangeError,
347
+ '70001': errors.BadRequest,
348
+ '70002': errors.BadSymbol,
349
+ '71001': errors.BadRequest,
350
+ '71002': errors.BadRequest,
351
+ '71003': errors.BadRequest,
352
+ '71004': errors.BadRequest,
353
+ '71005': errors.BadRequest,
354
+ // spot & margin errors
333
355
  '50000': errors.BadRequest,
334
356
  '50001': errors.BadSymbol,
335
357
  '50002': errors.BadRequest,
@@ -349,26 +371,75 @@ class bitmart extends bitmart$1 {
349
371
  '50016': errors.BadRequest,
350
372
  '50017': errors.BadRequest,
351
373
  '50018': errors.BadRequest,
352
- '50019': errors.BadRequest,
353
- '51004': errors.InsufficientFunds,
354
- // '50019': ExchangeError, // 400, Invalid status. validate status is [1=Failed, 2=Success, 3=Frozen Failed, 4=Frozen Success, 5=Partially Filled, 6=Fully Fulled, 7=Canceling, 8=Canceled
374
+ '50019': errors.ExchangeError,
355
375
  '50020': errors.InsufficientFunds,
356
376
  '50021': errors.BadRequest,
357
377
  '50022': errors.ExchangeNotAvailable,
358
378
  '50023': errors.BadSymbol,
379
+ '50024': errors.BadRequest,
380
+ '50025': errors.BadRequest,
381
+ '50026': errors.BadRequest,
382
+ '50027': errors.BadRequest,
383
+ '50028': errors.BadRequest,
359
384
  '50029': errors.InvalidOrder,
360
- '50030': errors.InvalidOrder,
385
+ '50030': errors.OrderNotFound,
386
+ '50031': errors.OrderNotFound,
361
387
  '50032': errors.OrderNotFound,
388
+ '50033': errors.InvalidOrder,
362
389
  // below Error codes used interchangeably for both failed postOnly and IOC orders depending on market price and order side
363
- '50035': errors.InvalidOrder,
364
390
  '50034': errors.InvalidOrder,
391
+ '50035': errors.InvalidOrder,
392
+ '50036': errors.ExchangeError,
393
+ '50037': errors.BadRequest,
394
+ '50038': errors.BadRequest,
395
+ '50039': errors.BadRequest,
396
+ '50040': errors.BadSymbol,
397
+ '50041': errors.ExchangeError,
398
+ '50042': errors.BadRequest,
399
+ '51000': errors.BadSymbol,
400
+ '51001': errors.ExchangeError,
401
+ '51002': errors.ExchangeError,
402
+ '51003': errors.ExchangeError,
403
+ '51004': errors.InsufficientFunds,
404
+ '51005': errors.InvalidOrder,
405
+ '51006': errors.InvalidOrder,
406
+ '51007': errors.BadRequest,
407
+ '51008': errors.ExchangeError,
408
+ '51009': errors.InvalidOrder,
409
+ '51010': errors.InvalidOrder,
365
410
  '51011': errors.InvalidOrder,
411
+ '51012': errors.InvalidOrder,
412
+ '51013': errors.InvalidOrder,
413
+ '51014': errors.InvalidOrder,
414
+ '51015': errors.InvalidOrder,
415
+ '52000': errors.BadRequest,
416
+ '52001': errors.BadRequest,
417
+ '52002': errors.BadRequest,
418
+ '52003': errors.BadRequest,
419
+ '52004': errors.BadRequest,
366
420
  '53000': errors.AccountSuspended,
367
421
  '53001': errors.AccountSuspended,
422
+ '53002': errors.PermissionDenied,
423
+ '53003': errors.PermissionDenied,
424
+ '53005': errors.PermissionDenied,
425
+ '53006': errors.PermissionDenied,
426
+ '53007': errors.PermissionDenied,
427
+ '53008': errors.PermissionDenied,
428
+ '53009': errors.PermissionDenied,
429
+ '53010': errors.PermissionDenied,
368
430
  '57001': errors.BadRequest,
369
431
  '58001': errors.BadRequest,
370
432
  '59001': errors.ExchangeError,
371
433
  '59002': errors.ExchangeError,
434
+ '59003': errors.ExchangeError,
435
+ '59004': errors.ExchangeError,
436
+ '59005': errors.PermissionDenied,
437
+ '59006': errors.ExchangeError,
438
+ '59007': errors.ExchangeError,
439
+ '59008': errors.ExchangeError,
440
+ '59009': errors.ExchangeError,
441
+ '59010': errors.InsufficientFunds,
442
+ '59011': errors.ExchangeError,
372
443
  // contract errors
373
444
  '40001': errors.ExchangeError,
374
445
  '40002': errors.ExchangeError,
@@ -404,14 +475,22 @@ class bitmart extends bitmart$1 {
404
475
  '40032': errors.InvalidOrder,
405
476
  '40033': errors.InvalidOrder,
406
477
  '40034': errors.BadSymbol,
407
- '53002': errors.PermissionDenied,
408
- '53003': errors.PermissionDenied,
409
- '53005': errors.PermissionDenied,
410
- '53006': errors.PermissionDenied,
411
- '53007': errors.PermissionDenied,
412
- '53008': errors.PermissionDenied,
413
- '53009': errors.PermissionDenied,
414
- '53010': errors.PermissionDenied, // 403 This account is restricted from borrowing
478
+ '40035': errors.OrderNotFound,
479
+ '40036': errors.InvalidOrder,
480
+ '40037': errors.OrderNotFound,
481
+ '40038': errors.BadRequest,
482
+ '40039': errors.BadRequest,
483
+ '40040': errors.InvalidOrder,
484
+ '40041': errors.InvalidOrder,
485
+ '40042': errors.InvalidOrder,
486
+ '40043': errors.InvalidOrder,
487
+ '40044': errors.InvalidOrder,
488
+ '40045': errors.InvalidOrder,
489
+ '40046': errors.PermissionDenied,
490
+ '40047': errors.PermissionDenied,
491
+ '40048': errors.BadRequest,
492
+ '40049': errors.BadRequest,
493
+ '40050': errors.InvalidOrder, // 403, Client OrderId duplicated with existing orders
415
494
  },
416
495
  'broad': {},
417
496
  },
@@ -3499,6 +3499,7 @@ class bybit extends bybit$1 {
3499
3499
  * @name bybit#createOrder
3500
3500
  * @description create a trade order
3501
3501
  * @see https://bybit-exchange.github.io/docs/v5/order/create-order
3502
+ * @see https://bybit-exchange.github.io/docs/v5/position/trading-stop
3502
3503
  * @param {string} symbol unified symbol of the market to create an order in
3503
3504
  * @param {string} type 'market' or 'limit'
3504
3505
  * @param {string} side 'buy' or 'sell'
@@ -3520,6 +3521,8 @@ class bybit extends bybit$1 {
3520
3521
  * @param {float} [params.takeProfit.triggerPrice] take profit trigger price
3521
3522
  * @param {object} [params.stopLoss] *stopLoss object in params* containing the triggerPrice at which the attached stop loss order will be triggered
3522
3523
  * @param {float} [params.stopLoss.triggerPrice] stop loss trigger price
3524
+ * @param {string} [params.trailingAmount] the quote amount to trail away from the current market price
3525
+ * @param {string} [params.trailingTriggerPrice] the price to trigger a trailing order, default uses the price argument
3523
3526
  * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
3524
3527
  */
3525
3528
  await this.loadMarkets();
@@ -3530,8 +3533,16 @@ class bybit extends bybit$1 {
3530
3533
  if (isUsdcSettled && !isUnifiedAccount) {
3531
3534
  return await this.createUsdcOrder(symbol, type, side, amount, price, params);
3532
3535
  }
3536
+ const trailingAmount = this.safeString2(params, 'trailingAmount', 'trailingStop');
3537
+ const isTrailingAmountOrder = trailingAmount !== undefined;
3533
3538
  const orderRequest = this.createOrderRequest(symbol, type, side, amount, price, params);
3534
- const response = await this.privatePostV5OrderCreate(orderRequest); // already extended inside createOrderRequest
3539
+ let response = undefined;
3540
+ if (isTrailingAmountOrder) {
3541
+ response = await this.privatePostV5PositionTradingStop(orderRequest);
3542
+ }
3543
+ else {
3544
+ response = await this.privatePostV5OrderCreate(orderRequest); // already extended inside createOrderRequest
3545
+ }
3535
3546
  //
3536
3547
  // {
3537
3548
  // "retCode": 0,
@@ -3641,12 +3652,21 @@ class bybit extends bybit$1 {
3641
3652
  const takeProfitTriggerPrice = this.safeValue(params, 'takeProfitPrice');
3642
3653
  const stopLoss = this.safeValue(params, 'stopLoss');
3643
3654
  const takeProfit = this.safeValue(params, 'takeProfit');
3655
+ const trailingTriggerPrice = this.safeString2(params, 'trailingTriggerPrice', 'activePrice', price);
3656
+ const trailingAmount = this.safeString2(params, 'trailingAmount', 'trailingStop');
3657
+ const isTrailingAmountOrder = trailingAmount !== undefined;
3644
3658
  const isStopLossTriggerOrder = stopLossTriggerPrice !== undefined;
3645
3659
  const isTakeProfitTriggerOrder = takeProfitTriggerPrice !== undefined;
3646
3660
  const isStopLoss = stopLoss !== undefined;
3647
3661
  const isTakeProfit = takeProfit !== undefined;
3648
3662
  const isBuy = side === 'buy';
3649
- if (triggerPrice !== undefined) {
3663
+ if (isTrailingAmountOrder) {
3664
+ if (trailingTriggerPrice !== undefined) {
3665
+ request['activePrice'] = this.priceToPrecision(symbol, trailingTriggerPrice);
3666
+ }
3667
+ request['trailingStop'] = trailingAmount;
3668
+ }
3669
+ else if (triggerPrice !== undefined) {
3650
3670
  const triggerDirection = this.safeString(params, 'triggerDirection');
3651
3671
  params = this.omit(params, ['triggerPrice', 'stopPrice', 'triggerDirection']);
3652
3672
  if (market['spot']) {
@@ -3701,7 +3721,7 @@ class bybit extends bybit$1 {
3701
3721
  // mandatory field for options
3702
3722
  request['orderLinkId'] = this.uuid16();
3703
3723
  }
3704
- params = this.omit(params, ['stopPrice', 'timeInForce', 'stopLossPrice', 'takeProfitPrice', 'postOnly', 'clientOrderId', 'triggerPrice', 'stopLoss', 'takeProfit']);
3724
+ params = this.omit(params, ['stopPrice', 'timeInForce', 'stopLossPrice', 'takeProfitPrice', 'postOnly', 'clientOrderId', 'triggerPrice', 'stopLoss', 'takeProfit', 'trailingAmount', 'trailingTriggerPrice']);
3705
3725
  return this.extend(request, params);
3706
3726
  }
3707
3727
  async createOrders(orders, params = {}) {
@@ -2587,6 +2587,8 @@ class okx extends okx$1 {
2587
2587
  const stopLossDefined = (stopLoss !== undefined);
2588
2588
  const takeProfit = this.safeValue(params, 'takeProfit');
2589
2589
  const takeProfitDefined = (takeProfit !== undefined);
2590
+ const trailingPercent = this.safeString2(params, 'trailingPercent', 'callbackRatio');
2591
+ const isTrailingPercentOrder = trailingPercent !== undefined;
2590
2592
  const defaultMarginMode = this.safeString2(this.options, 'defaultMarginMode', 'marginMode', 'cross');
2591
2593
  let marginMode = this.safeString2(params, 'marginMode', 'tdMode'); // cross or isolated, tdMode not ommited so as to be extended into the request
2592
2594
  let margin = false;
@@ -2619,7 +2621,7 @@ class okx extends okx$1 {
2619
2621
  const isMarketOrder = type === 'market';
2620
2622
  let postOnly = false;
2621
2623
  [postOnly, params] = this.handlePostOnly(isMarketOrder, type === 'post_only', params);
2622
- params = this.omit(params, ['currency', 'ccy', 'marginMode', 'timeInForce', 'stopPrice', 'triggerPrice', 'clientOrderId', 'stopLossPrice', 'takeProfitPrice', 'slOrdPx', 'tpOrdPx', 'margin', 'stopLoss', 'takeProfit']);
2624
+ params = this.omit(params, ['currency', 'ccy', 'marginMode', 'timeInForce', 'stopPrice', 'triggerPrice', 'clientOrderId', 'stopLossPrice', 'takeProfitPrice', 'slOrdPx', 'tpOrdPx', 'margin', 'stopLoss', 'takeProfit', 'trailingPercent']);
2623
2625
  const ioc = (timeInForce === 'IOC') || (type === 'ioc');
2624
2626
  const fok = (timeInForce === 'FOK') || (type === 'fok');
2625
2627
  const trigger = (triggerPrice !== undefined) || (type === 'trigger');
@@ -2678,7 +2680,12 @@ class okx extends okx$1 {
2678
2680
  else if (fok) {
2679
2681
  request['ordType'] = 'fok';
2680
2682
  }
2681
- if (stopLossDefined || takeProfitDefined) {
2683
+ if (isTrailingPercentOrder) {
2684
+ const convertedTrailingPercent = Precise["default"].stringDiv(trailingPercent, '100');
2685
+ request['callbackRatio'] = convertedTrailingPercent;
2686
+ request['ordType'] = 'move_order_stop';
2687
+ }
2688
+ else if (stopLossDefined || takeProfitDefined) {
2682
2689
  if (stopLossDefined) {
2683
2690
  const stopLossTriggerPrice = this.safeValueN(stopLoss, ['triggerPrice', 'stopPrice', 'slTriggerPx']);
2684
2691
  if (stopLossTriggerPrice === undefined) {
@@ -2822,6 +2829,7 @@ class okx extends okx$1 {
2822
2829
  * @param {float} [params.stopLoss.price] used for stop loss limit orders, not used for stop loss market price orders
2823
2830
  * @param {string} [params.stopLoss.type] 'market' or 'limit' used to specify the stop loss price type
2824
2831
  * @param {string} [params.positionSide] if position mode is one-way: set to 'net', if position mode is hedge-mode: set to 'long' or 'short'
2832
+ * @param {string} [params.trailingPercent] the percent to trail away from the current market price
2825
2833
  * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
2826
2834
  */
2827
2835
  await this.loadMarkets();
@@ -2829,7 +2837,7 @@ class okx extends okx$1 {
2829
2837
  let request = this.createOrderRequest(symbol, type, side, amount, price, params);
2830
2838
  let method = this.safeString(this.options, 'createOrder', 'privatePostTradeBatchOrders');
2831
2839
  const requestOrdType = this.safeString(request, 'ordType');
2832
- if ((requestOrdType === 'trigger') || (requestOrdType === 'conditional') || (type === 'oco') || (type === 'move_order_stop') || (type === 'iceberg') || (type === 'twap')) {
2840
+ if ((requestOrdType === 'trigger') || (requestOrdType === 'conditional') || (requestOrdType === 'move_order_stop') || (type === 'move_order_stop') || (type === 'oco') || (type === 'iceberg') || (type === 'twap')) {
2833
2841
  method = 'privatePostTradeOrderAlgo';
2834
2842
  }
2835
2843
  if ((method !== 'privatePostTradeOrder') && (method !== 'privatePostTradeOrderAlgo') && (method !== 'privatePostTradeBatchOrders')) {
@@ -3026,17 +3034,20 @@ class okx extends okx$1 {
3026
3034
  * @name okx#cancelOrder
3027
3035
  * @description cancels an open order
3028
3036
  * @see https://www.okx.com/docs-v5/en/#order-book-trading-trade-post-cancel-order
3037
+ * @see https://www.okx.com/docs-v5/en/#order-book-trading-algo-trading-post-cancel-algo-order
3029
3038
  * @param {string} id order id
3030
3039
  * @param {string} symbol unified symbol of the market the order was made in
3031
3040
  * @param {object} [params] extra parameters specific to the exchange API endpoint
3032
3041
  * @param {boolean} [params.trigger] true if trigger orders
3042
+ * @param {boolean} [params.trailing] set to true if you want to cancel a trailing order
3033
3043
  * @returns {object} An [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
3034
3044
  */
3035
3045
  if (symbol === undefined) {
3036
3046
  throw new errors.ArgumentsRequired(this.id + ' cancelOrder() requires a symbol argument');
3037
3047
  }
3038
3048
  const stop = this.safeValue2(params, 'stop', 'trigger');
3039
- if (stop) {
3049
+ const trailing = this.safeValue(params, 'trailing', false);
3050
+ if (stop || trailing) {
3040
3051
  const orderInner = await this.cancelOrders([id], symbol, params);
3041
3052
  return this.safeValue(orderInner, 0);
3042
3053
  }
@@ -3087,6 +3098,7 @@ class okx extends okx$1 {
3087
3098
  * @param {string} symbol unified market symbol
3088
3099
  * @param {object} [params] extra parameters specific to the exchange API endpoint
3089
3100
  * @param {boolean} [params.trigger] whether the order is a stop/trigger order
3101
+ * @param {boolean} [params.trailing] set to true if you want to cancel trailing orders
3090
3102
  * @returns {object} an list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
3091
3103
  */
3092
3104
  // TODO : the original endpoint signature differs, according to that you can skip individual symbol and assign ids in batch. At this moment, `params` is not being used too.
@@ -3102,7 +3114,8 @@ class okx extends okx$1 {
3102
3114
  const clientOrderIds = this.parseIds(this.safeValue2(params, 'clOrdId', 'clientOrderId'));
3103
3115
  const algoIds = this.parseIds(this.safeValue(params, 'algoId'));
3104
3116
  const stop = this.safeValue2(params, 'stop', 'trigger');
3105
- if (stop) {
3117
+ const trailing = this.safeValue(params, 'trailing', false);
3118
+ if (stop || trailing) {
3106
3119
  method = 'privatePostTradeCancelAlgos';
3107
3120
  }
3108
3121
  if (clientOrderIds === undefined) {
@@ -3116,7 +3129,7 @@ class okx extends okx$1 {
3116
3129
  }
3117
3130
  }
3118
3131
  for (let i = 0; i < ids.length; i++) {
3119
- if (stop) {
3132
+ if (trailing || stop) {
3120
3133
  request.push({
3121
3134
  'algoId': ids[i],
3122
3135
  'instId': market['id'],
@@ -3555,7 +3568,6 @@ class okx extends okx$1 {
3555
3568
  /**
3556
3569
  * @method
3557
3570
  * @name okx#fetchOpenOrders
3558
- * @description Fetch orders that are still open
3559
3571
  * @description fetch all unfilled currently open orders
3560
3572
  * @see https://www.okx.com/docs-v5/en/#order-book-trading-trade-get-order-list
3561
3573
  * @see https://www.okx.com/docs-v5/en/#order-book-trading-algo-trading-get-algo-order-list
@@ -3568,6 +3580,7 @@ class okx extends okx$1 {
3568
3580
  * @param {string} [params.ordType] "conditional", "oco", "trigger", "move_order_stop", "iceberg", or "twap"
3569
3581
  * @param {string} [params.algoId] Algo ID "'433845797218942976'"
3570
3582
  * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
3583
+ * @param {boolean} [params.trailing] set to true if you want to fetch trailing orders
3571
3584
  * @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
3572
3585
  */
3573
3586
  await this.loadMarkets();
@@ -3600,15 +3613,21 @@ class okx extends okx$1 {
3600
3613
  let method = this.safeString(params, 'method', defaultMethod);
3601
3614
  const ordType = this.safeString(params, 'ordType');
3602
3615
  const stop = this.safeValue2(params, 'stop', 'trigger');
3603
- if (stop || (ordType in algoOrderTypes)) {
3616
+ const trailing = this.safeValue(params, 'trailing', false);
3617
+ if (trailing || stop || (ordType in algoOrderTypes)) {
3604
3618
  method = 'privateGetTradeOrdersAlgoPending';
3619
+ }
3620
+ if (trailing) {
3621
+ request['ordType'] = 'move_order_stop';
3622
+ }
3623
+ else if (stop || (ordType in algoOrderTypes)) {
3605
3624
  if (stop) {
3606
3625
  if (ordType === undefined) {
3607
3626
  throw new errors.ArgumentsRequired(this.id + ' fetchOpenOrders() requires an "ordType" string parameter, "conditional", "oco", "trigger", "move_order_stop", "iceberg", or "twap"');
3608
3627
  }
3609
3628
  }
3610
3629
  }
3611
- const query = this.omit(params, ['method', 'stop', 'trigger']);
3630
+ const query = this.omit(params, ['method', 'stop', 'trigger', 'trailing']);
3612
3631
  let response = undefined;
3613
3632
  if (method === 'privateGetTradeOrdersAlgoPending') {
3614
3633
  response = await this.privateGetTradeOrdersAlgoPending(this.extend(request, query));
@@ -3729,6 +3748,7 @@ class okx extends okx$1 {
3729
3748
  * @param {string} [params.ordType] "conditional", "oco", "trigger", "move_order_stop", "iceberg", or "twap"
3730
3749
  * @param {string} [params.algoId] Algo ID "'433845797218942976'"
3731
3750
  * @param {int} [params.until] timestamp in ms to fetch orders for
3751
+ * @param {boolean} [params.trailing] set to true if you want to fetch trailing orders
3732
3752
  * @returns {object} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
3733
3753
  */
3734
3754
  await this.loadMarkets();
@@ -3762,7 +3782,12 @@ class okx extends okx$1 {
3762
3782
  let method = this.safeString(params, 'method', defaultMethod);
3763
3783
  const ordType = this.safeString(params, 'ordType');
3764
3784
  const stop = this.safeValue2(params, 'stop', 'trigger');
3765
- if (stop || (ordType in algoOrderTypes)) {
3785
+ const trailing = this.safeValue(params, 'trailing', false);
3786
+ if (trailing) {
3787
+ method = 'privateGetTradeOrdersAlgoHistory';
3788
+ request['ordType'] = 'move_order_stop';
3789
+ }
3790
+ else if (stop || (ordType in algoOrderTypes)) {
3766
3791
  method = 'privateGetTradeOrdersAlgoHistory';
3767
3792
  const algoId = this.safeString(params, 'algoId');
3768
3793
  if (algoId !== undefined) {
@@ -3773,7 +3798,6 @@ class okx extends okx$1 {
3773
3798
  if (ordType === undefined) {
3774
3799
  throw new errors.ArgumentsRequired(this.id + ' fetchCanceledOrders() requires an "ordType" string parameter, "conditional", "oco", "trigger", "move_order_stop", "iceberg", or "twap"');
3775
3800
  }
3776
- request['ordType'] = ordType;
3777
3801
  }
3778
3802
  }
3779
3803
  else {
@@ -3786,7 +3810,7 @@ class okx extends okx$1 {
3786
3810
  query = this.omit(query, ['until', 'till']);
3787
3811
  }
3788
3812
  }
3789
- const send = this.omit(query, ['method', 'stop', 'ordType', 'trigger']);
3813
+ const send = this.omit(query, ['method', 'stop', 'trigger', 'trailing']);
3790
3814
  let response = undefined;
3791
3815
  if (method === 'privateGetTradeOrdersAlgoHistory') {
3792
3816
  response = await this.privateGetTradeOrdersAlgoHistory(this.extend(request, send));
@@ -3914,6 +3938,7 @@ class okx extends okx$1 {
3914
3938
  * @param {int} [params.until] timestamp in ms to fetch orders for
3915
3939
  * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
3916
3940
  * @param {string} [params.method] method to be used, either 'privateGetTradeOrdersHistory', 'privateGetTradeOrdersHistoryArchive' or 'privateGetTradeOrdersAlgoHistory' default is 'privateGetTradeOrdersHistory'
3941
+ * @param {boolean} [params.trailing] set to true if you want to fetch trailing orders
3917
3942
  * @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
3918
3943
  */
3919
3944
  await this.loadMarkets();
@@ -3951,14 +3976,20 @@ class okx extends okx$1 {
3951
3976
  let method = this.safeString(params, 'method', defaultMethod);
3952
3977
  const ordType = this.safeString(params, 'ordType');
3953
3978
  const stop = this.safeValue2(params, 'stop', 'trigger');
3954
- if (stop || (ordType in algoOrderTypes)) {
3979
+ const trailing = this.safeValue(params, 'trailing', false);
3980
+ if (trailing || stop || (ordType in algoOrderTypes)) {
3955
3981
  method = 'privateGetTradeOrdersAlgoHistory';
3982
+ request['state'] = 'effective';
3983
+ }
3984
+ if (trailing) {
3985
+ request['ordType'] = 'move_order_stop';
3986
+ }
3987
+ else if (stop || (ordType in algoOrderTypes)) {
3956
3988
  if (stop) {
3957
3989
  if (ordType === undefined) {
3958
3990
  throw new errors.ArgumentsRequired(this.id + ' fetchClosedOrders() requires an "ordType" string parameter, "conditional", "oco", "trigger", "move_order_stop", "iceberg", or "twap"');
3959
3991
  }
3960
3992
  }
3961
- request['state'] = 'effective';
3962
3993
  }
3963
3994
  else {
3964
3995
  if (since !== undefined) {
@@ -3971,7 +4002,7 @@ class okx extends okx$1 {
3971
4002
  }
3972
4003
  request['state'] = 'filled';
3973
4004
  }
3974
- const send = this.omit(query, ['method', 'stop', 'trigger']);
4005
+ const send = this.omit(query, ['method', 'stop', 'trigger', 'trailing']);
3975
4006
  let response = undefined;
3976
4007
  if (method === 'privateGetTradeOrdersAlgoHistory') {
3977
4008
  response = await this.privateGetTradeOrdersAlgoHistory(this.extend(request, send));
@@ -864,7 +864,10 @@ class binance extends binance$1 {
864
864
  name = this.safeString(params, 'name', name);
865
865
  params = this.omit(params, 'name');
866
866
  let wsParams = [];
867
- const messageHash = 'tickers';
867
+ let messageHash = 'tickers';
868
+ if (symbols !== undefined) {
869
+ messageHash = 'tickers::' + symbols.join(',');
870
+ }
868
871
  if (name === 'bookTicker') {
869
872
  if (marketIds === undefined) {
870
873
  throw new errors.ArgumentsRequired(this.id + ' watchTickers() requires symbols for bookTicker');
@@ -1057,6 +1060,19 @@ class binance extends binance$1 {
1057
1060
  this.tickers[symbol] = result;
1058
1061
  newTickers.push(result);
1059
1062
  }
1063
+ const messageHashes = this.findMessageHashes(client, 'tickers::');
1064
+ for (let i = 0; i < messageHashes.length; i++) {
1065
+ const messageHash = messageHashes[i];
1066
+ const parts = messageHash.split('::');
1067
+ const symbolsString = parts[1];
1068
+ const symbols = symbolsString.split(',');
1069
+ const tickers = this.filterByArray(newTickers, 'symbol', symbols);
1070
+ const tickersSymbols = Object.keys(tickers);
1071
+ const numTickers = tickersSymbols.length;
1072
+ if (numTickers > 0) {
1073
+ client.resolve(tickers, messageHash);
1074
+ }
1075
+ }
1060
1076
  client.resolve(newTickers, 'tickers');
1061
1077
  }
1062
1078
  signParams(params = {}) {
@@ -153,7 +153,9 @@ class bitget extends bitget$1 {
153
153
  }
154
154
  const tickers = await this.watchPublicMultiple(messageHashes, topics, params);
155
155
  if (this.newUpdates) {
156
- return tickers;
156
+ const result = {};
157
+ result[tickers['symbol']] = tickers;
158
+ return result;
157
159
  }
158
160
  return this.filterByArray(this.tickers, 'symbol', symbols);
159
161
  }
@@ -298,7 +298,10 @@ class bitmart extends bitmart$1 {
298
298
  if (type === 'swap') {
299
299
  type = 'futures';
300
300
  }
301
- const messageHash = 'tickers';
301
+ let messageHash = 'tickers';
302
+ if (symbols !== undefined) {
303
+ messageHash += '::' + symbols.join(',');
304
+ }
302
305
  const request = {
303
306
  'action': 'subscribe',
304
307
  'args': ['futures/ticker'],
@@ -704,7 +707,7 @@ class bitmart extends bitmart$1 {
704
707
  // }
705
708
  //
706
709
  const marketId = this.safeString(position, 'symbol');
707
- market = this.safeMarket(marketId, market, '', 'swap');
710
+ market = this.safeMarket(marketId, market, undefined, 'swap');
708
711
  const symbol = market['symbol'];
709
712
  const openTimestamp = this.safeInteger(position, 'create_time');
710
713
  const timestamp = this.safeInteger(position, 'update_time');
@@ -897,6 +900,18 @@ class bitmart extends bitmart$1 {
897
900
  const symbol = this.safeString(ticker, 'symbol');
898
901
  this.tickers[symbol] = ticker;
899
902
  client.resolve(ticker, 'tickers');
903
+ const messageHashes = this.findMessageHashes(client, 'tickers::');
904
+ for (let i = 0; i < messageHashes.length; i++) {
905
+ const messageHash = messageHashes[i];
906
+ const parts = messageHash.split('::');
907
+ const symbolsString = parts[1];
908
+ const symbols = symbolsString.split(',');
909
+ if (this.inArray(symbol, symbols)) {
910
+ const response = {};
911
+ response[symbol] = ticker;
912
+ client.resolve(response, messageHash);
913
+ }
914
+ }
900
915
  }
901
916
  return message;
902
917
  }
@@ -1046,7 +1061,7 @@ class bitmart extends bitmart$1 {
1046
1061
  }
1047
1062
  else {
1048
1063
  const marketId = this.safeString(data, 'symbol');
1049
- const market = this.safeMarket(marketId, undefined, '', 'swap');
1064
+ const market = this.safeMarket(marketId, undefined, undefined, 'swap');
1050
1065
  const symbol = market['symbol'];
1051
1066
  const items = this.safeValue(data, 'items', []);
1052
1067
  this.ohlcvs[symbol] = this.safeValue(this.ohlcvs, symbol, {});