ccxt 4.5.3 → 4.5.4

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 (44) hide show
  1. package/README.md +4 -4
  2. package/dist/ccxt.browser.min.js +2 -2
  3. package/dist/cjs/ccxt.js +1 -1
  4. package/dist/cjs/src/base/Exchange.js +67 -5
  5. package/dist/cjs/src/base/functions/encode.js +8 -0
  6. package/dist/cjs/src/base/functions/rsa.js +14 -1
  7. package/dist/cjs/src/base/functions.js +1 -0
  8. package/dist/cjs/src/binance.js +7 -4
  9. package/dist/cjs/src/bitvavo.js +8 -0
  10. package/dist/cjs/src/bybit.js +20 -6
  11. package/dist/cjs/src/coinbase.js +28 -10
  12. package/dist/cjs/src/coincatch.js +32 -19
  13. package/dist/cjs/src/delta.js +1 -0
  14. package/dist/cjs/src/kucoinfutures.js +3 -2
  15. package/dist/cjs/src/okx.js +2 -1
  16. package/dist/cjs/src/pro/bitget.js +111 -14
  17. package/dist/cjs/src/pro/bybit.js +64 -8
  18. package/dist/cjs/src/pro/coinex.js +10 -11
  19. package/js/ccxt.d.ts +1 -1
  20. package/js/ccxt.js +1 -1
  21. package/js/src/abstract/myokx.d.ts +1 -0
  22. package/js/src/abstract/okx.d.ts +1 -0
  23. package/js/src/abstract/okxus.d.ts +1 -0
  24. package/js/src/base/Exchange.d.ts +4 -0
  25. package/js/src/base/Exchange.js +67 -5
  26. package/js/src/base/functions/encode.d.ts +2 -1
  27. package/js/src/base/functions/encode.js +8 -1
  28. package/js/src/base/functions/rsa.js +16 -3
  29. package/js/src/binance.js +7 -4
  30. package/js/src/bitvavo.js +8 -0
  31. package/js/src/bybit.js +20 -6
  32. package/js/src/coinbase.d.ts +1 -1
  33. package/js/src/coinbase.js +28 -10
  34. package/js/src/coincatch.d.ts +2 -0
  35. package/js/src/coincatch.js +32 -19
  36. package/js/src/delta.js +1 -0
  37. package/js/src/kucoinfutures.js +3 -2
  38. package/js/src/okx.js +2 -1
  39. package/js/src/pro/bitget.d.ts +3 -1
  40. package/js/src/pro/bitget.js +111 -14
  41. package/js/src/pro/bybit.d.ts +4 -0
  42. package/js/src/pro/bybit.js +64 -8
  43. package/js/src/pro/coinex.js +11 -12
  44. package/package.json +3 -3
package/dist/cjs/ccxt.js CHANGED
@@ -192,7 +192,7 @@ var xt$1 = require('./src/pro/xt.js');
192
192
 
193
193
  //-----------------------------------------------------------------------------
194
194
  // this is updated by vss.js when building
195
- const version = '4.5.3';
195
+ const version = '4.5.4';
196
196
  Exchange["default"].ccxtVersion = version;
197
197
  const exchanges = {
198
198
  'alpaca': alpaca["default"],
@@ -2448,9 +2448,9 @@ class Exchange {
2448
2448
  parseToNumeric(number) {
2449
2449
  const stringVersion = this.numberToString(number); // this will convert 1.0 and 1 to "1" and 1.1 to "1.1"
2450
2450
  // keep this in mind:
2451
- // in JS: 1 == 1.0 is true; 1 === 1.0 is true
2451
+ // in JS: 1 === 1.0 is true
2452
2452
  // in Python: 1 == 1.0 is true
2453
- // in PHP 1 == 1.0 is true, but 1 === 1.0 is false.
2453
+ // in PHP: 1 == 1.0 is true, but 1 === 1.0 is false.
2454
2454
  if (stringVersion.indexOf('.') >= 0) {
2455
2455
  return parseFloat(stringVersion);
2456
2456
  }
@@ -2965,6 +2965,26 @@ class Exchange {
2965
2965
  this.codes = Object.keys(currenciesSortedByCode);
2966
2966
  return this.markets;
2967
2967
  }
2968
+ setMarketsFromExchange(sourceExchange) {
2969
+ // Validate that both exchanges are of the same type
2970
+ if (this.id !== sourceExchange.id) {
2971
+ throw new errors.ArgumentsRequired(this.id + ' shareMarkets() can only share markets with exchanges of the same type (got ' + sourceExchange['id'] + ')');
2972
+ }
2973
+ // Validate that source exchange has loaded markets
2974
+ if (!sourceExchange.markets) {
2975
+ throw new errors.ExchangeError('setMarketsFromExchange() source exchange must have loaded markets first. Can call by using loadMarkets function');
2976
+ }
2977
+ // Set all market-related data
2978
+ this.markets = sourceExchange.markets;
2979
+ this.markets_by_id = sourceExchange.markets_by_id;
2980
+ this.symbols = sourceExchange.symbols;
2981
+ this.ids = sourceExchange.ids;
2982
+ this.currencies = sourceExchange.currencies;
2983
+ this.baseCurrencies = sourceExchange.baseCurrencies;
2984
+ this.quoteCurrencies = sourceExchange.quoteCurrencies;
2985
+ this.codes = sourceExchange.codes;
2986
+ return this;
2987
+ }
2968
2988
  getDescribeForExtendedWsExchange(currentRestInstance, parentRestInstance, wsBaseDescribe) {
2969
2989
  const extendedRestDescribe = this.deepExtend(parentRestInstance.describe(), currentRestInstance.describe());
2970
2990
  const superWithRestDescribe = this.deepExtend(extendedRestDescribe, wsBaseDescribe);
@@ -4243,17 +4263,30 @@ class Exchange {
4243
4263
  }
4244
4264
  return result;
4245
4265
  }
4246
- parseTrades(trades, market = undefined, since = undefined, limit = undefined, params = {}) {
4266
+ parseTradesHelper(isWs, trades, market = undefined, since = undefined, limit = undefined, params = {}) {
4247
4267
  trades = this.toArray(trades);
4248
4268
  let result = [];
4249
4269
  for (let i = 0; i < trades.length; i++) {
4250
- const trade = this.extend(this.parseTrade(trades[i], market), params);
4270
+ let parsed = undefined;
4271
+ if (isWs) {
4272
+ parsed = this.parseWsTrade(trades[i], market);
4273
+ }
4274
+ else {
4275
+ parsed = this.parseTrade(trades[i], market);
4276
+ }
4277
+ const trade = this.extend(parsed, params);
4251
4278
  result.push(trade);
4252
4279
  }
4253
4280
  result = this.sortBy2(result, 'timestamp', 'id');
4254
4281
  const symbol = (market !== undefined) ? market['symbol'] : undefined;
4255
4282
  return this.filterBySymbolSinceLimit(result, symbol, since, limit);
4256
4283
  }
4284
+ parseTrades(trades, market = undefined, since = undefined, limit = undefined, params = {}) {
4285
+ return this.parseTradesHelper(false, trades, market, since, limit, params);
4286
+ }
4287
+ parseWsTrades(trades, market = undefined, since = undefined, limit = undefined, params = {}) {
4288
+ return this.parseTradesHelper(true, trades, market, since, limit, params);
4289
+ }
4257
4290
  parseTransactions(transactions, currency = undefined, since = undefined, limit = undefined, params = {}) {
4258
4291
  transactions = this.toArray(transactions);
4259
4292
  let result = [];
@@ -6209,6 +6242,35 @@ class Exchange {
6209
6242
  const symbol = (market === undefined) ? undefined : market['symbol'];
6210
6243
  return this.filterBySymbolSinceLimit(sorted, symbol, since, limit);
6211
6244
  }
6245
+ handleTriggerPricesAndParams(symbol, params, omitParams = true) {
6246
+ //
6247
+ const triggerPrice = this.safeString2(params, 'triggerPrice', 'stopPrice');
6248
+ let triggerPriceStr = undefined;
6249
+ const stopLossPrice = this.safeString(params, 'stopLossPrice');
6250
+ let stopLossPriceStr = undefined;
6251
+ const takeProfitPrice = this.safeString(params, 'takeProfitPrice');
6252
+ let takeProfitPriceStr = undefined;
6253
+ //
6254
+ if (triggerPrice !== undefined) {
6255
+ if (omitParams) {
6256
+ params = this.omit(params, ['triggerPrice', 'stopPrice']);
6257
+ }
6258
+ triggerPriceStr = this.priceToPrecision(symbol, parseFloat(triggerPrice));
6259
+ }
6260
+ if (stopLossPrice !== undefined) {
6261
+ if (omitParams) {
6262
+ params = this.omit(params, 'stopLossPrice');
6263
+ }
6264
+ stopLossPriceStr = this.priceToPrecision(symbol, parseFloat(stopLossPrice));
6265
+ }
6266
+ if (takeProfitPrice !== undefined) {
6267
+ if (omitParams) {
6268
+ params = this.omit(params, 'takeProfitPrice');
6269
+ }
6270
+ takeProfitPriceStr = this.priceToPrecision(symbol, parseFloat(takeProfitPrice));
6271
+ }
6272
+ return [triggerPriceStr, stopLossPriceStr, takeProfitPriceStr, params];
6273
+ }
6212
6274
  handleTriggerDirectionAndParams(params, exchangeSpecificKey = undefined, allowEmpty = false) {
6213
6275
  /**
6214
6276
  * @ignore
@@ -7405,7 +7467,7 @@ class Exchange {
7405
7467
  const clients = Object.values(this.clients);
7406
7468
  for (let i = 0; i < clients.length; i++) {
7407
7469
  const client = clients[i];
7408
- const futures = this.safeDict(client, 'futures');
7470
+ const futures = client.futures;
7409
7471
  if ((futures !== undefined) && ('fetchPositionsSnapshot' in futures)) {
7410
7472
  delete futures['fetchPositionsSnapshot'];
7411
7473
  }
@@ -24,10 +24,18 @@ const json = (data, params = undefined) => JSON.stringify(data), isJsonEncodedOb
24
24
  function packb(req) {
25
25
  return msgpack.serialize(req);
26
26
  }
27
+ function base64ToBase64Url(base64, stripPadding = true) {
28
+ let base64url = base64.replace(/\+/g, "-").replace(/\//g, "_");
29
+ if (stripPadding) {
30
+ base64url = base64url.replace(/=+$/, "");
31
+ }
32
+ return base64url;
33
+ }
27
34
  /* ------------------------------------------------------------------------ */
28
35
 
29
36
  exports.base16ToBinary = base16ToBinary;
30
37
  exports.base58ToBinary = base58ToBinary;
38
+ exports.base64ToBase64Url = base64ToBase64Url;
31
39
  exports.base64ToBinary = base64ToBinary;
32
40
  exports.base64ToString = base64ToString;
33
41
  exports.binaryConcat = binaryConcat;
@@ -7,6 +7,7 @@ var index = require('../../static_dependencies/scure-base/index.js');
7
7
  var encode = require('./encode.js');
8
8
  var crypto = require('./crypto.js');
9
9
  var p256 = require('../../static_dependencies/noble-curves/p256.js');
10
+ var ed25519 = require('../../static_dependencies/noble-curves/ed25519.js');
10
11
 
11
12
  // ----------------------------------------------------------------------------
12
13
  function rsa(request, secret, hash) {
@@ -28,7 +29,7 @@ function jwt(request, secret, hash, isRSA = false, opts = {}) {
28
29
  }
29
30
  const encodedHeader = encode.urlencodeBase64(JSON.stringify(header));
30
31
  const encodedData = encode.urlencodeBase64(JSON.stringify(request));
31
- const token = [encodedHeader, encodedData].join('.');
32
+ let token = [encodedHeader, encodedData].join('.');
32
33
  const algoType = alg.slice(0, 2);
33
34
  let signature = undefined;
34
35
  if (algoType === 'HS') {
@@ -43,8 +44,20 @@ function jwt(request, secret, hash, isRSA = false, opts = {}) {
43
44
  const s = signedHash.s.padStart(64, '0');
44
45
  signature = encode.urlencodeBase64(encode.base16ToBinary(r + s));
45
46
  }
47
+ else if (algoType === 'ED') {
48
+ const base64str = crypto.eddsa(toHex(token), secret, ed25519.ed25519);
49
+ // we need urlencoded64 not base64
50
+ signature = encode.base64ToBase64Url(base64str);
51
+ }
46
52
  return [token, signature].join('.');
47
53
  }
54
+ function toHex(str) {
55
+ var result = '';
56
+ for (var i = 0; i < str.length; i++) {
57
+ result += str.charCodeAt(i).toString(16);
58
+ }
59
+ return result;
60
+ }
48
61
 
49
62
  exports.jwt = jwt;
50
63
  exports.rsa = rsa;
@@ -105,6 +105,7 @@ exports.truncate = number.truncate;
105
105
  exports.truncate_to_string = number.truncate_to_string;
106
106
  exports.base16ToBinary = encode.base16ToBinary;
107
107
  exports.base58ToBinary = encode.base58ToBinary;
108
+ exports.base64ToBase64Url = encode.base64ToBase64Url;
108
109
  exports.base64ToBinary = encode.base64ToBinary;
109
110
  exports.base64ToString = encode.base64ToString;
110
111
  exports.binaryConcat = encode.binaryConcat;
@@ -11403,11 +11403,14 @@ class binance extends binance$1["default"] {
11403
11403
  * @returns {object} response from the exchange
11404
11404
  */
11405
11405
  async setPositionMode(hedged, symbol = undefined, params = {}) {
11406
- const defaultType = this.safeString(this.options, 'defaultType', 'future');
11407
- const type = this.safeString(params, 'type', defaultType);
11408
- params = this.omit(params, ['type']);
11406
+ let market = undefined;
11407
+ if (symbol !== undefined) {
11408
+ market = this.market(symbol);
11409
+ }
11410
+ let type = undefined;
11411
+ [type, params] = this.handleMarketTypeAndParams('setPositionMode', market, params);
11409
11412
  let subType = undefined;
11410
- [subType, params] = this.handleSubTypeAndParams('setPositionMode', undefined, params);
11413
+ [subType, params] = this.handleSubTypeAndParams('setPositionMode', market, params);
11411
11414
  let isPortfolioMargin = undefined;
11412
11415
  [isPortfolioMargin, params] = this.handleOptionAndParams2(params, 'setPositionMode', 'papi', 'portfolioMargin', false);
11413
11416
  let dualSidePosition = undefined;
@@ -1423,6 +1423,14 @@ class bitvavo extends bitvavo$1["default"] {
1423
1423
  market = this.market(symbol);
1424
1424
  request['market'] = market['id'];
1425
1425
  }
1426
+ let operatorId = undefined;
1427
+ [operatorId, params] = this.handleOptionAndParams(params, 'cancelAllOrders', 'operatorId');
1428
+ if (operatorId !== undefined) {
1429
+ request['operatorId'] = this.parseToInt(operatorId);
1430
+ }
1431
+ else {
1432
+ throw new errors.ArgumentsRequired(this.id + ' canceAllOrders() requires an operatorId in params or options, eg: exchange.options[\'operatorId\'] = 1234567890');
1433
+ }
1426
1434
  const response = await this.privateDeleteOrders(this.extend(request, params));
1427
1435
  //
1428
1436
  // [
@@ -2996,17 +2996,31 @@ class bybit extends bybit$1["default"] {
2996
2996
  // "tradeId": "0e94eaf5-b08e-5505-b43f-7f1f30b1ca80"
2997
2997
  // }
2998
2998
  //
2999
+ // watchMyTrades execution.fast
3000
+ //
3001
+ // {
3002
+ // "category": "linear",
3003
+ // "symbol": "ICPUSDT",
3004
+ // "execId": "3510f361-0add-5c7b-a2e7-9679810944fc",
3005
+ // "execPrice": "12.015",
3006
+ // "execQty": "3000",
3007
+ // "orderId": "443d63fa-b4c3-4297-b7b1-23bca88b04dc",
3008
+ // "isMaker": false,
3009
+ // "orderLinkId": "test-00001",
3010
+ // "side": "Sell",
3011
+ // "execTime": "1716800399334",
3012
+ // "seq": 34771365464
3013
+ // }
3014
+ //
2999
3015
  const id = this.safeStringN(trade, ['execId', 'id', 'tradeId']);
3000
3016
  const marketId = this.safeString(trade, 'symbol');
3001
3017
  let marketType = ('createType' in trade) ? 'contract' : 'spot';
3002
- if (market !== undefined) {
3003
- marketType = market['type'];
3004
- }
3005
3018
  const category = this.safeString(trade, 'category');
3006
3019
  if (category !== undefined) {
3007
- if (category === 'spot') {
3008
- marketType = 'spot';
3009
- }
3020
+ marketType = (category === 'spot') ? 'spot' : 'contract';
3021
+ }
3022
+ if (market !== undefined) {
3023
+ marketType = market['type'];
3010
3024
  }
3011
3025
  market = this.safeMarket(marketId, market, undefined, marketType);
3012
3026
  const symbol = market['symbol'];
@@ -5014,8 +5014,9 @@ class coinbase extends coinbase$1["default"] {
5014
5014
  }
5015
5015
  return parsedPositions;
5016
5016
  }
5017
- createAuthToken(seconds, method = undefined, url = undefined) {
5018
- // it may not work for v2
5017
+ createAuthToken(seconds, method = undefined, url = undefined, useEddsa = false) {
5018
+ // v1 https://docs.cdp.coinbase.com/api-reference/authentication#php-2
5019
+ // v2 https://docs.cdp.coinbase.com/api-reference/v2/authentication
5019
5020
  let uri = undefined;
5020
5021
  if (url !== undefined) {
5021
5022
  uri = method + ' ' + url.replace('https://', '');
@@ -5026,20 +5027,35 @@ class coinbase extends coinbase$1["default"] {
5026
5027
  uri = uri.slice(0, quesPos);
5027
5028
  }
5028
5029
  }
5030
+ // eddsa {"sub":"d2efa49a-369c-43d7-a60e-ae26e28853c2","iss":"cdp","aud":["cdp_service"],"uris":["GET api.coinbase.com/api/v3/brokerage/transaction_summary"]}
5029
5031
  const nonce = this.randomBytes(16);
5032
+ const aud = useEddsa ? 'cdp_service' : 'retail_rest_api_proxy';
5033
+ const iss = useEddsa ? 'cdp' : 'coinbase-cloud';
5030
5034
  const request = {
5031
- 'aud': ['retail_rest_api_proxy'],
5032
- 'iss': 'coinbase-cloud',
5035
+ 'aud': [aud],
5036
+ 'iss': iss,
5033
5037
  'nbf': seconds,
5034
5038
  'exp': seconds + 120,
5035
5039
  'sub': this.apiKey,
5036
5040
  'iat': seconds,
5037
5041
  };
5038
5042
  if (uri !== undefined) {
5039
- request['uri'] = uri;
5043
+ if (!useEddsa) {
5044
+ request['uri'] = uri;
5045
+ }
5046
+ else {
5047
+ request['uris'] = [uri];
5048
+ }
5049
+ }
5050
+ if (useEddsa) {
5051
+ const byteArray = this.base64ToBinary(this.secret);
5052
+ const seed = this.arraySlice(byteArray, 0, 32);
5053
+ return rsa.jwt(request, seed, sha256.sha256, false, { 'kid': this.apiKey, 'nonce': nonce, 'alg': 'EdDSA' });
5054
+ }
5055
+ else {
5056
+ // ecdsa with p256
5057
+ return rsa.jwt(request, this.encode(this.secret), sha256.sha256, false, { 'kid': this.apiKey, 'nonce': nonce, 'alg': 'ES256' });
5040
5058
  }
5041
- const token = rsa.jwt(request, this.encode(this.secret), sha256.sha256, false, { 'kid': this.apiKey, 'nonce': nonce, 'alg': 'ES256' });
5042
- return token;
5043
5059
  }
5044
5060
  nonce() {
5045
5061
  return this.milliseconds() - this.options['timeDifference'];
@@ -5089,8 +5105,10 @@ class coinbase extends coinbase$1["default"] {
5089
5105
  // v2: 'GET' require payload in the signature
5090
5106
  // https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-key-authentication
5091
5107
  const isCloudAPiKey = (this.apiKey.indexOf('organizations/') >= 0) || (this.secret.startsWith('-----BEGIN'));
5092
- if (isCloudAPiKey) {
5093
- if (this.apiKey.startsWith('-----BEGIN')) {
5108
+ // using the size might be fragile, so we add an option to force v2 cloud api key if needed
5109
+ const isV2CloudAPiKey = this.secret.length === 88 || this.safeBool(this.options, 'v2CloudAPiKey', false) || this.secret.endsWith('=');
5110
+ if (isCloudAPiKey || isV2CloudAPiKey) {
5111
+ if (isCloudAPiKey && this.apiKey.startsWith('-----BEGIN')) {
5094
5112
  throw new errors.ArgumentsRequired(this.id + ' apiKey should contain the name (eg: organizations/3b910e93....) and not the public key');
5095
5113
  }
5096
5114
  // // it may not work for v2
@@ -5111,7 +5129,7 @@ class coinbase extends coinbase$1["default"] {
5111
5129
  // 'uri': uri,
5112
5130
  // 'iat': seconds,
5113
5131
  // };
5114
- const token = this.createAuthToken(seconds, method, url);
5132
+ const token = this.createAuthToken(seconds, method, url, isV2CloudAPiKey);
5115
5133
  // const token = jwt (request, this.encode (this.secret), sha256, false, { 'kid': this.apiKey, 'nonce': nonce, 'alg': 'ES256' });
5116
5134
  authorizationString = 'Bearer ' + token;
5117
5135
  }
@@ -2306,6 +2306,7 @@ class coincatch extends coincatch$1["default"] {
2306
2306
  * @param {float} amount how much of you want to trade in units of the base currency
2307
2307
  * @param {float} [price] the price that the order is to be fulfilled, in units of the quote currency, ignored in market orders
2308
2308
  * @param {object} [params] extra parameters specific to the exchange API endpoint
2309
+ * @param {bool} [params.hedged] *swap markets only* must be set to true if position mode is hedged (default false)
2309
2310
  * @param {float} [params.cost] *spot market buy only* the quote quantity that can be used as an alternative for the amount
2310
2311
  * @param {float} [params.triggerPrice] the price that the order is to be triggered
2311
2312
  * @param {bool} [params.postOnly] if true, the order will only be posted to the order book and not executed immediately
@@ -2508,6 +2509,7 @@ class coincatch extends coincatch$1["default"] {
2508
2509
  * @param {float} amount how much of you want to trade in units of the base currency
2509
2510
  * @param {float} [price] the price that the order is to be fulfilled, in units of the quote currency, ignored in market orders
2510
2511
  * @param {object} [params] extra parameters specific to the exchange API endpoint
2512
+ * @param {bool} [params.hedged] must be set to true if position mode is hedged (default false)
2511
2513
  * @param {bool} [params.postOnly] *non-trigger orders only* if true, the order will only be posted to the order book and not executed immediately
2512
2514
  * @param {bool} [params.reduceOnly] true or false whether the order is reduce only
2513
2515
  * @param {string} [params.timeInForce] *non-trigger orders only* 'GTC', 'FOK', 'IOC' or 'PO'
@@ -2565,7 +2567,7 @@ class coincatch extends coincatch$1["default"] {
2565
2567
  * @param {float} amount how much of you want to trade in units of the base currency
2566
2568
  * @param {float} [price] the price that the order is to be fulfilled, in units of the quote currency, ignored in market orders
2567
2569
  * @param {object} [params] extra parameters specific to the exchange API endpoint
2568
- * @param {bool} [params.hedged] default false
2570
+ * @param {bool} [params.hedged] must be set to true if position mode is hedged (default false)
2569
2571
  * @param {bool} [params.postOnly] *non-trigger orders only* if true, the order will only be posted to the order book and not executed immediately
2570
2572
  * @param {bool} [params.reduceOnly] true or false whether the order is reduce only
2571
2573
  * @param {string} [params.timeInForce] *non-trigger orders only* 'GTC', 'FOK', 'IOC' or 'PO'
@@ -2604,31 +2606,42 @@ class coincatch extends coincatch$1["default"] {
2604
2606
  }
2605
2607
  if ((endpointType !== 'tpsl')) {
2606
2608
  request['orderType'] = type;
2609
+ let sideIsExchangeSpecific = false;
2607
2610
  let hedged = false;
2608
- [hedged, params] = this.handleOptionAndParams(params, methodName, 'hedged', hedged);
2609
- // hedged and non-hedged orders have different side values and reduceOnly handling
2610
- let reduceOnly = false;
2611
- [reduceOnly, params] = this.handleParamBool(params, 'reduceOnly', reduceOnly);
2612
- if (hedged) {
2613
- if (reduceOnly) {
2614
- if (side === 'buy') {
2615
- side = 'close_short';
2611
+ if ((side === 'buy_single') || (side === 'sell_single') || (side === 'open_long') || (side === 'open_short') || (side === 'close_long') || (side === 'close_short')) {
2612
+ sideIsExchangeSpecific = true;
2613
+ if ((side !== 'buy_single') && (side !== 'sell_single')) {
2614
+ hedged = true;
2615
+ }
2616
+ }
2617
+ if (!sideIsExchangeSpecific) {
2618
+ [hedged, params] = this.handleOptionAndParams(params, methodName, 'hedged', hedged);
2619
+ // hedged and non-hedged orders have different side values and reduceOnly handling
2620
+ const reduceOnly = this.safeBool(params, 'reduceOnly');
2621
+ if (hedged) {
2622
+ if ((reduceOnly !== undefined) && reduceOnly) {
2623
+ if (side === 'buy') {
2624
+ side = 'close_short';
2625
+ }
2626
+ else if (side === 'sell') {
2627
+ side = 'close_long';
2628
+ }
2616
2629
  }
2617
- else if (side === 'sell') {
2618
- side = 'close_long';
2630
+ else {
2631
+ if (side === 'buy') {
2632
+ side = 'open_long';
2633
+ }
2634
+ else if (side === 'sell') {
2635
+ side = 'open_short';
2636
+ }
2619
2637
  }
2620
2638
  }
2621
2639
  else {
2622
- if (side === 'buy') {
2623
- side = 'open_long';
2624
- }
2625
- else if (side === 'sell') {
2626
- side = 'open_short';
2627
- }
2640
+ side = side.toLowerCase() + '_single';
2628
2641
  }
2629
2642
  }
2630
- else {
2631
- side = side.toLowerCase() + '_single';
2643
+ if (hedged) {
2644
+ params = this.omit(params, 'reduceOnly');
2632
2645
  }
2633
2646
  request['side'] = side;
2634
2647
  }
@@ -215,6 +215,7 @@ class delta extends delta$1["default"] {
215
215
  },
216
216
  },
217
217
  },
218
+ 'userAgent': this.userAgents['chrome39'],
218
219
  'options': {
219
220
  'networks': {
220
221
  'TRC20': 'TRC20(TRON)',
@@ -228,7 +228,7 @@ class kucoinfutures extends kucoinfutures$1["default"] {
228
228
  '429': errors.RateLimitExceeded,
229
229
  '500': errors.ExchangeNotAvailable,
230
230
  '503': errors.ExchangeNotAvailable,
231
- '100001': errors.InvalidOrder,
231
+ '100001': errors.OrderNotFound,
232
232
  '100004': errors.BadRequest,
233
233
  '101030': errors.PermissionDenied,
234
234
  '200004': errors.InsufficientFunds,
@@ -247,7 +247,8 @@ class kucoinfutures extends kucoinfutures$1["default"] {
247
247
  '400100': errors.BadRequest,
248
248
  '411100': errors.AccountSuspended,
249
249
  '500000': errors.ExchangeNotAvailable,
250
- '300009': errors.InvalidOrder, // {"msg":"No open positions to close.","code":"300009"}
250
+ '300009': errors.InvalidOrder,
251
+ '330008': errors.InsufficientFunds, // {"msg":"Your current margin and leverage have reached the maximum open limit. Please increase your margin or raise your leverage to open larger positions.","code":"330008"}
251
252
  },
252
253
  'broad': {
253
254
  'Position does not exist': errors.OrderNotFound, // { "code":"200000", "msg":"Position does not exist" }
@@ -213,6 +213,7 @@ class okx extends okx$1["default"] {
213
213
  'market/open-oracle': 50,
214
214
  'market/exchange-rate': 20,
215
215
  'market/index-components': 1,
216
+ 'public/market-data-history': 4,
216
217
  'public/economic-calendar': 50,
217
218
  'market/block-tickers': 1,
218
219
  'market/block-ticker': 1,
@@ -364,7 +365,7 @@ class okx extends okx$1["default"] {
364
365
  'account/fixed-loan/borrowing-limit': 4,
365
366
  'account/fixed-loan/borrowing-quote': 5,
366
367
  'account/fixed-loan/borrowing-orders-list': 5,
367
- 'account/spot-manual-borrow-repay': 10,
368
+ 'account/spot-manual-borrow-repay': 30,
368
369
  'account/set-auto-repay': 4,
369
370
  'account/spot-borrow-repay-history': 4,
370
371
  'account/move-positions-history': 10,