ccxt 4.4.34 → 4.4.36

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 (78) hide show
  1. package/README.md +6 -5
  2. package/dist/ccxt.browser.min.js +3 -3
  3. package/dist/cjs/ccxt.js +6 -1
  4. package/dist/cjs/src/abstract/defx.js +9 -0
  5. package/dist/cjs/src/bingx.js +339 -144
  6. package/dist/cjs/src/bitfinex2.js +20 -12
  7. package/dist/cjs/src/bitmex.js +104 -2
  8. package/dist/cjs/src/bitopro.js +22 -4
  9. package/dist/cjs/src/bitrue.js +2 -2
  10. package/dist/cjs/src/bitso.js +2 -1
  11. package/dist/cjs/src/btcmarkets.js +3 -3
  12. package/dist/cjs/src/btcturk.js +19 -19
  13. package/dist/cjs/src/bybit.js +20 -0
  14. package/dist/cjs/src/defx.js +2048 -0
  15. package/dist/cjs/src/deribit.js +34 -14
  16. package/dist/cjs/src/gate.js +158 -41
  17. package/dist/cjs/src/hashkey.js +1 -1
  18. package/dist/cjs/src/htx.js +14 -2
  19. package/dist/cjs/src/hyperliquid.js +73 -11
  20. package/dist/cjs/src/idex.js +3 -3
  21. package/dist/cjs/src/kraken.js +110 -102
  22. package/dist/cjs/src/kucoin.js +1 -1
  23. package/dist/cjs/src/okx.js +1 -0
  24. package/dist/cjs/src/onetrading.js +20 -395
  25. package/dist/cjs/src/pro/bitrue.js +13 -11
  26. package/dist/cjs/src/pro/defx.js +864 -0
  27. package/dist/cjs/src/pro/probit.js +58 -66
  28. package/dist/cjs/src/xt.js +5 -5
  29. package/js/ccxt.d.ts +8 -2
  30. package/js/ccxt.js +6 -2
  31. package/js/src/abstract/bingx.d.ts +1 -0
  32. package/js/src/abstract/bitopro.d.ts +1 -0
  33. package/js/src/abstract/bitpanda.d.ts +0 -12
  34. package/js/src/abstract/bitrue.d.ts +3 -3
  35. package/js/src/abstract/bybit.d.ts +15 -0
  36. package/js/src/abstract/defx.d.ts +72 -0
  37. package/js/src/abstract/defx.js +11 -0
  38. package/js/src/abstract/deribit.d.ts +1 -0
  39. package/js/src/abstract/gate.d.ts +14 -0
  40. package/js/src/abstract/gateio.d.ts +14 -0
  41. package/js/src/abstract/okx.d.ts +1 -0
  42. package/js/src/abstract/onetrading.d.ts +0 -12
  43. package/js/src/bingx.d.ts +8 -0
  44. package/js/src/bingx.js +339 -144
  45. package/js/src/bitfinex2.js +21 -13
  46. package/js/src/bitmex.js +104 -2
  47. package/js/src/bitopro.d.ts +11 -0
  48. package/js/src/bitopro.js +22 -4
  49. package/js/src/bitrue.js +2 -2
  50. package/js/src/bitso.js +2 -1
  51. package/js/src/btcmarkets.js +3 -3
  52. package/js/src/btcturk.js +19 -19
  53. package/js/src/bybit.js +20 -0
  54. package/js/src/defx.d.ts +349 -0
  55. package/js/src/defx.js +2049 -0
  56. package/js/src/deribit.d.ts +2 -0
  57. package/js/src/deribit.js +34 -14
  58. package/js/src/gate.d.ts +5 -5
  59. package/js/src/gate.js +158 -41
  60. package/js/src/hashkey.js +1 -1
  61. package/js/src/htx.d.ts +3 -0
  62. package/js/src/htx.js +14 -2
  63. package/js/src/hyperliquid.d.ts +10 -0
  64. package/js/src/hyperliquid.js +75 -13
  65. package/js/src/idex.js +4 -4
  66. package/js/src/kraken.d.ts +11 -8
  67. package/js/src/kraken.js +110 -102
  68. package/js/src/kucoin.js +1 -1
  69. package/js/src/okx.js +1 -0
  70. package/js/src/onetrading.d.ts +15 -67
  71. package/js/src/onetrading.js +20 -395
  72. package/js/src/pro/bitrue.js +13 -11
  73. package/js/src/pro/defx.d.ts +236 -0
  74. package/js/src/pro/defx.js +865 -0
  75. package/js/src/pro/probit.d.ts +2 -1
  76. package/js/src/pro/probit.js +58 -66
  77. package/js/src/xt.js +5 -5
  78. package/package.json +2 -1
package/js/src/htx.js CHANGED
@@ -5432,8 +5432,8 @@ export default class htx extends Exchange {
5432
5432
  request['price'] = this.priceToPrecision(symbol, price);
5433
5433
  }
5434
5434
  }
5435
+ const reduceOnly = this.safeBool2(params, 'reduceOnly', 'reduce_only', false);
5435
5436
  if (!isStopLossTriggerOrder && !isTakeProfitTriggerOrder) {
5436
- const reduceOnly = this.safeValue2(params, 'reduceOnly', 'reduce_only', false);
5437
5437
  if (reduceOnly) {
5438
5438
  request['reduce_only'] = 1;
5439
5439
  }
@@ -5442,10 +5442,19 @@ export default class htx extends Exchange {
5442
5442
  request['order_price_type'] = type;
5443
5443
  }
5444
5444
  }
5445
+ const hedged = this.safeBool(params, 'hedged', false);
5446
+ if (hedged) {
5447
+ if (reduceOnly) {
5448
+ request['offset'] = 'close';
5449
+ }
5450
+ else {
5451
+ request['offset'] = 'open';
5452
+ }
5453
+ }
5445
5454
  const broker = this.safeValue(this.options, 'broker', {});
5446
5455
  const brokerId = this.safeString(broker, 'id');
5447
5456
  request['channel_code'] = brokerId;
5448
- params = this.omit(params, ['reduceOnly', 'triggerPrice', 'stopPrice', 'stopLossPrice', 'takeProfitPrice', 'triggerType', 'leverRate', 'timeInForce', 'leverage', 'trailingPercent', 'trailingTriggerPrice']);
5457
+ params = this.omit(params, ['reduceOnly', 'triggerPrice', 'stopPrice', 'stopLossPrice', 'takeProfitPrice', 'triggerType', 'leverRate', 'timeInForce', 'leverage', 'trailingPercent', 'trailingTriggerPrice', 'hedged']);
5449
5458
  return this.extend(request, params);
5450
5459
  }
5451
5460
  /**
@@ -5459,6 +5468,8 @@ export default class htx extends Exchange {
5459
5468
  * @see https://huobiapi.github.io/docs/usdt_swap/v1/en/#cross-place-trigger-order // usdt-m swap cross trigger
5460
5469
  * @see https://huobiapi.github.io/docs/usdt_swap/v1/en/#isolated-place-an-order // usdt-m swap isolated
5461
5470
  * @see https://huobiapi.github.io/docs/usdt_swap/v1/en/#isolated-place-trigger-order // usdt-m swap isolated trigger
5471
+ * @see https://huobiapi.github.io/docs/usdt_swap/v1/en/#isolated-set-a-take-profit-and-stop-loss-order-for-an-existing-position
5472
+ * @see https://huobiapi.github.io/docs/usdt_swap/v1/en/#cross-set-a-take-profit-and-stop-loss-order-for-an-existing-position
5462
5473
  * @see https://huobiapi.github.io/docs/dm/v1/en/#place-an-order // coin-m futures
5463
5474
  * @see https://huobiapi.github.io/docs/dm/v1/en/#place-trigger-order // coin-m futures contract trigger
5464
5475
  * @param {string} symbol unified symbol of the market to create an order in
@@ -5479,6 +5490,7 @@ export default class htx extends Exchange {
5479
5490
  * @param {float} [params.cost] *spot market buy only* the quote quantity that can be used as an alternative for the amount
5480
5491
  * @param {float} [params.trailingPercent] *contract only* the percent to trail away from the current market price
5481
5492
  * @param {float} [params.trailingTriggerPrice] *contract only* the price to trigger a trailing order, default uses the price argument
5493
+ * @param {bool} [params.hedged] *contract only* true for hedged mode, false for one way mode, default is false
5482
5494
  * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
5483
5495
  */
5484
5496
  async createOrder(symbol, type, side, amount, price = undefined, params = {}) {
@@ -35,6 +35,16 @@ export default class hyperliquid extends Exchange {
35
35
  * @returns {object[]} an array of objects representing market data
36
36
  */
37
37
  fetchSwapMarkets(params?: {}): Promise<Market[]>;
38
+ /**
39
+ * @method
40
+ * @name calculatePricePrecision
41
+ * @description Helper function to calculate the Hyperliquid DECIMAL_PLACES price precision
42
+ * @param {float} price the price to use in the calculation
43
+ * @param {int} amountPrecision the amountPrecision to use in the calculation
44
+ * @param {int} maxDecimals the maxDecimals to use in the calculation
45
+ * @returns {int} The calculated price precision
46
+ */
47
+ calculatePricePrecision(price: number, amountPrecision: number, maxDecimals: number): number;
38
48
  /**
39
49
  * @method
40
50
  * @name hyperliquid#fetchMarkets
@@ -6,9 +6,9 @@
6
6
 
7
7
  // ---------------------------------------------------------------------------
8
8
  import Exchange from './abstract/hyperliquid.js';
9
- import { ExchangeError, ArgumentsRequired, NotSupported, InvalidOrder, OrderNotFound, BadRequest } from './base/errors.js';
9
+ import { ExchangeError, ArgumentsRequired, NotSupported, InvalidOrder, OrderNotFound, BadRequest, InsufficientFunds } from './base/errors.js';
10
10
  import { Precise } from './base/Precise.js';
11
- import { ROUND, SIGNIFICANT_DIGITS, DECIMAL_PLACES } from './base/functions/number.js';
11
+ import { ROUND, SIGNIFICANT_DIGITS, DECIMAL_PLACES, TICK_SIZE } from './base/functions/number.js';
12
12
  import { keccak_256 as keccak } from './static_dependencies/noble-hashes/sha3.js';
13
13
  import { secp256k1 } from './static_dependencies/noble-curves/secp256k1.js';
14
14
  import { ecdsa } from './base/functions/crypto.js';
@@ -205,9 +205,11 @@ export default class hyperliquid extends Exchange {
205
205
  'User or API Wallet ': InvalidOrder,
206
206
  'Order has invalid size': InvalidOrder,
207
207
  'Order price cannot be more than 80% away from the reference price': InvalidOrder,
208
+ 'Order has zero size.': InvalidOrder,
209
+ 'Insufficient spot balance asset': InsufficientFunds,
208
210
  },
209
211
  },
210
- 'precisionMode': DECIMAL_PLACES,
212
+ 'precisionMode': TICK_SIZE,
211
213
  'commonCurrencies': {},
212
214
  'options': {
213
215
  'defaultType': 'swap',
@@ -354,6 +356,55 @@ export default class hyperliquid extends Exchange {
354
356
  }
355
357
  return this.parseMarkets(result);
356
358
  }
359
+ /**
360
+ * @method
361
+ * @name calculatePricePrecision
362
+ * @description Helper function to calculate the Hyperliquid DECIMAL_PLACES price precision
363
+ * @param {float} price the price to use in the calculation
364
+ * @param {int} amountPrecision the amountPrecision to use in the calculation
365
+ * @param {int} maxDecimals the maxDecimals to use in the calculation
366
+ * @returns {int} The calculated price precision
367
+ */
368
+ calculatePricePrecision(price, amountPrecision, maxDecimals) {
369
+ let pricePrecision = 0;
370
+ const priceStr = this.numberToString(price);
371
+ if (priceStr === undefined) {
372
+ return 0;
373
+ }
374
+ const priceSplitted = priceStr.split('.');
375
+ if (Precise.stringEq(priceStr, '0')) {
376
+ // Significant digits is always 5 in this case
377
+ const significantDigits = 5;
378
+ // Integer digits is always 0 in this case (0 doesn't count)
379
+ const integerDigits = 0;
380
+ // Calculate the price precision
381
+ pricePrecision = Math.min(maxDecimals - amountPrecision, significantDigits - integerDigits);
382
+ }
383
+ else if (Precise.stringGt(priceStr, '0') && Precise.stringLt(priceStr, '1')) {
384
+ // Significant digits, always 5 in this case
385
+ const significantDigits = 5;
386
+ // Get the part after the decimal separator
387
+ const decimalPart = this.safeString(priceSplitted, 1, '');
388
+ // Count the number of leading zeros in the decimal part
389
+ let leadingZeros = 0;
390
+ while ((leadingZeros <= decimalPart.length) && (decimalPart[leadingZeros] === '0')) {
391
+ leadingZeros = leadingZeros + 1;
392
+ }
393
+ // Calculate price precision based on leading zeros and significant digits
394
+ pricePrecision = leadingZeros + significantDigits;
395
+ // Calculate the price precision based on maxDecimals - szDecimals and the calculated price precision from the previous step
396
+ pricePrecision = Math.min(maxDecimals - amountPrecision, pricePrecision);
397
+ }
398
+ else {
399
+ // Count the numbers before the decimal separator
400
+ const integerPart = this.safeString(priceSplitted, 0, '');
401
+ // Get significant digits, take the max() of 5 and the integer digits count
402
+ const significantDigits = Math.max(5, integerPart.length);
403
+ // Calculate price precision based on maxDecimals - szDecimals and significantDigits - integerPart.length
404
+ pricePrecision = Math.min(maxDecimals - amountPrecision, significantDigits - integerPart.length);
405
+ }
406
+ return this.parseToInt(pricePrecision);
407
+ }
357
408
  /**
358
409
  * @method
359
410
  * @name hyperliquid#fetchMarkets
@@ -443,7 +494,11 @@ export default class hyperliquid extends Exchange {
443
494
  const symbol = base + '/' + quote;
444
495
  const innerBaseTokenInfo = this.safeDict(baseTokenInfo, 'spec', baseTokenInfo);
445
496
  // const innerQuoteTokenInfo = this.safeDict (quoteTokenInfo, 'spec', quoteTokenInfo);
446
- const amountPrecision = this.safeInteger(innerBaseTokenInfo, 'szDecimals');
497
+ const amountPrecisionStr = this.safeString(innerBaseTokenInfo, 'szDecimals');
498
+ const amountPrecision = parseInt(amountPrecisionStr);
499
+ const price = this.safeNumber(extraData, 'midPx');
500
+ const pricePrecision = this.calculatePricePrecision(price, amountPrecision, 8);
501
+ const pricePrecisionStr = this.numberToString(pricePrecision);
447
502
  // const quotePrecision = this.parseNumber (this.parsePrecision (this.safeString (innerQuoteTokenInfo, 'szDecimals')));
448
503
  const baseId = this.numberToString(i + 10000);
449
504
  markets.push(this.safeMarketStructure({
@@ -474,8 +529,8 @@ export default class hyperliquid extends Exchange {
474
529
  'strike': undefined,
475
530
  'optionType': undefined,
476
531
  'precision': {
477
- 'amount': amountPrecision,
478
- 'price': 8 - amountPrecision, // MAX_DECIMALS is 8
532
+ 'amount': this.parseNumber(this.parsePrecision(amountPrecisionStr)),
533
+ 'price': this.parseNumber(this.parsePrecision(pricePrecisionStr)),
479
534
  },
480
535
  'limits': {
481
536
  'leverage': {
@@ -539,7 +594,11 @@ export default class hyperliquid extends Exchange {
539
594
  const fees = this.safeDict(this.fees, 'swap', {});
540
595
  const taker = this.safeNumber(fees, 'taker');
541
596
  const maker = this.safeNumber(fees, 'maker');
542
- const amountPrecision = this.safeInteger(market, 'szDecimals');
597
+ const amountPrecisionStr = this.safeString(market, 'szDecimals');
598
+ const amountPrecision = parseInt(amountPrecisionStr);
599
+ const price = this.safeNumber(market, 'markPx', 0);
600
+ const pricePrecision = this.calculatePricePrecision(price, amountPrecision, 6);
601
+ const pricePrecisionStr = this.numberToString(pricePrecision);
543
602
  return this.safeMarketStructure({
544
603
  'id': baseId,
545
604
  'symbol': symbol,
@@ -567,8 +626,8 @@ export default class hyperliquid extends Exchange {
567
626
  'strike': undefined,
568
627
  'optionType': undefined,
569
628
  'precision': {
570
- 'amount': amountPrecision,
571
- 'price': 6 - amountPrecision, // MAX_DECIMALS is 6
629
+ 'amount': this.parseNumber(this.parsePrecision(amountPrecisionStr)),
630
+ 'price': this.parseNumber(this.parsePrecision(pricePrecisionStr)),
572
631
  },
573
632
  'limits': {
574
633
  'leverage': {
@@ -1045,10 +1104,13 @@ export default class hyperliquid extends Exchange {
1045
1104
  }
1046
1105
  priceToPrecision(symbol, price) {
1047
1106
  const market = this.market(symbol);
1048
- // https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/tick-and-lot-size
1049
- const result = this.decimalToPrecision(price, ROUND, 5, SIGNIFICANT_DIGITS, this.paddingMode);
1050
- const decimalParsedResult = this.decimalToPrecision(result, ROUND, market['precision']['price'], this.precisionMode, this.paddingMode);
1051
- return decimalParsedResult;
1107
+ const priceStr = this.numberToString(price);
1108
+ const integerPart = priceStr.split('.')[0];
1109
+ const significantDigits = Math.max(5, integerPart.length);
1110
+ const result = this.decimalToPrecision(price, ROUND, significantDigits, SIGNIFICANT_DIGITS, this.paddingMode);
1111
+ const maxDecimals = market['spot'] ? 8 : 6;
1112
+ const subtractedValue = maxDecimals - this.precisionFromString(this.safeString(market['precision'], 'amount'));
1113
+ return this.decimalToPrecision(result, ROUND, subtractedValue, DECIMAL_PLACES, this.paddingMode);
1052
1114
  }
1053
1115
  hashMessage(message) {
1054
1116
  return '0x' + this.hash(message, keccak, 'hex');
package/js/src/idex.js CHANGED
@@ -6,7 +6,7 @@
6
6
 
7
7
  // ---------------------------------------------------------------------------
8
8
  import Exchange from './abstract/idex.js';
9
- import { TICK_SIZE, PAD_WITH_ZERO, ROUND, TRUNCATE, DECIMAL_PLACES } from './base/functions/number.js';
9
+ import { TICK_SIZE, PAD_WITH_ZERO, ROUND, TRUNCATE } from './base/functions/number.js';
10
10
  import { InvalidOrder, InsufficientFunds, ExchangeError, ExchangeNotAvailable, DDoSProtection, BadRequest, NotSupported, InvalidAddress, AuthenticationError } from './base/errors.js';
11
11
  import { Precise } from './base/Precise.js';
12
12
  import { sha256 } from './static_dependencies/noble-hashes/sha256.js';
@@ -198,10 +198,8 @@ export default class idex extends Exchange {
198
198
  // {"code":"INVALID_PARAMETER","message":"invalid value provided for request parameter \"price\": all quantities and prices must be below 100 billion, above 0, need to be provided as strings, and always require 4 decimals ending with 4 zeroes"}
199
199
  //
200
200
  const market = this.market(symbol);
201
- const info = this.safeValue(market, 'info', {});
202
- const quoteAssetPrecision = this.safeInteger(info, 'quoteAssetPrecision');
203
201
  price = this.decimalToPrecision(price, ROUND, market['precision']['price'], this.precisionMode);
204
- return this.decimalToPrecision(price, TRUNCATE, quoteAssetPrecision, DECIMAL_PLACES, PAD_WITH_ZERO);
202
+ return this.decimalToPrecision(price, TRUNCATE, market['precision']['quote'], TICK_SIZE, PAD_WITH_ZERO);
205
203
  }
206
204
  /**
207
205
  * @method
@@ -309,6 +307,8 @@ export default class idex extends Exchange {
309
307
  'precision': {
310
308
  'amount': basePrecision,
311
309
  'price': this.safeNumber(entry, 'tickSize'),
310
+ 'base': basePrecision,
311
+ 'quote': quotePrecision,
312
312
  },
313
313
  'limits': {
314
314
  'leverage': {
@@ -207,20 +207,23 @@ export default class kraken extends Exchange {
207
207
  * @method
208
208
  * @name kraken#editOrder
209
209
  * @description edit a trade order
210
- * @see https://docs.kraken.com/rest/#tag/Spot-Trading/operation/editOrder
210
+ * @see https://docs.kraken.com/api/docs/rest-api/amend-order
211
211
  * @param {string} id order id
212
212
  * @param {string} symbol unified symbol of the market to create an order in
213
213
  * @param {string} type 'market' or 'limit'
214
214
  * @param {string} side 'buy' or 'sell'
215
- * @param {float} amount how much of the currency you want to trade in units of the base currency
215
+ * @param {float} [amount] how much of the currency you want to trade in units of the base currency
216
216
  * @param {float} [price] the price at which the order is to be fulfilled, in units of the quote currency, ignored in market orders
217
217
  * @param {object} [params] extra parameters specific to the exchange API endpoint
218
- * @param {float} [params.stopLossPrice] *margin only* the price that a stop loss order is triggered at
219
- * @param {float} [params.takeProfitPrice] *margin only* the price that a take profit order is triggered at
220
- * @param {string} [params.trailingAmount] *margin only* the quote price away from the current market price
221
- * @param {string} [params.trailingLimitAmount] *margin only* the quote amount away from the trailingAmount
222
- * @param {string} [params.offset] *margin only* '+' or '-' whether you want the trailingLimitAmount value to be positive or negative, default is negative '-'
223
- * @param {string} [params.trigger] *margin only* the activation price type, 'last' or 'index', default is 'last'
218
+ * @param {float} [params.stopLossPrice] the price that a stop loss order is triggered at
219
+ * @param {float} [params.takeProfitPrice] the price that a take profit order is triggered at
220
+ * @param {string} [params.trailingAmount] the quote amount to trail away from the current market price
221
+ * @param {string} [params.trailingPercent] the percent to trail away from the current market price
222
+ * @param {string} [params.trailingLimitAmount] the quote amount away from the trailingAmount
223
+ * @param {string} [params.trailingLimitPercent] the percent away from the trailingAmount
224
+ * @param {string} [params.offset] '+' or '-' whether you want the trailingLimitAmount value to be positive or negative
225
+ * @param {boolean} [params.postOnly] if true, the order will only be posted to the order book and not executed immediately
226
+ * @param {string} [params.clientOrderId] the orders client order id
224
227
  * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
225
228
  */
226
229
  editOrder(id: string, symbol: string, type: OrderType, side: OrderSide, amount?: Num, price?: Num, params?: {}): Promise<Order>;
package/js/src/kraken.js CHANGED
@@ -432,31 +432,43 @@ export default class kraken extends Exchange {
432
432
  },
433
433
  'precisionMode': TICK_SIZE,
434
434
  'exceptions': {
435
- 'EQuery:Invalid asset pair': BadSymbol,
436
- 'EAPI:Invalid key': AuthenticationError,
437
- 'EFunding:Unknown withdraw key': InvalidAddress,
438
- 'EFunding:Invalid amount': InsufficientFunds,
439
- 'EService:Unavailable': ExchangeNotAvailable,
440
- 'EDatabase:Internal error': ExchangeNotAvailable,
441
- 'EService:Busy': ExchangeNotAvailable,
442
- 'EQuery:Unknown asset': BadSymbol,
443
- 'EAPI:Rate limit exceeded': DDoSProtection,
444
- 'EOrder:Rate limit exceeded': DDoSProtection,
445
- 'EGeneral:Internal error': ExchangeNotAvailable,
446
- 'EGeneral:Temporary lockout': DDoSProtection,
447
- 'EGeneral:Permission denied': PermissionDenied,
448
- 'EGeneral:Invalid arguments:price': InvalidOrder,
449
- 'EOrder:Unknown order': InvalidOrder,
450
- 'EOrder:Invalid price:Invalid price argument': InvalidOrder,
451
- 'EOrder:Order minimum not met': InvalidOrder,
452
- 'EGeneral:Invalid arguments': BadRequest,
453
- 'ESession:Invalid session': AuthenticationError,
454
- 'EAPI:Invalid nonce': InvalidNonce,
455
- 'EFunding:No funding method': BadRequest,
456
- 'EFunding:Unknown asset': BadSymbol,
457
- 'EService:Market in post_only mode': OnMaintenance,
458
- 'EGeneral:Too many requests': DDoSProtection,
459
- 'ETrade:User Locked': AccountSuspended, // {"error":["ETrade:User Locked"]}
435
+ 'exact': {
436
+ 'EQuery:Invalid asset pair': BadSymbol,
437
+ 'EAPI:Invalid key': AuthenticationError,
438
+ 'EFunding:Unknown withdraw key': InvalidAddress,
439
+ 'EFunding:Invalid amount': InsufficientFunds,
440
+ 'EService:Unavailable': ExchangeNotAvailable,
441
+ 'EDatabase:Internal error': ExchangeNotAvailable,
442
+ 'EService:Busy': ExchangeNotAvailable,
443
+ 'EQuery:Unknown asset': BadSymbol,
444
+ 'EAPI:Rate limit exceeded': DDoSProtection,
445
+ 'EOrder:Rate limit exceeded': DDoSProtection,
446
+ 'EGeneral:Internal error': ExchangeNotAvailable,
447
+ 'EGeneral:Temporary lockout': DDoSProtection,
448
+ 'EGeneral:Permission denied': PermissionDenied,
449
+ 'EGeneral:Invalid arguments:price': InvalidOrder,
450
+ 'EOrder:Unknown order': InvalidOrder,
451
+ 'EOrder:Invalid price:Invalid price argument': InvalidOrder,
452
+ 'EOrder:Order minimum not met': InvalidOrder,
453
+ 'EOrder:Insufficient funds': InsufficientFunds,
454
+ 'EGeneral:Invalid arguments': BadRequest,
455
+ 'ESession:Invalid session': AuthenticationError,
456
+ 'EAPI:Invalid nonce': InvalidNonce,
457
+ 'EFunding:No funding method': BadRequest,
458
+ 'EFunding:Unknown asset': BadSymbol,
459
+ 'EService:Market in post_only mode': OnMaintenance,
460
+ 'EGeneral:Too many requests': DDoSProtection,
461
+ 'ETrade:User Locked': AccountSuspended, // {"error":["ETrade:User Locked"]}
462
+ },
463
+ 'broad': {
464
+ ':Invalid order': InvalidOrder,
465
+ ':Invalid arguments:volume': InvalidOrder,
466
+ ':Invalid arguments:viqc': InvalidOrder,
467
+ ':Invalid nonce': InvalidNonce,
468
+ ':IInsufficient funds': InsufficientFunds,
469
+ ':Cancel pending': CancelPending,
470
+ ':Rate limit exceeded': RateLimitExceeded,
471
+ },
460
472
  },
461
473
  });
462
474
  }
@@ -1587,18 +1599,9 @@ export default class kraken extends Exchange {
1587
1599
  // editOrder
1588
1600
  //
1589
1601
  // {
1590
- // "status": "ok",
1591
- // "txid": "OAW2BO-7RWEK-PZY5UO",
1592
- // "originaltxid": "OXL6SS-UPNMC-26WBE7",
1593
- // "newuserref": 1234,
1594
- // "olduserref": 123,
1595
- // "volume": "0.00075000",
1596
- // "price": "13500.0",
1597
- // "orders_cancelled": 1,
1598
- // "descr": {
1599
- // "order": "buy 0.00075000 XBTUSDT @ limit 13500.0"
1600
- // }
1602
+ // "amend_id": "TJSMEH-AA67V-YUSQ6O"
1601
1603
  // }
1604
+ //
1602
1605
  // ws - createOrder
1603
1606
  // {
1604
1607
  // "descr": 'sell 0.00010000 XBTUSDT @ market',
@@ -1718,7 +1721,7 @@ export default class kraken extends Exchange {
1718
1721
  price = this.safeString(order, 'price', price);
1719
1722
  }
1720
1723
  const flags = this.safeString(order, 'oflags', '');
1721
- const isPostOnly = flags.indexOf('post') > -1;
1724
+ let isPostOnly = flags.indexOf('post') > -1;
1722
1725
  const average = this.safeNumber(order, 'price');
1723
1726
  if (market !== undefined) {
1724
1727
  symbol = market['symbol'];
@@ -1737,12 +1740,12 @@ export default class kraken extends Exchange {
1737
1740
  }
1738
1741
  }
1739
1742
  const status = this.parseOrderStatus(this.safeString(order, 'status'));
1740
- let id = this.safeString2(order, 'id', 'txid');
1743
+ let id = this.safeStringN(order, ['id', 'txid', 'amend_id']);
1741
1744
  if ((id === undefined) || (id.startsWith('['))) {
1742
1745
  const txid = this.safeList(order, 'txid');
1743
1746
  id = this.safeString(txid, 0);
1744
1747
  }
1745
- const clientOrderId = this.safeString2(order, 'userref', 'newuserref');
1748
+ const clientOrderId = this.safeString(order, 'userref');
1746
1749
  const rawTrades = this.safeValue(order, 'trades', []);
1747
1750
  const trades = [];
1748
1751
  for (let i = 0; i < rawTrades.length; i++) {
@@ -1760,19 +1763,21 @@ export default class kraken extends Exchange {
1760
1763
  let takeProfitPrice = undefined;
1761
1764
  // the dashed strings are not provided from fields (eg. fetch order)
1762
1765
  // while spaced strings from "order" sentence (when other fields not available)
1763
- if (rawType.startsWith('take-profit')) {
1764
- takeProfitPrice = this.safeString(description, 'price');
1765
- price = this.omitZero(this.safeString(description, 'price2'));
1766
- }
1767
- else if (rawType.startsWith('stop-loss')) {
1768
- stopLossPrice = this.safeString(description, 'price');
1769
- price = this.omitZero(this.safeString(description, 'price2'));
1770
- }
1771
- else if (rawType === 'take profit') {
1772
- takeProfitPrice = triggerPrice;
1773
- }
1774
- else if (rawType === 'stop loss') {
1775
- stopLossPrice = triggerPrice;
1766
+ if (rawType !== undefined) {
1767
+ if (rawType.startsWith('take-profit')) {
1768
+ takeProfitPrice = this.safeString(description, 'price');
1769
+ price = this.omitZero(this.safeString(description, 'price2'));
1770
+ }
1771
+ else if (rawType.startsWith('stop-loss')) {
1772
+ stopLossPrice = this.safeString(description, 'price');
1773
+ price = this.omitZero(this.safeString(description, 'price2'));
1774
+ }
1775
+ else if (rawType === 'take profit') {
1776
+ takeProfitPrice = triggerPrice;
1777
+ }
1778
+ else if (rawType === 'stop loss') {
1779
+ stopLossPrice = triggerPrice;
1780
+ }
1776
1781
  }
1777
1782
  let finalType = this.parseOrderType(rawType);
1778
1783
  // unlike from endpoints which provide eg: "take-profit-limit"
@@ -1781,6 +1786,10 @@ export default class kraken extends Exchange {
1781
1786
  if (this.inArray(finalType, ['stop loss', 'take profit'])) {
1782
1787
  finalType = (price === undefined) ? 'market' : 'limit';
1783
1788
  }
1789
+ const amendId = this.safeString(order, 'amend_id');
1790
+ if (amendId !== undefined) {
1791
+ isPostOnly = undefined;
1792
+ }
1784
1793
  return this.safeOrder({
1785
1794
  'id': id,
1786
1795
  'clientOrderId': clientOrderId,
@@ -1810,10 +1819,10 @@ export default class kraken extends Exchange {
1810
1819
  }, market);
1811
1820
  }
1812
1821
  orderRequest(method, symbol, type, request, amount, price = undefined, params = {}) {
1813
- const clientOrderId = this.safeString2(params, 'userref', 'clientOrderId');
1814
- params = this.omit(params, ['userref', 'clientOrderId']);
1822
+ const clientOrderId = this.safeString(params, 'clientOrderId');
1823
+ params = this.omit(params, ['clientOrderId']);
1815
1824
  if (clientOrderId !== undefined) {
1816
- request['userref'] = clientOrderId;
1825
+ request['cl_ord_id'] = clientOrderId;
1817
1826
  }
1818
1827
  const stopLossTriggerPrice = this.safeString(params, 'stopLossPrice');
1819
1828
  const takeProfitTriggerPrice = this.safeString(params, 'takeProfitPrice');
@@ -1943,20 +1952,23 @@ export default class kraken extends Exchange {
1943
1952
  * @method
1944
1953
  * @name kraken#editOrder
1945
1954
  * @description edit a trade order
1946
- * @see https://docs.kraken.com/rest/#tag/Spot-Trading/operation/editOrder
1955
+ * @see https://docs.kraken.com/api/docs/rest-api/amend-order
1947
1956
  * @param {string} id order id
1948
1957
  * @param {string} symbol unified symbol of the market to create an order in
1949
1958
  * @param {string} type 'market' or 'limit'
1950
1959
  * @param {string} side 'buy' or 'sell'
1951
- * @param {float} amount how much of the currency you want to trade in units of the base currency
1960
+ * @param {float} [amount] how much of the currency you want to trade in units of the base currency
1952
1961
  * @param {float} [price] the price at which the order is to be fulfilled, in units of the quote currency, ignored in market orders
1953
1962
  * @param {object} [params] extra parameters specific to the exchange API endpoint
1954
- * @param {float} [params.stopLossPrice] *margin only* the price that a stop loss order is triggered at
1955
- * @param {float} [params.takeProfitPrice] *margin only* the price that a take profit order is triggered at
1956
- * @param {string} [params.trailingAmount] *margin only* the quote price away from the current market price
1957
- * @param {string} [params.trailingLimitAmount] *margin only* the quote amount away from the trailingAmount
1958
- * @param {string} [params.offset] *margin only* '+' or '-' whether you want the trailingLimitAmount value to be positive or negative, default is negative '-'
1959
- * @param {string} [params.trigger] *margin only* the activation price type, 'last' or 'index', default is 'last'
1963
+ * @param {float} [params.stopLossPrice] the price that a stop loss order is triggered at
1964
+ * @param {float} [params.takeProfitPrice] the price that a take profit order is triggered at
1965
+ * @param {string} [params.trailingAmount] the quote amount to trail away from the current market price
1966
+ * @param {string} [params.trailingPercent] the percent to trail away from the current market price
1967
+ * @param {string} [params.trailingLimitAmount] the quote amount away from the trailingAmount
1968
+ * @param {string} [params.trailingLimitPercent] the percent away from the trailingAmount
1969
+ * @param {string} [params.offset] '+' or '-' whether you want the trailingLimitAmount value to be positive or negative
1970
+ * @param {boolean} [params.postOnly] if true, the order will only be posted to the order book and not executed immediately
1971
+ * @param {string} [params.clientOrderId] the orders client order id
1960
1972
  * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
1961
1973
  */
1962
1974
  async editOrder(id, symbol, type, side, amount = undefined, price = undefined, params = {}) {
@@ -1965,33 +1977,50 @@ export default class kraken extends Exchange {
1965
1977
  if (!market['spot']) {
1966
1978
  throw new NotSupported(this.id + ' editOrder() does not support ' + market['type'] + ' orders, only spot orders are accepted');
1967
1979
  }
1968
- const request = {
1980
+ let request = {
1969
1981
  'txid': id,
1970
- 'pair': market['id'],
1971
1982
  };
1983
+ const clientOrderId = this.safeString(params, 'clientOrderId');
1984
+ if (clientOrderId !== undefined) {
1985
+ request['cl_ord_id'] = clientOrderId;
1986
+ params = this.omit(params, 'clientOrderId');
1987
+ request = this.omit(request, 'txid');
1988
+ }
1989
+ const isMarket = (type === 'market');
1990
+ let postOnly = undefined;
1991
+ [postOnly, params] = this.handlePostOnly(isMarket, false, params);
1992
+ if (postOnly) {
1993
+ request['post_only'] = 'true'; // not using boolean in this case, because the urlencodedNested transforms it into 'True' string
1994
+ }
1972
1995
  if (amount !== undefined) {
1973
- request['volume'] = this.amountToPrecision(symbol, amount);
1996
+ request['order_qty'] = this.amountToPrecision(symbol, amount);
1997
+ }
1998
+ if (price !== undefined) {
1999
+ request['limit_price'] = this.priceToPrecision(symbol, price);
2000
+ }
2001
+ let allTriggerPrices = this.safeStringN(params, ['stopLossPrice', 'takeProfitPrice', 'trailingAmount', 'trailingPercent', 'trailingLimitAmount', 'trailingLimitPercent']);
2002
+ if (allTriggerPrices !== undefined) {
2003
+ const offset = this.safeString(params, 'offset');
2004
+ params = this.omit(params, ['stopLossPrice', 'takeProfitPrice', 'trailingAmount', 'trailingPercent', 'trailingLimitAmount', 'trailingLimitPercent', 'offset']);
2005
+ if (offset !== undefined) {
2006
+ allTriggerPrices = offset + allTriggerPrices;
2007
+ request['trigger_price'] = allTriggerPrices;
2008
+ }
2009
+ else {
2010
+ request['trigger_price'] = this.priceToPrecision(symbol, allTriggerPrices);
2011
+ }
1974
2012
  }
1975
- const orderRequest = this.orderRequest('editOrder', symbol, type, request, amount, price, params);
1976
- const response = await this.privatePostEditOrder(this.extend(orderRequest[0], orderRequest[1]));
2013
+ const response = await this.privatePostAmendOrder(this.extend(request, params));
1977
2014
  //
1978
2015
  // {
1979
2016
  // "error": [],
1980
2017
  // "result": {
1981
- // "status": "ok",
1982
- // "txid": "OAW2BO-7RWEK-PZY5UO",
1983
- // "originaltxid": "OXL6SS-UPNMC-26WBE7",
1984
- // "volume": "0.00075000",
1985
- // "price": "13500.0",
1986
- // "orders_cancelled": 1,
1987
- // "descr": {
1988
- // "order": "buy 0.00075000 XBTUSDT @ limit 13500.0"
1989
- // }
2018
+ // "amend_id": "TJSMEH-AA67V-YUSQ6O"
1990
2019
  // }
1991
2020
  // }
1992
2021
  //
1993
- const data = this.safeDict(response, 'result', {});
1994
- return this.parseOrder(data, market);
2022
+ const result = this.safeDict(response, 'result', {});
2023
+ return this.parseOrder(result, market);
1995
2024
  }
1996
2025
  /**
1997
2026
  * @method
@@ -3207,28 +3236,6 @@ export default class kraken extends Exchange {
3207
3236
  if (code === 520) {
3208
3237
  throw new ExchangeNotAvailable(this.id + ' ' + code.toString() + ' ' + reason);
3209
3238
  }
3210
- // todo: rewrite this for "broad" exceptions matching
3211
- if (body.indexOf('Invalid order') >= 0) {
3212
- throw new InvalidOrder(this.id + ' ' + body);
3213
- }
3214
- if (body.indexOf('Invalid nonce') >= 0) {
3215
- throw new InvalidNonce(this.id + ' ' + body);
3216
- }
3217
- if (body.indexOf('Insufficient funds') >= 0) {
3218
- throw new InsufficientFunds(this.id + ' ' + body);
3219
- }
3220
- if (body.indexOf('Cancel pending') >= 0) {
3221
- throw new CancelPending(this.id + ' ' + body);
3222
- }
3223
- if (body.indexOf('Invalid arguments:volume') >= 0) {
3224
- throw new InvalidOrder(this.id + ' ' + body);
3225
- }
3226
- if (body.indexOf('Invalid arguments:viqc') >= 0) {
3227
- throw new InvalidOrder(this.id + ' ' + body);
3228
- }
3229
- if (body.indexOf('Rate limit exceeded') >= 0) {
3230
- throw new RateLimitExceeded(this.id + ' ' + body);
3231
- }
3232
3239
  if (response === undefined) {
3233
3240
  return undefined;
3234
3241
  }
@@ -3240,7 +3247,8 @@ export default class kraken extends Exchange {
3240
3247
  const message = this.id + ' ' + body;
3241
3248
  for (let i = 0; i < response['error'].length; i++) {
3242
3249
  const error = response['error'][i];
3243
- this.throwExactlyMatchedException(this.exceptions, error, message);
3250
+ this.throwExactlyMatchedException(this.exceptions['exact'], error, message);
3251
+ this.throwExactlyMatchedException(this.exceptions['broad'], error, message);
3244
3252
  }
3245
3253
  throw new ExchangeError(message);
3246
3254
  }
package/js/src/kucoin.js CHANGED
@@ -1186,7 +1186,7 @@ export default class kucoin extends Exchange {
1186
1186
  'type': 'spot',
1187
1187
  'spot': true,
1188
1188
  'margin': isMarginable,
1189
- 'marginMode': {
1189
+ 'marginModes': {
1190
1190
  'cross': hasCrossMargin,
1191
1191
  'isolated': hasIsolatedMargin,
1192
1192
  },
package/js/src/okx.js CHANGED
@@ -328,6 +328,7 @@ export default class okx extends Exchange {
328
328
  'asset/convert/history': 5 / 3,
329
329
  'asset/monthly-statement': 2,
330
330
  // account
331
+ 'account/instruments': 1,
331
332
  'account/balance': 2,
332
333
  'account/positions': 2,
333
334
  'account/positions-history': 100,