ccxt 4.2.7 → 4.2.8

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.8';
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
@@ -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));
@@ -121,8 +121,7 @@ class coinbasepro extends coinbasepro$1 {
121
121
  async watchTickers(symbols = undefined, params = {}) {
122
122
  /**
123
123
  * @method
124
- * @name okx#watchTickers
125
- * @see https://www.okx.com/docs-v5/en/#order-book-trading-market-data-ws-tickers-channel
124
+ * @name coinbasepro#watchTickers
126
125
  * @description watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for all markets of a specific list
127
126
  * @param {string[]} [symbols] unified symbol of the market to fetch the ticker for
128
127
  * @param {object} [params] extra parameters specific to the exchange API endpoint
@@ -89,13 +89,19 @@ class cryptocom extends cryptocom$1 {
89
89
  await this.loadMarkets();
90
90
  symbols = this.marketSymbols(symbols);
91
91
  const topics = [];
92
+ const messageHashes = [];
93
+ if (!limit) {
94
+ limit = 150;
95
+ }
92
96
  for (let i = 0; i < symbols.length; i++) {
93
97
  const symbol = symbols[i];
94
98
  const market = this.market(symbol);
95
- const currentTopic = 'book' + '.' + market['id'];
99
+ const currentTopic = 'book' + '.' + market['id'] + '.' + limit;
100
+ const messageHash = 'orderbook:' + market['symbol'];
101
+ messageHashes.push(messageHash);
96
102
  topics.push(currentTopic);
97
103
  }
98
- const orderbook = await this.watchPublicMultiple(topics, topics, params);
104
+ const orderbook = await this.watchPublicMultiple(messageHashes, topics, params);
99
105
  return orderbook.limit();
100
106
  }
101
107
  handleOrderBookSnapshot(client, message) {
@@ -120,7 +126,6 @@ class cryptocom extends cryptocom$1 {
120
126
  // ]
121
127
  // }
122
128
  //
123
- const messageHash = this.safeString(message, 'subscription');
124
129
  const marketId = this.safeString(message, 'instrument_name');
125
130
  const market = this.safeMarket(marketId);
126
131
  const symbol = market['symbol'];
@@ -136,6 +141,7 @@ class cryptocom extends cryptocom$1 {
136
141
  }
137
142
  orderbook.reset(snapshot);
138
143
  this.orderbooks[symbol] = orderbook;
144
+ const messageHash = 'orderbook:' + symbol;
139
145
  client.resolve(orderbook, messageHash);
140
146
  }
141
147
  async watchTrades(symbol, since = undefined, limit = undefined, params = {}) {
@@ -539,7 +539,8 @@ class poloniex extends poloniex$1 {
539
539
  const marketId = this.safeString(data, 'symbol');
540
540
  const symbol = this.safeSymbol(marketId);
541
541
  const market = this.safeMarket(symbol);
542
- const timeframe = this.findTimeframe(channel);
542
+ const timeframes = this.safeValue(this.options, 'timeframes', {});
543
+ const timeframe = this.findTimeframe(channel, timeframes);
543
544
  const messageHash = channel + '::' + symbol;
544
545
  const parsed = this.parseWsOHLCV(data, market);
545
546
  this.ohlcvs[symbol] = this.safeValue(this.ohlcvs, symbol, {});
package/js/ccxt.d.ts CHANGED
@@ -4,7 +4,7 @@ import * as functions from './src/base/functions.js';
4
4
  import * as errors from './src/base/errors.js';
5
5
  import type { Market, Trade, Fee, Ticker, OrderBook, Order, Transaction, Tickers, Currency, Balance, DepositAddress, WithdrawalResponse, DepositAddressResponse, OHLCV, Balances, PartialBalances, Dictionary, MinMax, Position, FundingRateHistory, Liquidation, FundingHistory, MarginMode, Greeks } from './src/base/types.js';
6
6
  import { BaseError, ExchangeError, PermissionDenied, AccountNotEnabled, AccountSuspended, ArgumentsRequired, BadRequest, BadSymbol, MarginModeAlreadySet, BadResponse, NullResponse, InsufficientFunds, InvalidAddress, InvalidOrder, OrderNotFound, OrderNotCached, CancelPending, OrderImmediatelyFillable, OrderNotFillable, DuplicateOrderId, NotSupported, NetworkError, DDoSProtection, RateLimitExceeded, ExchangeNotAvailable, OnMaintenance, InvalidNonce, RequestTimeout, AuthenticationError, AddressPending, NoChange } from './src/base/errors.js';
7
- declare const version = "4.2.6";
7
+ declare const version = "4.2.7";
8
8
  import ace from './src/ace.js';
9
9
  import alpaca from './src/alpaca.js';
10
10
  import ascendex from './src/ascendex.js';
package/js/ccxt.js CHANGED
@@ -38,7 +38,7 @@ import * as errors from './src/base/errors.js';
38
38
  import { BaseError, ExchangeError, PermissionDenied, AccountNotEnabled, AccountSuspended, ArgumentsRequired, BadRequest, BadSymbol, MarginModeAlreadySet, BadResponse, NullResponse, InsufficientFunds, InvalidAddress, InvalidOrder, OrderNotFound, OrderNotCached, CancelPending, OrderImmediatelyFillable, OrderNotFillable, DuplicateOrderId, NotSupported, NetworkError, DDoSProtection, RateLimitExceeded, ExchangeNotAvailable, OnMaintenance, InvalidNonce, RequestTimeout, AuthenticationError, AddressPending, NoChange } from './src/base/errors.js';
39
39
  //-----------------------------------------------------------------------------
40
40
  // this is updated by vss.js when building
41
- const version = '4.2.7';
41
+ const version = '4.2.8';
42
42
  Exchange.ccxtVersion = version;
43
43
  //-----------------------------------------------------------------------------
44
44
  import ace from './src/ace.js';
package/js/src/binance.js CHANGED
@@ -4417,6 +4417,8 @@ export default class binance extends Exchange {
4417
4417
  * @param {string} [params.marginMode] 'cross' or 'isolated', for spot margin trading
4418
4418
  * @param {boolean} [params.sor] *spot only* whether to use SOR (Smart Order Routing) or not, default is false
4419
4419
  * @param {boolean} [params.test] *spot only* whether to use the test endpoint or not, default is false
4420
+ * @param {float} [params.trailingPercent] the percent to trail away from the current market price
4421
+ * @param {float} [params.trailingTriggerPrice] the price to trigger a trailing order, default uses the price argument
4420
4422
  * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
4421
4423
  */
4422
4424
  await this.loadMarkets();
@@ -4465,6 +4467,8 @@ export default class binance extends Exchange {
4465
4467
  * @param {float|undefined} price the price at which the order is to be fullfilled, in units of the quote currency, ignored in market orders
4466
4468
  * @param {object} params extra parameters specific to the exchange API endpoint
4467
4469
  * @param {string|undefined} params.marginMode 'cross' or 'isolated', for spot margin trading
4470
+ * @param {float} [params.trailingPercent] the percent to trail away from the current market price
4471
+ * @param {float} [params.trailingTriggerPrice] the price to trigger a trailing order, default uses the price argument
4468
4472
  * @returns {object} request to be sent to the exchange
4469
4473
  */
4470
4474
  const market = this.market(symbol);
@@ -4478,9 +4482,12 @@ export default class binance extends Exchange {
4478
4482
  const stopLossPrice = this.safeValue(params, 'stopLossPrice', triggerPrice); // fallback to stopLoss
4479
4483
  const takeProfitPrice = this.safeValue(params, 'takeProfitPrice');
4480
4484
  const trailingDelta = this.safeValue(params, 'trailingDelta');
4485
+ const trailingTriggerPrice = this.safeString2(params, 'trailingTriggerPrice', 'activationPrice', price);
4486
+ const trailingPercent = this.safeString2(params, 'trailingPercent', 'callbackRate');
4487
+ const isTrailingPercentOrder = trailingPercent !== undefined;
4481
4488
  const isStopLoss = stopLossPrice !== undefined || trailingDelta !== undefined;
4482
4489
  const isTakeProfit = takeProfitPrice !== undefined;
4483
- params = this.omit(params, ['type', 'newClientOrderId', 'clientOrderId', 'postOnly', 'stopLossPrice', 'takeProfitPrice', 'stopPrice', 'triggerPrice']);
4490
+ params = this.omit(params, ['type', 'newClientOrderId', 'clientOrderId', 'postOnly', 'stopLossPrice', 'takeProfitPrice', 'stopPrice', 'triggerPrice', 'trailingTriggerPrice', 'trailingPercent']);
4484
4491
  const [marginMode, query] = this.handleMarginModeAndParams('createOrder', params);
4485
4492
  const request = {
4486
4493
  'symbol': market['id'],
@@ -4501,7 +4508,14 @@ export default class binance extends Exchange {
4501
4508
  }
4502
4509
  let uppercaseType = type.toUpperCase();
4503
4510
  let stopPrice = undefined;
4504
- if (isStopLoss) {
4511
+ if (isTrailingPercentOrder) {
4512
+ uppercaseType = 'TRAILING_STOP_MARKET';
4513
+ request['callbackRate'] = trailingPercent;
4514
+ if (trailingTriggerPrice !== undefined) {
4515
+ request['activationPrice'] = this.priceToPrecision(symbol, trailingTriggerPrice);
4516
+ }
4517
+ }
4518
+ else if (isStopLoss) {
4505
4519
  stopPrice = stopLossPrice;
4506
4520
  if (isMarketOrder) {
4507
4521
  // spot STOP_LOSS market orders are not a valid order type
@@ -4645,9 +4659,8 @@ export default class binance extends Exchange {
4645
4659
  }
4646
4660
  else if (uppercaseType === 'TRAILING_STOP_MARKET') {
4647
4661
  quantityIsRequired = true;
4648
- const callbackRate = this.safeNumber(query, 'callbackRate');
4649
- if (callbackRate === undefined) {
4650
- throw new InvalidOrder(this.id + ' createOrder() requires a callbackRate extra param for a ' + type + ' order');
4662
+ if (trailingPercent === undefined) {
4663
+ throw new InvalidOrder(this.id + ' createOrder() requires a trailingPercent param for a ' + type + ' order');
4651
4664
  }
4652
4665
  }
4653
4666
  if (quantityIsRequired) {
package/js/src/bingx.d.ts CHANGED
@@ -66,6 +66,7 @@ export default class bingx extends Exchange {
66
66
  createMarketSellOrderWithCost(symbol: string, cost: any, params?: {}): Promise<Order>;
67
67
  createOrderRequest(symbol: string, type: OrderType, side: OrderSide, amount: any, price?: any, params?: {}): any;
68
68
  createOrder(symbol: string, type: OrderType, side: OrderSide, amount: any, price?: any, params?: {}): Promise<Order>;
69
+ fixStringifiedJsonMembers(content: any): any;
69
70
  createOrders(orders: OrderRequest[], params?: {}): Promise<Order[]>;
70
71
  parseOrderSide(side: any): string;
71
72
  parseOrder(order: any, market?: Market): Order;
package/js/src/bingx.js CHANGED
@@ -6,7 +6,7 @@
6
6
 
7
7
  // ---------------------------------------------------------------------------
8
8
  import Exchange from './abstract/bingx.js';
9
- import { AuthenticationError, ExchangeNotAvailable, PermissionDenied, ExchangeError, InsufficientFunds, BadRequest, OrderNotFound, DDoSProtection, BadSymbol, ArgumentsRequired } from './base/errors.js';
9
+ import { AuthenticationError, ExchangeNotAvailable, PermissionDenied, AccountSuspended, ExchangeError, InsufficientFunds, BadRequest, OrderNotFound, DDoSProtection, BadSymbol, ArgumentsRequired } from './base/errors.js';
10
10
  import { Precise } from './base/Precise.js';
11
11
  import { sha256 } from './static_dependencies/noble-hashes/sha256.js';
12
12
  import { DECIMAL_PLACES } from './base/functions/number.js';
@@ -355,6 +355,7 @@ export default class bingx extends Exchange {
355
355
  '80014': BadRequest,
356
356
  '80016': OrderNotFound,
357
357
  '80017': OrderNotFound,
358
+ '100414': AccountSuspended,
358
359
  '100437': BadRequest, // {"code":100437,"msg":"The withdrawal amount is lower than the minimum limit, please re-enter.","timestamp":1689258588845}
359
360
  },
360
361
  'broad': {},
@@ -1898,12 +1899,26 @@ export default class bingx extends Exchange {
1898
1899
  // }
1899
1900
  //
1900
1901
  if (typeof response === 'string') {
1902
+ // broken api engine : order-ids are too long numbers (i.e. 1742930526912864656)
1903
+ // and JSON.parse can not handle them in JS, so we have to use .parseJson
1904
+ // however, when order has an attached SL/TP, their value types need extra parsing
1905
+ response = this.fixStringifiedJsonMembers(response);
1901
1906
  response = this.parseJson(response);
1902
1907
  }
1903
1908
  const data = this.safeValue(response, 'data', {});
1904
1909
  const order = this.safeValue(data, 'order', data);
1905
1910
  return this.parseOrder(order, market);
1906
1911
  }
1912
+ fixStringifiedJsonMembers(content) {
1913
+ // when stringified json has members with their values also stringified, like:
1914
+ // '{"code":0, "data":{"order":{"orderId":1742968678528512345,"symbol":"BTC-USDT", "takeProfit":"{\"type\":\"TAKE_PROFIT\",\"stopPrice\":43320.1}","reduceOnly":false}}}'
1915
+ // we can fix with below manipulations
1916
+ // @ts-ignore
1917
+ let modifiedContent = content.replaceAll('\\', '');
1918
+ modifiedContent = modifiedContent.replaceAll('"{', '{');
1919
+ modifiedContent = modifiedContent.replaceAll('}"', '}');
1920
+ return modifiedContent;
1921
+ }
1907
1922
  async createOrders(orders, params = {}) {
1908
1923
  /**
1909
1924
  * @method