ccxt 4.5.45 → 4.5.47

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 (91) hide show
  1. package/README.md +5 -6
  2. package/dist/ccxt.browser.min.js +3 -3
  3. package/dist/cjs/ccxt.js +1 -6
  4. package/dist/cjs/src/aftermath.js +1 -1
  5. package/dist/cjs/src/backpack.js +1 -1
  6. package/dist/cjs/src/base/Exchange.js +27 -0
  7. package/dist/cjs/src/binance.js +23 -17
  8. package/dist/cjs/src/bitfinex.js +6 -11
  9. package/dist/cjs/src/bitget.js +9 -4
  10. package/dist/cjs/src/bitmart.js +144 -21
  11. package/dist/cjs/src/bitmex.js +46 -0
  12. package/dist/cjs/src/bitstamp.js +14 -1
  13. package/dist/cjs/src/bittrade.js +1 -1
  14. package/dist/cjs/src/blofin.js +137 -29
  15. package/dist/cjs/src/bybit.js +58 -56
  16. package/dist/cjs/src/bydfi.js +102 -100
  17. package/dist/cjs/src/gate.js +37 -2
  18. package/dist/cjs/src/hollaex.js +1 -1
  19. package/dist/cjs/src/kraken.js +39 -29
  20. package/dist/cjs/src/kucoin.js +2161 -462
  21. package/dist/cjs/src/lighter.js +2 -2
  22. package/dist/cjs/src/okx.js +75 -58
  23. package/dist/cjs/src/paradex.js +2 -6
  24. package/dist/cjs/src/pro/bittrade.js +4 -0
  25. package/dist/cjs/src/pro/bydfi.js +19 -19
  26. package/dist/cjs/src/pro/gate.js +79 -54
  27. package/dist/cjs/src/pro/grvt.js +6 -4
  28. package/dist/cjs/src/pro/htx.js +4 -4
  29. package/dist/cjs/src/pro/lighter.js +1 -1
  30. package/dist/cjs/src/pro/okx.js +1 -1
  31. package/dist/cjs/src/whitebit.js +21 -2
  32. package/index.d.cts +2 -0
  33. package/js/ccxt.d.ts +2 -8
  34. package/js/ccxt.js +2 -6
  35. package/js/src/abstract/bitmart.d.ts +7 -0
  36. package/js/src/abstract/blofin.d.ts +28 -12
  37. package/js/src/abstract/bydfi.d.ts +29 -29
  38. package/js/src/abstract/kraken.d.ts +36 -29
  39. package/js/src/abstract/kucoin.d.ts +2 -0
  40. package/js/src/abstract/kucoinfutures.d.ts +2 -0
  41. package/js/src/aftermath.js +1 -1
  42. package/js/src/backpack.js +1 -1
  43. package/js/src/base/Exchange.d.ts +2 -0
  44. package/js/src/base/Exchange.js +27 -0
  45. package/js/src/binance.js +23 -17
  46. package/js/src/bitfinex.js +6 -11
  47. package/js/src/bitget.d.ts +1 -1
  48. package/js/src/bitget.js +9 -4
  49. package/js/src/bitmart.d.ts +18 -4
  50. package/js/src/bitmart.js +144 -21
  51. package/js/src/bitmex.d.ts +12 -0
  52. package/js/src/bitmex.js +46 -0
  53. package/js/src/bitstamp.js +14 -1
  54. package/js/src/bittrade.js +1 -1
  55. package/js/src/blofin.d.ts +2 -0
  56. package/js/src/blofin.js +137 -29
  57. package/js/src/bybit.d.ts +1 -0
  58. package/js/src/bybit.js +58 -56
  59. package/js/src/bydfi.d.ts +31 -31
  60. package/js/src/bydfi.js +102 -100
  61. package/js/src/gate.js +37 -2
  62. package/js/src/hollaex.js +1 -1
  63. package/js/src/kraken.js +39 -29
  64. package/js/src/kucoin.d.ts +249 -8
  65. package/js/src/kucoin.js +2161 -462
  66. package/js/src/lighter.js +2 -2
  67. package/js/src/okx.d.ts +1 -0
  68. package/js/src/okx.js +75 -58
  69. package/js/src/paradex.d.ts +0 -1
  70. package/js/src/paradex.js +2 -6
  71. package/js/src/pro/bittrade.js +4 -0
  72. package/js/src/pro/bydfi.d.ts +18 -18
  73. package/js/src/pro/bydfi.js +19 -19
  74. package/js/src/pro/gate.d.ts +2 -2
  75. package/js/src/pro/gate.js +79 -54
  76. package/js/src/pro/grvt.js +6 -4
  77. package/js/src/pro/htx.js +4 -4
  78. package/js/src/pro/lighter.js +1 -1
  79. package/js/src/pro/okx.js +1 -1
  80. package/js/src/whitebit.d.ts +1 -1
  81. package/js/src/whitebit.js +21 -2
  82. package/package.json +2 -2
  83. package/dist/cjs/src/abstract/coincatch.js +0 -11
  84. package/dist/cjs/src/coincatch.js +0 -5495
  85. package/dist/cjs/src/pro/coincatch.js +0 -1563
  86. package/js/src/abstract/coincatch.d.ts +0 -97
  87. package/js/src/abstract/coincatch.js +0 -5
  88. package/js/src/coincatch.d.ts +0 -788
  89. package/js/src/coincatch.js +0 -5488
  90. package/js/src/pro/coincatch.d.ts +0 -207
  91. package/js/src/pro/coincatch.js +0 -1556
package/js/src/kucoin.js CHANGED
@@ -42,10 +42,13 @@ export default class kucoin extends Exchange {
42
42
  'createMarketSellOrderWithCost': true,
43
43
  'createOrder': true,
44
44
  'createOrders': true,
45
+ 'createOrderWithTakeProfitAndStopLoss': true,
45
46
  'createPostOnlyOrder': true,
46
47
  'createStopLimitOrder': true,
48
+ 'createStopLossOrder': true,
47
49
  'createStopMarketOrder': true,
48
50
  'createStopOrder': true,
51
+ 'createTakeProfitOrder': true,
49
52
  'createTriggerOrder': true,
50
53
  'editOrder': true,
51
54
  'fetchAccounts': true,
@@ -84,8 +87,9 @@ export default class kucoin extends Exchange {
84
87
  'fetchMarkPrices': true,
85
88
  'fetchMyTrades': true,
86
89
  'fetchOHLCV': true,
87
- 'fetchOpenInterest': false,
88
- 'fetchOpenInterestHistory': false,
90
+ 'fetchOpenInterest': true,
91
+ 'fetchOpenInterestHistory': true,
92
+ 'fetchOpenInterests': true,
89
93
  'fetchOpenOrders': true,
90
94
  'fetchOrder': true,
91
95
  'fetchOrderBook': true,
@@ -94,7 +98,7 @@ export default class kucoin extends Exchange {
94
98
  'fetchOrderTrades': true,
95
99
  'fetchPosition': true,
96
100
  'fetchPositionADLRank': true,
97
- 'fetchPositionHistory': false,
101
+ 'fetchPositionHistory': true,
98
102
  'fetchPositionMode': true,
99
103
  'fetchPositions': true,
100
104
  'fetchPositionsADLRank': true,
@@ -186,6 +190,7 @@ export default class kucoin extends Exchange {
186
190
  'get': {
187
191
  // account
188
192
  'user-info': 20,
193
+ 'user/api-key': 20,
189
194
  'accounts': 5,
190
195
  'accounts/{accountId}': 5,
191
196
  'accounts/ledgers': 2,
@@ -561,6 +566,7 @@ export default class kucoin extends Exchange {
561
566
  '{accountMode}/order/execution': 8,
562
567
  '{accountMode}/position/open-list': 6,
563
568
  '{accountMode}/position/history': 4,
569
+ 'position/history': 4,
564
570
  '{accountMode}/position/tiers': 40,
565
571
  'sub-account/balance': 10,
566
572
  'user/fee-rate': 6,
@@ -625,6 +631,7 @@ export default class kucoin extends Exchange {
625
631
  '503': ExchangeNotAvailable,
626
632
  '101030': PermissionDenied,
627
633
  '103000': InvalidOrder,
634
+ '112010': PermissionDenied,
628
635
  '130101': BadRequest,
629
636
  '130102': ExchangeError,
630
637
  '130103': OrderNotFound,
@@ -703,7 +710,7 @@ export default class kucoin extends Exchange {
703
710
  '400006': AuthenticationError,
704
711
  '400007': AuthenticationError,
705
712
  '400008': NotSupported,
706
- '400100': InsufficientFunds,
713
+ '400100': BadRequest,
707
714
  '400200': InvalidOrder,
708
715
  '400330': InvalidOrder,
709
716
  '400350': InvalidOrder,
@@ -735,6 +742,7 @@ export default class kucoin extends Exchange {
735
742
  '330008': 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"}
736
743
  },
737
744
  'broad': {
745
+ 'pageSize should not greater than 500': BadRequest,
738
746
  'Exceeded the access frequency': RateLimitExceeded,
739
747
  'require more permission': PermissionDenied,
740
748
  // futures errors
@@ -873,15 +881,14 @@ export default class kucoin extends Exchange {
873
881
  },
874
882
  'options': {
875
883
  'hf': undefined,
884
+ 'uta': undefined,
876
885
  'version': 'v1',
877
886
  'symbolSeparator': '-',
878
887
  'fetchMyTradesMethod': 'private_get_fills',
879
888
  'timeDifference': 0,
880
889
  'adjustForTimeDifference': false,
881
890
  'fetchCurrencies': {
882
- 'webApiEnable': true,
883
- 'webApiRetries': 1,
884
- 'webApiMuteFailure': true,
891
+ 'brokenCurrencies': ['00', 'OPEN_ERROR', 'HUF', 'BDT'], // skip buggy entries: https://t.me/KuCoin_API/217798
885
892
  },
886
893
  'fetchMarkets': {
887
894
  'types': ['spot', 'swap', 'future', 'contract'],
@@ -896,6 +903,13 @@ export default class kucoin extends Exchange {
896
903
  'fetchBalance': {
897
904
  'code': 'USDT', // for contract endpoint
898
905
  },
906
+ 'timeInForce': {
907
+ 'IOC': 'IOC',
908
+ 'FOK': 'FOK',
909
+ 'PO': 'PO',
910
+ 'GTD': 'GTT',
911
+ 'RPI': 'RPI',
912
+ },
899
913
  'timeframes': {
900
914
  'swap': {
901
915
  '1m': 1,
@@ -1059,12 +1073,32 @@ export default class kucoin extends Exchange {
1059
1073
  'mining': 'pool',
1060
1074
  'hf': 'trade_hf',
1061
1075
  'contract': 'contract',
1076
+ 'uta': 'unified',
1077
+ 'unified': 'unified',
1078
+ },
1079
+ 'utaAccountsByType': {
1080
+ 'trade': 'SPOT',
1081
+ 'spot': 'SPOT',
1082
+ 'margin': 'CROSS',
1083
+ 'cross': 'CROSS',
1084
+ 'isolated': 'ISOLATED',
1085
+ 'main': 'FUNDING',
1086
+ 'funding': 'FUNDING',
1087
+ 'future': 'FUTURES',
1088
+ 'swap': 'FUTURES',
1089
+ 'contract': 'FUTURES',
1090
+ 'uta': 'unified',
1091
+ 'unified': 'unified',
1062
1092
  },
1063
1093
  'networks': {
1094
+ 'BTC': 'btc',
1064
1095
  'BRC20': 'btc',
1065
1096
  'BTCNATIVESEGWIT': 'bech32',
1097
+ 'ETH': 'eth',
1066
1098
  'ERC20': 'eth',
1099
+ 'TRX': 'trx',
1067
1100
  'TRC20': 'trx',
1101
+ 'HECO': 'heco',
1068
1102
  'HRC20': 'heco',
1069
1103
  'MATIC': 'matic',
1070
1104
  'KCC': 'kcc',
@@ -1079,6 +1113,7 @@ export default class kucoin extends Exchange {
1079
1113
  'TLOS': 'tlos',
1080
1114
  'CFX': 'cfx',
1081
1115
  'ACA': 'aca',
1116
+ 'OP': 'optimism',
1082
1117
  'OPTIMISM': 'optimism',
1083
1118
  'ONT': 'ont',
1084
1119
  'GLMR': 'glmr',
@@ -1269,6 +1304,14 @@ export default class kucoin extends Exchange {
1269
1304
  // 'KLEVER': 'klv',
1270
1305
  // undetermined: xns(insolar), rhoc, luk (luniverse), kts (klimatas), bchn (bitcoin cash node), god (shallow entry), lit (litmus),
1271
1306
  },
1307
+ 'networksById': {
1308
+ 'btc': 'BTC',
1309
+ 'trx': 'TRC20',
1310
+ 'eth': 'ERC20',
1311
+ 'heco': 'HRC20',
1312
+ 'optimism': 'OP',
1313
+ 'op': 'OP',
1314
+ },
1272
1315
  'marginModes': {
1273
1316
  'cross': 'MARGIN_TRADE',
1274
1317
  'isolated': 'MARGIN_ISOLATED_TRADE',
@@ -1352,7 +1395,11 @@ export default class kucoin extends Exchange {
1352
1395
  'stopLossPrice': true,
1353
1396
  'takeProfitPrice': true,
1354
1397
  'attachedStopLossTakeProfit': {
1355
- 'triggerPriceType': undefined,
1398
+ 'triggerPriceType': {
1399
+ 'last': true,
1400
+ 'mark': true,
1401
+ 'index': true,
1402
+ },
1356
1403
  'price': true,
1357
1404
  },
1358
1405
  'timeInForce': {
@@ -1478,8 +1525,8 @@ export default class kucoin extends Exchange {
1478
1525
  * @returns {object} a [status structure]{@link https://docs.ccxt.com/?id=exchange-status-structure}
1479
1526
  */
1480
1527
  async fetchStatus(params = {}) {
1481
- let uta = undefined;
1482
- [uta, params] = this.handleOptionAndParams(params, 'fetchStatus', 'uta', false);
1528
+ let uta = false;
1529
+ [uta, params] = this.handleOptionAndParams(params, 'fetchStatus', 'uta', uta);
1483
1530
  let type = undefined;
1484
1531
  [type, params] = this.handleMarketTypeAndParams('fetchStatus', undefined, params);
1485
1532
  let response = undefined;
@@ -1550,8 +1597,8 @@ export default class kucoin extends Exchange {
1550
1597
  async fetchMarkets(params = {}) {
1551
1598
  let fetchTickersFees = undefined;
1552
1599
  [fetchTickersFees, params] = this.handleOptionAndParams(params, 'fetchMarkets', 'fetchTickersFees', true);
1553
- let uta = undefined;
1554
- [uta, params] = this.handleOptionAndParams(params, 'fetchMarkets', 'uta', false);
1600
+ let uta = false;
1601
+ [uta, params] = this.handleOptionAndParams(params, 'fetchMarkets', 'uta', uta);
1555
1602
  if (uta) {
1556
1603
  return await this.fetchUTAMarkets(params);
1557
1604
  }
@@ -2087,7 +2134,7 @@ export default class kucoin extends Exchange {
2087
2134
  'strike': undefined,
2088
2135
  'optionType': undefined,
2089
2136
  'precision': {
2090
- 'amount': this.safeNumber(market, 'lotSize'),
2137
+ 'amount': this.safeNumber2(market, 'lotSize', 'baseOrderStep'),
2091
2138
  'price': this.safeNumber(market, 'tickSize'),
2092
2139
  },
2093
2140
  'limits': {
@@ -2159,9 +2206,13 @@ export default class kucoin extends Exchange {
2159
2206
  */
2160
2207
  async fetchCurrencies(params = {}) {
2161
2208
  let uta = false;
2209
+ if (this.checkRequiredCredentials(false)) {
2210
+ uta = await this.isUTAEnabled();
2211
+ }
2162
2212
  [uta, params] = this.handleOptionAndParams(params, 'fetchCurrencies', 'uta', uta);
2163
2213
  let response = undefined;
2164
2214
  if (uta) {
2215
+ response = await this.utaGetAssetCurrencies(params);
2165
2216
  //
2166
2217
  // {
2167
2218
  // "code": "200000",
@@ -2196,7 +2247,6 @@ export default class kucoin extends Exchange {
2196
2247
  // ]
2197
2248
  // }
2198
2249
  //
2199
- response = await this.utaGetAssetCurrencies(params);
2200
2250
  }
2201
2251
  else {
2202
2252
  //
@@ -2239,64 +2289,61 @@ export default class kucoin extends Exchange {
2239
2289
  response = await this.publicGetCurrencies(params);
2240
2290
  }
2241
2291
  const currenciesData = this.safeList(response, 'data', []);
2242
- const brokenCurrencies = this.safeList(this.options, 'brokenCurrencies', ['00', 'OPEN_ERROR', 'HUF', 'BDT']);
2243
- const result = {};
2244
- for (let i = 0; i < currenciesData.length; i++) {
2245
- const entry = currenciesData[i];
2246
- const id = this.safeString(entry, 'currency');
2247
- if (this.inArray(id, brokenCurrencies)) {
2248
- continue; // skip buggy entries: https://t.me/KuCoin_API/217798
2249
- }
2250
- const code = this.safeCurrencyCode(id);
2251
- const networks = {};
2252
- const chains = this.safeList2(entry, 'chains', 'items', []);
2253
- const chainsLength = chains.length;
2254
- for (let j = 0; j < chainsLength; j++) {
2255
- const chain = chains[j];
2256
- const chainId = this.safeString(chain, 'chainId');
2257
- const networkCode = this.networkIdToCode(chainId, code);
2258
- networks[networkCode] = {
2259
- 'info': chain,
2260
- 'id': chainId,
2261
- 'name': this.safeString(chain, 'chainName'),
2262
- 'code': networkCode,
2263
- 'active': undefined,
2264
- 'fee': this.safeNumber2(chain, 'withdrawalMinFee', 'minWithdrawFee'),
2265
- 'deposit': this.safeBool(chain, 'isDepositEnabled'),
2266
- 'withdraw': this.safeBool(chain, 'isWithdrawEnabled'),
2267
- 'precision': this.parseNumber(this.parsePrecision(this.safeString(chain, 'withdrawPrecision'))),
2268
- 'limits': {
2269
- 'withdraw': {
2270
- 'min': this.safeNumber2(chain, 'withdrawalMinSize', 'minWithdrawSize'),
2271
- 'max': this.safeNumber2(chain, 'maxWithdraw', 'maxWithdrawSize'),
2272
- },
2273
- 'deposit': {
2274
- 'min': this.safeNumber2(chain, 'depositMinSize', 'minDepositSize'),
2275
- 'max': this.safeNumber2(chain, 'maxDeposit', 'maxDepositSize'),
2276
- },
2277
- },
2278
- };
2279
- }
2280
- // kucoin has determined 'fiat' currencies with below logic
2281
- const rawPrecision = this.safeString(entry, 'precision');
2282
- const precision = this.parseNumber(this.parsePrecision(rawPrecision));
2283
- const isFiat = chainsLength === 0;
2284
- result[code] = this.safeCurrencyStructure({
2285
- 'id': id,
2286
- 'name': this.safeString(entry, 'fullName'),
2287
- 'code': code,
2288
- 'type': isFiat ? 'fiat' : 'crypto',
2289
- 'precision': precision,
2290
- 'info': entry,
2291
- 'networks': networks,
2292
- 'deposit': undefined,
2293
- 'withdraw': undefined,
2292
+ const brokenCurrencies = this.handleOption('fetchCurrencies', 'brokenCurrencies', []);
2293
+ const filteredCurrencies = this.filterOutByArray(currenciesData, 'currency', brokenCurrencies); // remove broken entries
2294
+ return this.parseCurrencies(filteredCurrencies);
2295
+ }
2296
+ parseCurrency(currency) {
2297
+ const entry = currency;
2298
+ const id = this.safeString(entry, 'currency');
2299
+ const code = this.safeCurrencyCode(id);
2300
+ const networks = {};
2301
+ const chains = this.safeList2(entry, 'chains', 'items', []);
2302
+ const chainsLength = chains.length;
2303
+ for (let j = 0; j < chainsLength; j++) {
2304
+ const chain = chains[j];
2305
+ const chainId = this.safeString(chain, 'chainId');
2306
+ const networkCode = this.networkIdToCode(chainId, code);
2307
+ networks[networkCode] = {
2308
+ 'info': chain,
2309
+ 'id': chainId,
2310
+ 'name': this.safeString(chain, 'chainName'),
2311
+ 'code': networkCode,
2294
2312
  'active': undefined,
2295
- 'fee': undefined,
2296
- 'limits': undefined,
2297
- });
2313
+ 'fee': this.safeNumber2(chain, 'withdrawalMinFee', 'minWithdrawFee'),
2314
+ 'deposit': this.safeBool(chain, 'isDepositEnabled'),
2315
+ 'withdraw': this.safeBool(chain, 'isWithdrawEnabled'),
2316
+ 'precision': this.parseNumber(this.parsePrecision(this.safeString(chain, 'withdrawPrecision'))),
2317
+ 'limits': {
2318
+ 'withdraw': {
2319
+ 'min': this.safeNumber2(chain, 'withdrawalMinSize', 'minWithdrawSize'),
2320
+ 'max': this.safeNumber2(chain, 'maxWithdraw', 'maxWithdrawSize'),
2321
+ },
2322
+ 'deposit': {
2323
+ 'min': this.safeNumber2(chain, 'depositMinSize', 'minDepositSize'),
2324
+ 'max': this.safeNumber2(chain, 'maxDeposit', 'maxDepositSize'),
2325
+ },
2326
+ },
2327
+ };
2298
2328
  }
2299
- return result;
2329
+ // kucoin has determined 'fiat' currencies with below logic
2330
+ const rawPrecision = this.safeString(entry, 'precision');
2331
+ const precision = this.parseNumber(this.parsePrecision(rawPrecision));
2332
+ const isFiat = chainsLength === 0;
2333
+ return this.safeCurrencyStructure({
2334
+ 'id': id,
2335
+ 'name': this.safeString(entry, 'fullName'),
2336
+ 'code': code,
2337
+ 'type': isFiat ? 'fiat' : 'crypto',
2338
+ 'precision': precision,
2339
+ 'info': entry,
2340
+ 'networks': networks,
2341
+ 'deposit': undefined,
2342
+ 'withdraw': undefined,
2343
+ 'active': undefined,
2344
+ 'fee': undefined,
2345
+ 'limits': undefined,
2346
+ });
2300
2347
  }
2301
2348
  /**
2302
2349
  * @method
@@ -2304,41 +2351,68 @@ export default class kucoin extends Exchange {
2304
2351
  * @description fetch all the accounts associated with a profile
2305
2352
  * @see https://www.kucoin.com/docs-new/rest/account-info/account-funding/get-account-list-spot
2306
2353
  * @param {object} [params] extra parameters specific to the exchange API endpoint
2354
+ * @param {boolean} [params.uta] set to true for the unified trading account (uta), defaults to false
2307
2355
  * @returns {object} a dictionary of [account structures]{@link https://docs.ccxt.com/?id=account-structure} indexed by the account type
2308
2356
  */
2309
2357
  async fetchAccounts(params = {}) {
2310
- const response = await this.privateGetAccounts(params);
2311
- //
2312
- // {
2313
- // "code": "200000",
2314
- // "data": [
2315
- // {
2316
- // "balance": "0.00009788",
2317
- // "available": "0.00009788",
2318
- // "holds": "0",
2319
- // "currency": "BTC",
2320
- // "id": "5c6a4fd399a1d81c4f9cc4d0",
2321
- // "type": "trade"
2322
- // },
2323
- // {
2324
- // "balance": "0.00000001",
2325
- // "available": "0.00000001",
2326
- // "holds": "0",
2327
- // "currency": "ETH",
2328
- // "id": "5c6a49ec99a1d819392e8e9f",
2329
- // "type": "trade"
2330
- // }
2331
- // ]
2332
- // }
2333
- //
2334
- const data = this.safeList(response, 'data', []);
2358
+ let uta = await this.isUTAEnabled();
2359
+ [uta, params] = this.handleOptionAndParams(params, 'fetchAccounts', 'uta', uta);
2360
+ let response = undefined;
2361
+ let data = [];
2362
+ if (uta) {
2363
+ response = await this.utaPrivateGetAccountModeAccountOverview(this.extend(params, { 'accountMode': 'unified' }));
2364
+ //
2365
+ // {
2366
+ // "code": "200000",
2367
+ // "data": {
2368
+ // "accountType": "UNIFIED",
2369
+ // "riskRatio": "0.0000000000",
2370
+ // "equity": "30.0000000000",
2371
+ // "liability": "0.0000000000",
2372
+ // "availableMargin": "30.0000000000",
2373
+ // "adjustedEquity": "30.0000000000",
2374
+ // "im": "0.0000000000",
2375
+ // "mm": "0.0000000000"
2376
+ // }
2377
+ // }
2378
+ //
2379
+ const dataDict = this.safeDict(response, 'data', {});
2380
+ data = [dataDict];
2381
+ }
2382
+ else {
2383
+ //
2384
+ // {
2385
+ // "code": "200000",
2386
+ // "data": [
2387
+ // {
2388
+ // "balance": "0.00009788",
2389
+ // "available": "0.00009788",
2390
+ // "holds": "0",
2391
+ // "currency": "BTC",
2392
+ // "id": "5c6a4fd399a1d81c4f9cc4d0",
2393
+ // "type": "trade"
2394
+ // },
2395
+ // {
2396
+ // "balance": "0.00000001",
2397
+ // "available": "0.00000001",
2398
+ // "holds": "0",
2399
+ // "currency": "ETH",
2400
+ // "id": "5c6a49ec99a1d819392e8e9f",
2401
+ // "type": "trade"
2402
+ // }
2403
+ // ]
2404
+ // }
2405
+ //
2406
+ response = await this.privateGetAccounts(params);
2407
+ data = this.safeList(response, 'data', []);
2408
+ }
2335
2409
  const result = [];
2336
2410
  for (let i = 0; i < data.length; i++) {
2337
2411
  const account = data[i];
2338
2412
  const accountId = this.safeString(account, 'id');
2339
2413
  const currencyId = this.safeString(account, 'currency');
2340
2414
  const code = this.safeCurrencyCode(currencyId);
2341
- const type = this.safeString(account, 'type'); // main or trade
2415
+ const type = this.safeStringLower2(account, 'type', 'accountType'); // main or trade or unified
2342
2416
  result.push({
2343
2417
  'id': accountId,
2344
2418
  'type': type,
@@ -2367,7 +2441,7 @@ export default class kucoin extends Exchange {
2367
2441
  let networkCode = undefined;
2368
2442
  [networkCode, params] = this.handleNetworkCodeAndParams(params);
2369
2443
  if (networkCode !== undefined) {
2370
- request['chain'] = this.networkCodeToId(networkCode).toLowerCase();
2444
+ request['chain'] = this.networkCodeToId(networkCode, currency['code']).toLowerCase();
2371
2445
  }
2372
2446
  const response = await this.privateGetWithdrawalsQuotas(this.extend(request, params));
2373
2447
  const data = this.safeDict(response, 'data', {});
@@ -2398,7 +2472,7 @@ export default class kucoin extends Exchange {
2398
2472
  let networkCode = undefined;
2399
2473
  [networkCode, params] = this.handleNetworkCodeAndParams(params);
2400
2474
  if (networkCode !== undefined) {
2401
- request['chain'] = this.networkCodeToId(networkCode).toLowerCase();
2475
+ request['chain'] = this.networkCodeToId(networkCode, currency['code']).toLowerCase();
2402
2476
  }
2403
2477
  const response = await this.privateGetWithdrawalsQuotas(this.extend(request, params));
2404
2478
  //
@@ -2455,7 +2529,8 @@ export default class kucoin extends Exchange {
2455
2529
  const chains = this.safeList(fee, 'chains', []);
2456
2530
  for (let i = 0; i < chains.length; i++) {
2457
2531
  const chain = chains[i];
2458
- const networkCodeNew = this.networkIdToCode(this.safeString(chain, 'chainId'), this.safeString(currency, 'code'));
2532
+ const chainId = this.safeString(chain, 'chainId');
2533
+ const networkCodeNew = this.networkIdToCode(chainId, this.safeString(currency, 'code'));
2459
2534
  resultNew['networks'][networkCodeNew] = {
2460
2535
  'withdraw': {
2461
2536
  'fee': this.safeNumber2(chain, 'withdrawalMinFee', 'withdrawMinFee'),
@@ -2483,7 +2558,9 @@ export default class kucoin extends Exchange {
2483
2558
  'networks': {},
2484
2559
  };
2485
2560
  const networkId = this.safeString(fee, 'chain');
2486
- const networkCode = this.networkIdToCode(networkId, this.safeString(currency, 'code'));
2561
+ const currencyId = this.safeString(fee, 'currency');
2562
+ currency = this.safeCurrency(currencyId, currency);
2563
+ const networkCode = this.networkIdToCode(networkId, currency['code']);
2487
2564
  result['networks'][networkCode] = {
2488
2565
  'withdraw': minWithdrawFee,
2489
2566
  'deposit': {
@@ -2768,8 +2845,8 @@ export default class kucoin extends Exchange {
2768
2845
  await this.loadMarkets();
2769
2846
  const request = {};
2770
2847
  symbols = this.marketSymbols(symbols, undefined, true, true);
2771
- let uta = undefined;
2772
- [uta, params] = this.handleOptionAndParams(params, 'fetchTickers', 'uta', false);
2848
+ let uta = false;
2849
+ [uta, params] = this.handleOptionAndParams(params, 'fetchTickers', 'uta', uta);
2773
2850
  const tradeType = this.safeString(params, 'tradeType');
2774
2851
  let firstMarket = undefined;
2775
2852
  if (symbols !== undefined) {
@@ -2969,8 +3046,8 @@ export default class kucoin extends Exchange {
2969
3046
  const request = {
2970
3047
  'symbol': market['id'],
2971
3048
  };
2972
- let uta = undefined;
2973
- [uta, params] = this.handleOptionAndParams(params, 'fetchTicker', 'uta', false);
3049
+ let uta = false;
3050
+ [uta, params] = this.handleOptionAndParams(params, 'fetchTicker', 'uta', uta);
2974
3051
  let response = undefined;
2975
3052
  let result = undefined;
2976
3053
  let type = undefined;
@@ -3143,8 +3220,8 @@ export default class kucoin extends Exchange {
3143
3220
  async fetchOHLCV(symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
3144
3221
  await this.loadMarkets();
3145
3222
  const market = this.market(symbol);
3146
- let uta = undefined;
3147
- [uta, params] = this.handleOptionAndParams(params, 'fetchOHLCV', 'uta', false);
3223
+ let uta = false;
3224
+ [uta, params] = this.handleOptionAndParams(params, 'fetchOHLCV', 'uta', uta);
3148
3225
  if (uta) {
3149
3226
  return await this.fetchUTAOHLCV(symbol, timeframe, since, limit, params);
3150
3227
  }
@@ -3365,7 +3442,7 @@ export default class kucoin extends Exchange {
3365
3442
  let networkCode = undefined;
3366
3443
  [networkCode, params] = this.handleNetworkCodeAndParams(params);
3367
3444
  if (networkCode !== undefined) {
3368
- request['chain'] = this.networkCodeToId(networkCode); // docs mention "chain-name", but seems "chain-id" is used, like in "fetchDepositAddress"
3445
+ request['chain'] = this.networkCodeToId(networkCode, currency['code']); // docs mention "chain-name", but seems "chain-id" is used, like in "fetchDepositAddress"
3369
3446
  }
3370
3447
  const response = await this.privatePostDepositAddressCreate(this.extend(request, params));
3371
3448
  // {"code":"260000","msg":"Deposit address already exists."}
@@ -3391,10 +3468,12 @@ export default class kucoin extends Exchange {
3391
3468
  * @name kucoin#fetchDepositAddress
3392
3469
  * @description fetch the deposit address for a currency associated with this account
3393
3470
  * @see https://www.kucoin.com/docs-new/rest/account-info/deposit/get-deposit-address-v3/en
3471
+ * @see https://www.kucoin.com/docs-new/rest/ua/get-deposit-address
3394
3472
  * @param {string} code unified currency code
3395
3473
  * @param {object} [params] extra parameters specific to the exchange API endpoint
3396
3474
  * @param {string} [params.network] the blockchain network name
3397
- * @param {string} [params.accountType] 'main' or 'contract' (default is 'main')
3475
+ * @param {string} [params.accountType] 'main', 'contract' or 'uta' (default is 'main')
3476
+ * @param {boolean} [params.uta] set to true for the unified trading account (uta) endpoint, defaults to false
3398
3477
  * @returns {object} an [address structure]{@link https://docs.ccxt.com/?id=address-structure}
3399
3478
  */
3400
3479
  async fetchDepositAddress(code, params = {}) {
@@ -3403,9 +3482,14 @@ export default class kucoin extends Exchange {
3403
3482
  [accountType, params] = this.handleOptionAndParams(params, 'fetchDepositAddress', 'accountType', accountType);
3404
3483
  const accountsByType = this.safeDict(this.options, 'accountsByType', {});
3405
3484
  accountType = this.safeString(accountsByType, accountType, accountType);
3485
+ let uta = await this.isUTAEnabled();
3486
+ [uta, params] = this.handleOptionAndParams(params, 'fetchDepositAddress', 'uta', uta);
3406
3487
  if (accountType === 'contract') {
3407
3488
  return await this.fetchContractDepositAddress(code, params);
3408
3489
  }
3490
+ else if (uta || (accountType === 'uta') || (accountType === 'unified')) {
3491
+ return await super.fetchDepositAddress(code, this.extend(params, { 'uta': true }));
3492
+ }
3409
3493
  const currency = this.currency(code);
3410
3494
  const request = {
3411
3495
  'currency': currency['id'],
@@ -3416,7 +3500,7 @@ export default class kucoin extends Exchange {
3416
3500
  let networkCode = undefined;
3417
3501
  [networkCode, params] = this.handleNetworkCodeAndParams(params);
3418
3502
  if (networkCode !== undefined) {
3419
- request['chain'] = this.networkCodeToId(networkCode).toLowerCase();
3503
+ request['chain'] = this.networkCodeToId(networkCode, currency['code']).toLowerCase();
3420
3504
  }
3421
3505
  const version = this.options['versions']['private']['GET']['deposit-addresses'];
3422
3506
  this.options['versions']['private']['GET']['deposit-addresses'] = 'v1';
@@ -3484,10 +3568,11 @@ export default class kucoin extends Exchange {
3484
3568
  this.checkAddress(address);
3485
3569
  }
3486
3570
  }
3571
+ const chainId = this.safeString(depositAddress, 'chainId');
3487
3572
  return {
3488
3573
  'info': depositAddress,
3489
3574
  'currency': code,
3490
- 'network': this.networkIdToCode(this.safeString(depositAddress, 'chainId')),
3575
+ 'network': this.networkIdToCode(chainId, code),
3491
3576
  'address': address,
3492
3577
  'tag': this.safeString(depositAddress, 'memo'),
3493
3578
  };
@@ -3496,9 +3581,11 @@ export default class kucoin extends Exchange {
3496
3581
  * @method
3497
3582
  * @name kucoin#fetchDepositAddressesByNetwork
3498
3583
  * @see https://www.kucoin.com/docs-new/rest/account-info/deposit/get-deposit-address-v3/en
3584
+ * @see https://www.kucoin.com/docs-new/rest/ua/get-deposit-address
3499
3585
  * @description fetch the deposit address for a currency associated with this account
3500
3586
  * @param {string} code unified currency code
3501
3587
  * @param {object} [params] extra parameters specific to the exchange API endpoint
3588
+ * @param {boolean} [params.uta] set to true for the unified trading account (uta) endpoint, defaults to false
3502
3589
  * @returns {object} an array of [address structures]{@link https://docs.ccxt.com/?id=address-structure}
3503
3590
  */
3504
3591
  async fetchDepositAddressesByNetwork(code, params = {}) {
@@ -3507,25 +3594,56 @@ export default class kucoin extends Exchange {
3507
3594
  const request = {
3508
3595
  'currency': currency['id'],
3509
3596
  };
3510
- const version = this.options['versions']['private']['GET']['deposit-addresses'];
3511
- this.options['versions']['private']['GET']['deposit-addresses'] = 'v2';
3512
- const response = await this.privateGetDepositAddresses(this.extend(request, params));
3513
- //
3514
- // {
3515
- // "code": "200000",
3516
- // "data": [
3517
- // {
3518
- // "address": "fr1qvus7d4d5fgxj5e7zvqe6yhxd7txm95h2and69r",
3519
- // "memo": "",
3520
- // "chain": "BTC-Segwit",
3521
- // "contractAddress": ""
3522
- // },
3523
- // {"address":"37icNMEWbiF8ZkwUMxmfzMxi2A1MQ44bMn","memo":"","chain":"BTC","contractAddress":""},
3524
- // {"address":"Deposit temporarily blocked","memo":"","chain":"TRC20","contractAddress":""}
3525
- // ]
3526
- // }
3527
- //
3528
- this.options['versions']['private']['GET']['deposit-addresses'] = version;
3597
+ let uta = await this.isUTAEnabled();
3598
+ [uta, params] = this.handleOptionAndParams(params, 'fetchDepositAddressesByNetwork', 'uta', uta);
3599
+ let response = undefined;
3600
+ if (uta) {
3601
+ let networkCode = undefined;
3602
+ [networkCode, params] = this.handleNetworkCodeAndParams(params);
3603
+ if (networkCode !== undefined) {
3604
+ request['chain'] = this.networkCodeToId(networkCode).toLowerCase();
3605
+ }
3606
+ //
3607
+ // {
3608
+ // "code": "200000",
3609
+ // "data": [
3610
+ // {
3611
+ // "address": "0xf30a9b6968183668dbce515bd6449438ab3252b3",
3612
+ // "memo": "",
3613
+ // "remark": "",
3614
+ // "chainId": "eth",
3615
+ // "to": "FUNDING",
3616
+ // "expirationDate": 0,
3617
+ // "currency": "USDT",
3618
+ // "contractAddress": "0xdac17f958d2ee523a2206206994597c13d831ec7",
3619
+ // "chainName": "ERC20"
3620
+ // }
3621
+ // ]
3622
+ // }
3623
+ //
3624
+ response = await this.utaPrivateGetAssetDepositAddress(this.extend(request, params));
3625
+ }
3626
+ else {
3627
+ const version = this.options['versions']['private']['GET']['deposit-addresses'];
3628
+ this.options['versions']['private']['GET']['deposit-addresses'] = 'v2';
3629
+ response = await this.privateGetDepositAddresses(this.extend(request, params));
3630
+ //
3631
+ // {
3632
+ // "code": "200000",
3633
+ // "data": [
3634
+ // {
3635
+ // "address": "fr1qvus7d4d5fgxj5e7zvqe6yhxd7txm95h2and69r",
3636
+ // "memo": "",
3637
+ // "chain": "BTC-Segwit",
3638
+ // "contractAddress": ""
3639
+ // },
3640
+ // {"address":"37icNMEWbiF8ZkwUMxmfzMxi2A1MQ44bMn","memo":"","chain":"BTC","contractAddress":""},
3641
+ // {"address":"Deposit temporarily blocked","memo":"","chain":"TRC20","contractAddress":""}
3642
+ // ]
3643
+ // }
3644
+ //
3645
+ this.options['versions']['private']['GET']['deposit-addresses'] = version;
3646
+ }
3529
3647
  const chains = this.safeList(response, 'data', []);
3530
3648
  const parsed = this.parseDepositAddresses(chains, [currency['code']], false, {
3531
3649
  'currency': currency['code'],
@@ -3552,8 +3670,8 @@ export default class kucoin extends Exchange {
3552
3670
  const level = this.safeInteger(params, 'level', 2);
3553
3671
  const request = { 'symbol': market['id'] };
3554
3672
  const isAuthenticated = this.checkRequiredCredentials(false);
3555
- let uta = undefined;
3556
- [uta, params] = this.handleOptionAndParams(params, 'fetchOrderBook', 'uta', false);
3673
+ let uta = false;
3674
+ [uta, params] = this.handleOptionAndParams(params, 'fetchOrderBook', 'uta', uta);
3557
3675
  let response = undefined;
3558
3676
  let type = undefined;
3559
3677
  [type, params] = this.handleMarketTypeAndParams('fetchOrderBook', market, params);
@@ -3707,19 +3825,26 @@ export default class kucoin extends Exchange {
3707
3825
  * @see https://www.kucoin.com/docs-new/rest/futures-trading/orders/add-order
3708
3826
  * @see https://www.kucoin.com/docs-new/rest/futures-trading/orders/add-order-test
3709
3827
  * @see https://www.kucoin.com/docs-new/rest/futures-trading/orders/add-take-profit-and-stop-loss-order
3828
+ * @see https://www.kucoin.com/docs-new/rest/ua/place-order
3710
3829
  * @param {string} symbol Unified CCXT market symbol
3711
3830
  * @param {string} type 'limit' or 'market'
3712
3831
  * @param {string} side 'buy' or 'sell'
3713
3832
  * @param {float} amount the amount of currency to trade
3714
3833
  * @param {float} [price] the price at which the order is to be fulfilled, in units of the quote currency, ignored in market orders
3715
3834
  * @param {object} [params] extra parameters specific to the exchange API endpoint
3716
- * Check createSpotOrder() and createContractOrder() for more details on the extra parameters that can be used in params
3835
+ * @param {boolean} [params.uta] set to true for the unified trading account (uta) endpoint, defaults to false
3836
+ * Check createSpotOrder(), createContractOrder() and createUtaOrder () for more details on the extra parameters that can be used in params
3717
3837
  * @returns {object} an [order structure]{@link https://docs.ccxt.com/?id=order-structure}
3718
3838
  */
3719
3839
  async createOrder(symbol, type, side, amount, price = undefined, params = {}) {
3720
3840
  await this.loadMarkets();
3721
3841
  const market = this.market(symbol);
3722
- if (market['spot']) {
3842
+ let uta = await this.isUTAEnabled();
3843
+ [uta, params] = this.handleOptionAndParams(params, 'createOrder', 'uta', uta);
3844
+ if (uta) {
3845
+ return await this.createUtaOrder(symbol, type, side, amount, price, params);
3846
+ }
3847
+ else if (market['spot']) {
3723
3848
  return await this.createSpotOrder(symbol, type, side, amount, price, params);
3724
3849
  }
3725
3850
  else if (market['contract']) {
@@ -3749,7 +3874,7 @@ export default class kucoin extends Exchange {
3749
3874
  * @param {float} [params.triggerPrice] The price at which a trigger order is triggered at
3750
3875
  * @param {string} [params.marginMode] 'cross', // cross (cross mode) and isolated (isolated mode), set to cross by default, the isolated mode will be released soon, stay tuned
3751
3876
  * @param {string} [params.timeInForce] GTC, GTT, IOC, or FOK, default is GTC, limit orders only
3752
- * @param {string} [params.postOnly] Post only flag, invalid when timeInForce is IOC or FOK
3877
+ * @param {bool} [params.postOnly] Post only flag, invalid when timeInForce is IOC or FOK
3753
3878
  *
3754
3879
  * EXCHANGE SPECIFIC PARAMETERS
3755
3880
  * @param {string} [params.clientOid] client order id, defaults to uuid if not passed
@@ -3942,7 +4067,7 @@ export default class kucoin extends Exchange {
3942
4067
  * @param {float} [params.takeProfitPrice] price to trigger take-profit orders
3943
4068
  * @param {bool} [params.reduceOnly] A mark to reduce the position size only. Set to false by default. Need to set the position size when reduceOnly is true.
3944
4069
  * @param {string} [params.timeInForce] GTC, GTT, IOC, or FOK, default is GTC, limit orders only
3945
- * @param {string} [params.postOnly] Post only flag, invalid when timeInForce is IOC or FOK
4070
+ * @param {bool} [params.postOnly] Post only flag, invalid when timeInForce is IOC or FOK
3946
4071
  * @param {float} [params.cost] the cost of the order in units of USDT
3947
4072
  * @param {string} [params.marginMode] 'cross' or 'isolated', default is 'isolated'
3948
4073
  * @param {bool} [params.hedged] *swap and future only* true for hedged mode, false for one way mode, default is false
@@ -4112,6 +4237,223 @@ export default class kucoin extends Exchange {
4112
4237
  params = this.omit(params, ['timeInForce', 'stopPrice', 'triggerPrice', 'stopLossPrice', 'takeProfitPrice', 'reduceOnly', 'hedged']); // Time in force only valid for limit orders, exchange error when gtc for market orders
4113
4238
  return this.extend(request, params);
4114
4239
  }
4240
+ /**
4241
+ * @method
4242
+ * @name kucoin#createUtaOrder
4243
+ * @description helper method for creating uta orders
4244
+ * @see https://www.kucoin.com/docs-new/rest/ua/place-order
4245
+ * @param {string} symbol Unified CCXT market symbol
4246
+ * @param {string} type 'limit' or 'market'
4247
+ * @param {string} side 'buy' or 'sell'
4248
+ * @param {float} amount the amount of currency to trade
4249
+ * @param {float} [price] the price at which the order is to be fulfilled, in units of the quote currency, ignored in market orders
4250
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
4251
+ * @param {string} [params.clientOrderId] client order id, defaults to uuid if not passed
4252
+ * @param {float} [params.cost] the cost of the order in units of quote currency
4253
+ * @param {string} [params.timeInForce] GTC, GTD, IOC, FOK or PO
4254
+ * @param {bool} [params.postOnly] Post only flag, invalid when timeInForce is IOC or FOK (default is false)
4255
+ * @param {bool} [params.reduceOnly] *contract markets only* A mark to reduce the position size only. Set to false by default
4256
+ * @param {float} [params.triggerPrice] The price a trigger order is triggered at
4257
+ * @param {string} [params.triggerDirection] 'ascending' or 'descending', the direction the triggerPrice is triggered from, requires triggerPrice
4258
+ * @param {string} [params.triggerPriceType] *contract markets only* "last", "mark", "index" - defaults to "mark"
4259
+ * @param {float} [params.stopLossPrice] price to trigger stop-loss orders
4260
+ * @param {float} [params.takeProfitPrice] price to trigger take-profit orders
4261
+ * @param {string} [params.marginMode] 'cross' or 'isolated', (default is 'cross' for margin orders, default is 'isolated' for contract orders)
4262
+ *
4263
+ * Exchange-specific parameters -------------------------------------------------
4264
+ * @param {string} [params.accountMode] 'unified' or 'classic', default is 'unified'
4265
+ * @param {string} [params.stp] '', // self trade prevention, CN, CO, CB or DC
4266
+ * @param {int} [params.cancelAfter] - Cancel After N Seconds (Calculated from the time of entering the matching engine), only effective when timeInForce is GTD
4267
+ * @param {string} [params.sizeUnit] *contracts only* 'BASECCY' (amount of base currency) or 'UNIT' (number of contracts), default is 'UNIT'
4268
+ *
4269
+ * Classic account parameters
4270
+ * @param {bool} [params.autoBorrow] *classic margin orders only*
4271
+ * @param {bool} [params.autoRepay] *classic margin orders only*
4272
+ * @param {string} [params.hedged] *classic contract orders only* true for hedged mode, false for one way mode, default is false
4273
+ * @param {int} [params.leverage] *classic contract orders with isolated marginMode only* Leverage size of the order
4274
+ * @returns {object} an [order structure]{@link https://docs.ccxt.com/?id=order-structure}
4275
+ */
4276
+ async createUtaOrder(symbol, type, side, amount, price = undefined, params = {}) {
4277
+ await this.loadMarkets();
4278
+ const request = this.createUtaOrderRequest(symbol, type, side, amount, price, params);
4279
+ const response = await this.utaPrivatePostAccountModeOrderPlace(request);
4280
+ //
4281
+ // {
4282
+ // "code": "200000",
4283
+ // "data": {
4284
+ // "orderId": "426319129738321920",
4285
+ // "tradeType": "SPOT",
4286
+ // "ts": 1774455603216000000,
4287
+ // "clientOid": "b896c118-a674-4863-baf4-a9ea3cd696c5"
4288
+ // }
4289
+ // }
4290
+ //
4291
+ const data = this.safeDict(response, 'data', {});
4292
+ return this.parseOrder(data);
4293
+ }
4294
+ createUtaOrderRequest(symbol, type, side, amount, price = undefined, params = {}) {
4295
+ const market = this.market(symbol);
4296
+ const isSpot = market['spot'];
4297
+ const isContract = market['contract'];
4298
+ let accountMode = 'unified';
4299
+ [accountMode, params] = this.handleOptionAndParams(params, 'createOrder', 'accountMode', accountMode);
4300
+ const isUnified = (accountMode === 'unified');
4301
+ let marginMode = undefined;
4302
+ [marginMode, params] = this.handleMarginModeAndParams('createOrder', params);
4303
+ const marginModeDefined = (marginMode !== undefined);
4304
+ const isSpotMargin = (isSpot && marginModeDefined);
4305
+ if (isSpotMargin && isUnified) {
4306
+ throw new NotSupported(this.id + ' createOrder() does not support spot margin orders with unified accountMode');
4307
+ }
4308
+ const tradeType = this.handleTradeType(isContract, marginMode, params);
4309
+ const clientOrderId = this.safeString2(params, 'clientOid', 'clientOrderId', this.uuid());
4310
+ params = this.omit(params, ['clientOid', 'clientOrderId']);
4311
+ const request = {
4312
+ 'accountMode': accountMode,
4313
+ 'tradeType': tradeType,
4314
+ 'clientOid': clientOrderId,
4315
+ 'symbol': market['id'],
4316
+ // 'triggerDirection'- 'UP' or 'DOWN (required for trigger orders, supported for classic-FUTURES and unified-SPOT and unified-FUTURES)
4317
+ // 'triggerPriceType' - 'TP', 'IP', 'MP' (required for trigger orders, supported for classic-FUTURES and unified-SPOT and unified-FUTURES)
4318
+ // 'triggerPrice' (required for trigger orders)
4319
+ 'side': side.toUpperCase(),
4320
+ 'orderType': type.toUpperCase(),
4321
+ // 'size'
4322
+ // 'sizeUnit' - 'BASECCY', 'QUOTECCY' (for market SPOT) or 'UNIT' (for unified-FUTURES)
4323
+ // 'price'
4324
+ // 'timeInForce' - 'GTC', 'IOC', 'FOK', 'GTT' or 'RPI' (GTT is not supported for FUTURES)
4325
+ // 'postOnly'
4326
+ // 'reduceOnly' (only for FUTURES)
4327
+ // 'stp' - 'CN', 'CO', 'CB' or 'DC' (DC is not supported for FUTURES)
4328
+ // 'cancelAfter' - time in seconds (only valid when timeInForce is GTT, not supported for FUTURES)
4329
+ // 'tags'
4330
+ // 'autoBorrow' (only for classic-CROSS and classic-ISOLATED)
4331
+ // 'autoRepay' (only for classic-CROSS and classic-ISOLATED)
4332
+ // 'positionSide' - 'BOTH', 'LONG' or 'SHORT' (only for classic-FUTURES)
4333
+ // 'marginMode' - 'ISOLATED' or 'CROSS' (only for classic-FUTURES, default is 'ISOLATED')
4334
+ // 'leverage' (only for classic-FUTURES-ISOLATED, required)
4335
+ // 'tpTriggerPriceType' - 'TP', 'IP', 'MP' (only for unified-FUTURES and classic-FUTURES)
4336
+ // 'tpTriggerPrice' (only for unified-FUTURES and classic-FUTURES)
4337
+ // 'slTriggerPriceType' - 'TP', 'IP', 'MP' (only for unified-FUTURES and classic-FUTURES)
4338
+ // 'slTriggerPrice' (only for unified-FUTURES and classic-FUTURES)
4339
+ };
4340
+ if (tradeType !== undefined) {
4341
+ request['tradeType'] = tradeType;
4342
+ }
4343
+ request['clientOid'] = clientOrderId;
4344
+ const isMarketOrder = (type === 'market');
4345
+ const cost = this.safeString(params, 'cost');
4346
+ if (cost !== undefined) {
4347
+ params = this.omit(params, 'cost');
4348
+ if (isSpot && isMarketOrder) {
4349
+ request['sizeUnit'] = 'QUOTECCY';
4350
+ request['size'] = this.marketOrderAmountToPrecision(symbol, cost);
4351
+ }
4352
+ else {
4353
+ throw new NotSupported(this.id + ' createOrder() with cost is supported for spot market orders only');
4354
+ }
4355
+ }
4356
+ else {
4357
+ let sizeUnit = 'BASECCY';
4358
+ if (isContract) {
4359
+ [sizeUnit, params] = this.handleOptionAndParams(params, 'createOrder', 'sizeUnit', 'UNIT');
4360
+ }
4361
+ request['sizeUnit'] = sizeUnit;
4362
+ request['size'] = this.amountToPrecision(symbol, amount);
4363
+ }
4364
+ if (!isMarketOrder) {
4365
+ request['price'] = this.priceToPrecision(symbol, price);
4366
+ }
4367
+ let postOnly = undefined;
4368
+ [postOnly, params] = this.handlePostOnly(isMarketOrder, false, params);
4369
+ const timeInForce = this.handleTimeInForce(params);
4370
+ if ((timeInForce !== undefined)) {
4371
+ params = this.omit(params, 'timeInForce');
4372
+ request['timeInForce'] = timeInForce;
4373
+ }
4374
+ if (postOnly) {
4375
+ request['postOnly'] = true;
4376
+ }
4377
+ if (isContract) {
4378
+ if (!isUnified) {
4379
+ if (marginModeDefined) {
4380
+ request['marginMode'] = marginMode.toUpperCase();
4381
+ if (marginMode === 'isolated') {
4382
+ const leverage = this.safeInteger(params, 'leverage');
4383
+ if (leverage === undefined) {
4384
+ request['leverage'] = 1;
4385
+ }
4386
+ }
4387
+ }
4388
+ const reduceOnly = this.safeBool(params, 'reduceOnly', false);
4389
+ let hedged = false;
4390
+ [hedged, params] = this.handleParamBool(params, 'hedged', hedged);
4391
+ if (hedged) {
4392
+ let positionSide = (side === 'buy') ? 'LONG' : 'SHORT';
4393
+ if (reduceOnly) {
4394
+ positionSide = (positionSide === 'LONG') ? 'SHORT' : 'LONG';
4395
+ }
4396
+ request['positionSide'] = positionSide;
4397
+ }
4398
+ }
4399
+ }
4400
+ // handling with coinditional orders
4401
+ const [triggerPrice, stopLossPrice, takeProfitPrice] = this.handleTriggerPrices(params);
4402
+ const stopLoss = this.safeDict(params, 'stopLoss');
4403
+ const takeProfit = this.safeDict(params, 'takeProfit');
4404
+ const hasStopLoss = stopLoss !== undefined;
4405
+ const hasTakeProfit = takeProfit !== undefined;
4406
+ const triggerPriceTypes = {
4407
+ 'mark': 'MP',
4408
+ 'last': 'TP',
4409
+ 'index': 'IP',
4410
+ };
4411
+ if (triggerPrice) {
4412
+ const triggerDirection = this.safeString(params, 'triggerDirection');
4413
+ if (triggerDirection === undefined) {
4414
+ throw new ArgumentsRequired(this.id + ' createOrder() requires a triggerDirection parameter for trigger orders. Provide params.tringgerDirection or use params.stopLossPrice or params.takeProfitPrice instead of params.triggerPrice');
4415
+ }
4416
+ request['triggerDirection'] = (triggerDirection === 'ascending') ? 'UP' : 'DOWN';
4417
+ request['triggerPrice'] = this.priceToPrecision(symbol, triggerPrice);
4418
+ }
4419
+ else if (hasStopLoss || hasTakeProfit) {
4420
+ if (!isContract) {
4421
+ throw new NotSupported(this.id + ' createOrder() stopLoss and takeProfit parameters are only supported for contract orders');
4422
+ }
4423
+ if (hasStopLoss) {
4424
+ const slTriggerPrice = this.safeString2(stopLoss, 'triggerPrice', 'stopPrice');
4425
+ const slTriggerPriceType = this.safeString(stopLoss, 'triggerPriceType', 'mark');
4426
+ request['slTriggerPrice'] = this.priceToPrecision(symbol, slTriggerPrice);
4427
+ request['slTriggerPriceType'] = this.safeString(triggerPriceTypes, slTriggerPriceType, slTriggerPriceType);
4428
+ }
4429
+ if (hasTakeProfit) {
4430
+ const tpTriggerPrice = this.safeString2(takeProfit, 'triggerPrice', 'takeProfitPrice');
4431
+ const tpTriggerPriceType = this.safeString(takeProfit, 'triggerPriceType', 'mark');
4432
+ request['tpTriggerPrice'] = this.priceToPrecision(symbol, tpTriggerPrice);
4433
+ request['tpTriggerPriceType'] = this.safeString(triggerPriceTypes, tpTriggerPriceType, tpTriggerPriceType);
4434
+ }
4435
+ }
4436
+ else if (stopLossPrice || takeProfitPrice) {
4437
+ if (stopLossPrice) {
4438
+ request['triggerDirection'] = (side === 'buy') ? 'UP' : 'DOWN';
4439
+ request['triggerPrice'] = this.priceToPrecision(symbol, stopLossPrice);
4440
+ if (isContract) {
4441
+ const stopLossPriceType = this.safeString2(params, 'stopLossPriceType', 'triggerPriceType', 'mark');
4442
+ request['triggerPriceType'] = this.safeString(triggerPriceTypes, stopLossPriceType, stopLossPriceType);
4443
+ }
4444
+ }
4445
+ else {
4446
+ request['triggerDirection'] = (side === 'buy') ? 'DOWN' : 'UP';
4447
+ request['triggerPrice'] = this.priceToPrecision(symbol, takeProfitPrice);
4448
+ if (isContract) {
4449
+ const takeProfitPriceType = this.safeString2(params, 'takeProfitPriceType', 'triggerPriceType', 'mark');
4450
+ request['triggerPriceType'] = this.safeString(triggerPriceTypes, takeProfitPriceType, takeProfitPriceType);
4451
+ }
4452
+ }
4453
+ }
4454
+ params = this.omit(params, ['triggerPrice', 'stopLossPrice', 'takeProfitPrice', 'stopPriceType', 'stopLossPriceType', 'takeProfitPriceType', 'triggerPriceType', 'triggerDirection', 'stopLoss', 'takeProfit', 'hedged']);
4455
+ return this.extend(request, params);
4456
+ }
4115
4457
  /**
4116
4458
  * @method
4117
4459
  * @name kucoin#createMarketOrderWithCost
@@ -4403,16 +4745,23 @@ export default class kucoin extends Exchange {
4403
4745
  * @see https://www.kucoin.com/docs-new/rest/margin-trading/orders/cancel-stop-order-by-clientoid
4404
4746
  * @see https://www.kucoin.com/docs-new/rest/futures-trading/orders/cancel-order-by-orderld
4405
4747
  * @see https://www.kucoin.com/docs-new/rest/futures-trading/orders/cancel-order-by-clientoid
4748
+ * @see https://www.kucoin.com/docs-new/rest/ua/cancel-order
4406
4749
  * @param {string} id order id
4407
4750
  * @param {string} symbol unified symbol of the market the order was made in
4408
4751
  * @param {object} [params] extra parameters specific to the exchange API endpoint
4409
4752
  * @param {string} [params.type] 'spot' or 'swap', used if symbol is not provided (default is 'spot')
4410
4753
  * @param {string} [params.marginMode] *spot only* 'cross' or 'isolated'
4754
+ * @param {boolean} [params.uta] true for cancelling order with unified account endpoint (default is false)
4411
4755
  * Check cancelSpotOrder() and cancelContractOrder() for more details on the extra parameters that can be used in params
4412
4756
  * @returns Response from the exchange
4413
4757
  */
4414
4758
  async cancelOrder(id, symbol = undefined, params = {}) {
4415
4759
  await this.loadMarkets();
4760
+ let uta = await this.isUTAEnabled();
4761
+ [uta, params] = this.handleOptionAndParams(params, 'cancelOrder', 'uta', uta);
4762
+ if (uta) {
4763
+ return await this.cancelUtaOrder(id, symbol, params);
4764
+ }
4416
4765
  let marketType = undefined;
4417
4766
  let market = undefined;
4418
4767
  if (symbol !== undefined) {
@@ -4629,6 +4978,61 @@ export default class kucoin extends Exchange {
4629
4978
  //
4630
4979
  return this.safeOrder({ 'info': response });
4631
4980
  }
4981
+ /**
4982
+ * @method
4983
+ * @name kucoin#cancelUtaOrder
4984
+ * @description helper method for cancelling uta orders
4985
+ * @see https://www.kucoin.com/docs-new/rest/ua/cancel-order
4986
+ * @param {string} id order id
4987
+ * @param {string} symbol unified symbol of the market the order was made in
4988
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
4989
+ * @param {string} [params.accountMode] 'unified' or 'classic' (default is 'unified')
4990
+ * @param {string} [params.clientOrderId] client order id, required if id is not provided
4991
+ * @param {string} [params.marginMode] 'cross' or 'isolated', required if fetching a margin order
4992
+ * @returns Response from the exchange
4993
+ */
4994
+ async cancelUtaOrder(id, symbol = undefined, params = {}) {
4995
+ if (symbol === undefined) {
4996
+ throw new ArgumentsRequired(this.id + ' cancelOrder() requires a symbol argument for uta endpoint');
4997
+ }
4998
+ await this.loadMarkets();
4999
+ const request = {};
5000
+ const clientOrderId = this.safeString2(params, 'clientOid', 'clientOrderId');
5001
+ if (clientOrderId !== undefined) {
5002
+ request['clientOid'] = clientOrderId;
5003
+ params = this.omit(params, ['clientOid', 'clientOrderId']);
5004
+ }
5005
+ else {
5006
+ if (id === undefined) {
5007
+ throw new ArgumentsRequired(this.id + ' fetchOrder() requires an id argument or clientOrderId parameter');
5008
+ }
5009
+ request['orderId'] = id;
5010
+ }
5011
+ await this.loadMarkets();
5012
+ const market = this.market(symbol);
5013
+ request['symbol'] = market['id'];
5014
+ let accountMode = 'unified';
5015
+ [accountMode, params] = this.handleOptionAndParams(params, 'fetchOrder', 'accountMode', accountMode);
5016
+ request['accountMode'] = accountMode;
5017
+ let marginMode = undefined;
5018
+ [marginMode, params] = this.handleMarginModeAndParams('fetchOrder', params);
5019
+ const tradeType = this.handleTradeType(market['contract'], marginMode, params);
5020
+ request['tradeType'] = tradeType;
5021
+ const response = await this.utaPrivatePostAccountModeOrderCancel(this.extend(request, params));
5022
+ //
5023
+ // {
5024
+ // "code": "200000",
5025
+ // "data": {
5026
+ // "orderId": "426319129738321920",
5027
+ // "tradeType": "SPOT",
5028
+ // "ts": 1774457628105000000,
5029
+ // "clientOid": "b896c118-a674-4863-baf4-a9ea3cd696c5"
5030
+ // }
5031
+ // }
5032
+ //
5033
+ const data = this.safeDict(response, 'data', {});
5034
+ return this.parseOrder(data, market);
5035
+ }
4632
5036
  /**
4633
5037
  * @method
4634
5038
  * @name kucoin#cancelAllOrders
@@ -4640,14 +5044,22 @@ export default class kucoin extends Exchange {
4640
5044
  * @see https://www.kucoin.com/docs-new/rest/margin-trading/orders/batch-cancel-stop-orders
4641
5045
  * @see https://www.kucoin.com/docs-new/rest/futures-trading/orders/cancel-all-orders
4642
5046
  * @see https://www.kucoin.com/docs-new/rest/futures-trading/orders/cancel-all-stop-orders
5047
+ * @see https://www.kucoin.com/docs-new/rest/ua/batch-cancel-order-by-symbol
4643
5048
  * @param {string} symbol unified market symbol, only orders in the market of this symbol are cancelled when symbol is not undefined
4644
5049
  * @param {object} [params] extra parameters specific to the exchange API endpoint
4645
5050
  * @param {string} [params.type] 'spot' or 'swap', used if symbol is not provided (default is 'spot')
4646
5051
  * @param {string} [params.marginMode] *spot only* 'cross' or 'isolated'
5052
+ * @param {boolean} [params.uta] true for cancelling orders with unified account endpoint (default is false)
5053
+ * Check cancelAllSpotOrders(), cancelAllContractOrders() and cancelAllUtaOrders() for more details on the extra parameters that can be used in params
4647
5054
  * @returns Response from the exchange
4648
5055
  */
4649
5056
  async cancelAllOrders(symbol = undefined, params = {}) {
4650
5057
  await this.loadMarkets();
5058
+ let uta = await this.isUTAEnabled();
5059
+ [uta, params] = this.handleOptionAndParams(params, 'cancelAllOrders', 'uta', uta);
5060
+ if (uta) {
5061
+ return await this.cancelAllUtaOrders(symbol, params);
5062
+ }
4651
5063
  let marketType = undefined;
4652
5064
  let market = undefined;
4653
5065
  if (symbol !== undefined) {
@@ -4765,26 +5177,78 @@ export default class kucoin extends Exchange {
4765
5177
  }
4766
5178
  /**
4767
5179
  * @method
4768
- * @name kucoin#fetchOrdersByStatus
4769
- * @description fetches a list of orders placed on the exchange
4770
- * @see https://www.kucoin.com/docs-new/rest/spot-trading/orders/get-open-orders
4771
- * @see https://www.kucoin.com/docs-new/rest/spot-trading/orders/get-closed-orders
4772
- * @see https://www.kucoin.com/docs-new/rest/spot-trading/orders/get-stop-orders-list
4773
- * @see https://www.kucoin.com/docs-new/rest/margin-trading/orders/get-open-orders
4774
- * @see https://www.kucoin.com/docs-new/rest/margin-trading/orders/get-closed-orders
4775
- * @see https://www.kucoin.com/docs-new/rest/margin-trading/orders/get-stop-order-list
4776
- * @see https://www.kucoin.com/docs-new/rest/futures-trading/orders/get-order-list
4777
- * @see https://www.kucoin.com/docs-new/rest/futures-trading/orders/get-stop-order-list
4778
- * @param {string} status 'active' or 'closed', only 'active' is valid for stop orders
4779
- * @param {string} symbol unified symbol for the market to retrieve orders from
4780
- * @param {int} [since] timestamp in ms of the earliest order to retrieve
4781
- * @param {int} [limit] The maximum number of orders to retrieve
5180
+ * @name kucoin#cancelAllUtaOrders
5181
+ * @description helper method for cancelling all uta orders
5182
+ * @see https://www.kucoin.com/docs-new/rest/ua/batch-cancel-order-by-symbol
5183
+ * @param {string} symbol unified market symbol, only orders in the market of this symbol are cancelled when symbol is not undefined
5184
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
5185
+ * @param {bool} [params.trigger] true if cancelling all stop orders
5186
+ * @param {string} [params.marginMode] 'CROSS' or 'ISOLATED'
5187
+ * @returns Response from the exchange
5188
+ */
5189
+ async cancelAllUtaOrders(symbol = undefined, params = {}) {
5190
+ if (symbol === undefined) {
5191
+ throw new ArgumentsRequired(this.id + ' cancelAllOrders() requires a symbol argument for uta endpoint');
5192
+ }
5193
+ await this.loadMarkets();
5194
+ const market = this.market(symbol);
5195
+ const isContract = market['contract'];
5196
+ const tradeType = isContract ? 'FUTURES' : 'SPOT';
5197
+ let trigger = false;
5198
+ [trigger, params] = this.handleParamBool(params, 'trigger', trigger);
5199
+ const orderFilter = trigger ? 'ADVANCED' : 'NORMAL';
5200
+ const request = {
5201
+ 'accountMode': 'unified',
5202
+ 'symbol': market['id'],
5203
+ 'tradeType': tradeType,
5204
+ 'orderFilter': orderFilter,
5205
+ };
5206
+ const response = await this.utaPrivatePostAccountModeOrderCancelAll(this.extend(request, params));
5207
+ //
5208
+ // {
5209
+ // "code": "200000",
5210
+ // "data": {
5211
+ // "tradeType": "SPOT",
5212
+ // "ts": 1774458644140000000,
5213
+ // "items": [
5214
+ // {
5215
+ // "orderId": "426328635071352832"
5216
+ // }
5217
+ // ]
5218
+ // }
5219
+ // }
5220
+ //
5221
+ const data = this.safeDict(response, 'data', {});
5222
+ const orders = this.safeList(data, 'items', []);
5223
+ return this.parseOrders(orders, market, undefined, undefined, { 'status': 'canceled' });
5224
+ }
5225
+ /**
5226
+ * @method
5227
+ * @name kucoin#fetchOrdersByStatus
5228
+ * @description fetches a list of orders placed on the exchange
5229
+ * @see https://www.kucoin.com/docs-new/rest/spot-trading/orders/get-open-orders
5230
+ * @see https://www.kucoin.com/docs-new/rest/spot-trading/orders/get-closed-orders
5231
+ * @see https://www.kucoin.com/docs-new/rest/spot-trading/orders/get-stop-orders-list
5232
+ * @see https://www.kucoin.com/docs-new/rest/margin-trading/orders/get-open-orders
5233
+ * @see https://www.kucoin.com/docs-new/rest/margin-trading/orders/get-closed-orders
5234
+ * @see https://www.kucoin.com/docs-new/rest/margin-trading/orders/get-stop-order-list
5235
+ * @see https://www.kucoin.com/docs-new/rest/futures-trading/orders/get-order-list
5236
+ * @see https://www.kucoin.com/docs-new/rest/futures-trading/orders/get-stop-order-list
5237
+ * @see https://www.kucoin.com/docs-new/rest/ua/get-open-order-list
5238
+ * @see https://www.kucoin.com/docs-new/rest/ua/get-order-history
5239
+ * @param {string} status 'active' or 'closed', only 'active' is valid for stop orders
5240
+ * @param {string} symbol unified symbol for the market to retrieve orders from
5241
+ * @param {int} [since] timestamp in ms of the earliest order to retrieve
5242
+ * @param {int} [limit] The maximum number of orders to retrieve
4782
5243
  * @param {object} [params] exchange specific parameters
4783
- * Check fetchSpotOrdersByStatus() and fetchContractOrdersByStatus() for more details on the extra parameters that can be used in params
5244
+ * @param {boolean} [params.uta] true for fetch orders with uta endpoint (default is false)
5245
+ * Check fetchSpotOrdersByStatus(), fetchContractOrdersByStatus() and fetchUtaOrdersByStatus() for more details on the extra parameters that can be used in params
4784
5246
  * @returns An [array of order structures]{@link https://docs.ccxt.com/?id=order-structure}
4785
5247
  */
4786
5248
  async fetchOrdersByStatus(status, symbol = undefined, since = undefined, limit = undefined, params = {}) {
4787
5249
  await this.loadMarkets();
5250
+ let uta = await this.isUTAEnabled();
5251
+ [uta, params] = this.handleOptionAndParams(params, 'fetchOrdersByStatus', 'uta', uta);
4788
5252
  let marketType = undefined;
4789
5253
  if (symbol === undefined) {
4790
5254
  const type = this.safeString(params, 'type'); // exchange has specific param for order type
@@ -4794,14 +5258,26 @@ export default class kucoin extends Exchange {
4794
5258
  params = this.omit(params, 'type');
4795
5259
  }
4796
5260
  else {
4797
- [marketType, params] = this.handleMarketTypeAndParams('fetchOrdersByStatus', undefined, {});
5261
+ const methodOptions = this.safeDict(this.options, 'fetchOrdersByStatus', {});
5262
+ const methodDefaultType = this.safeString2(methodOptions, 'defaultType', 'type');
5263
+ if (methodDefaultType === undefined) {
5264
+ marketType = this.safeString2(this.options, 'defaultType', 'type', 'spot');
5265
+ }
5266
+ else {
5267
+ marketType = methodDefaultType;
5268
+ }
4798
5269
  }
4799
5270
  }
4800
5271
  else {
4801
5272
  const market = this.market(symbol);
4802
5273
  marketType = market['type'];
4803
5274
  }
4804
- if ((marketType === 'spot') || (marketType === 'margin')) {
5275
+ if (uta) {
5276
+ params = this.omit(params, 'uta');
5277
+ params = this.extend(params, { 'marketType': marketType });
5278
+ return await this.fetchUtaOrdersByStatus(status, symbol, since, limit, params);
5279
+ }
5280
+ else if ((marketType === 'spot') || (marketType === 'margin')) {
4805
5281
  return await this.fetchSpotOrdersByStatus(status, symbol, since, limit, params);
4806
5282
  }
4807
5283
  else {
@@ -5066,6 +5542,128 @@ export default class kucoin extends Exchange {
5066
5542
  const orders = this.safeList(responseData, 'items', []);
5067
5543
  return this.parseOrders(orders, market, since, limit);
5068
5544
  }
5545
+ /**
5546
+ * @method
5547
+ * @name kucoin#fetchUtaOrdersByStatus
5548
+ * @description helper method for fetching orders by status with uta endpoint
5549
+ * @see https://www.kucoin.com/docs-new/rest/ua/get-open-order-list
5550
+ * @see https://www.kucoin.com/docs-new/rest/ua/get-order-history
5551
+ * @param {string} status 'active' or 'closed', only 'active' is valid for stop orders
5552
+ * @param {string} symbol unified symbol for the market to retrieve orders from
5553
+ * @param {int} [since] timestamp in ms of the earliest order to retrieve
5554
+ * @param {int} [limit] The maximum number of orders to retrieve
5555
+ * @param {object} [params] exchange specific parameters
5556
+ * @param {int} [params.until] End time in ms
5557
+ * @param {string} [params.side] *closed orders only* 'BUY' or 'SELL'
5558
+ * @param {string} [params.accountMode] 'unified' or 'classic' (default is unified)
5559
+ * @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)
5560
+ * @returns An [array of order structures]{@link https://docs.ccxt.com/?id=order-structure}
5561
+ */
5562
+ async fetchUtaOrdersByStatus(status, symbol = undefined, since = undefined, limit = undefined, params = {}) {
5563
+ await this.loadMarkets();
5564
+ let paginate = false;
5565
+ const maxLimit = 200;
5566
+ [paginate, params] = this.handleOptionAndParams(params, 'fetchOrdersByStatus', 'paginate');
5567
+ if (paginate) {
5568
+ return await this.fetchPaginatedCallDynamic('fetchOrdersByStatus', symbol, since, limit, params, maxLimit);
5569
+ }
5570
+ let accountMode = 'unified';
5571
+ [accountMode, params] = this.handleOptionAndParams(params, 'fetchUtaOrdersByStatus', 'accountMode', accountMode);
5572
+ let request = {
5573
+ 'accountMode': accountMode,
5574
+ };
5575
+ let marketType = undefined;
5576
+ let market = undefined;
5577
+ if (symbol !== undefined) {
5578
+ market = this.market(symbol);
5579
+ marketType = market['type'];
5580
+ request['symbol'] = market['id'];
5581
+ }
5582
+ else {
5583
+ marketType = this.safeString(params, 'marketType');
5584
+ }
5585
+ params = this.omit(params, 'marketType');
5586
+ const isContract = (marketType !== 'spot') && (marketType !== 'margin');
5587
+ if (!isContract && (symbol === undefined)) {
5588
+ throw new ArgumentsRequired(this.id + ' fetchOrdersByStatus() requires a symbol argument for spot and margin markets when using uta endpoint');
5589
+ }
5590
+ let marginMode = undefined;
5591
+ [marginMode, params] = this.handleMarginModeAndParams('fetchOrdersByStatus', params);
5592
+ const tradeType = this.handleTradeType(isContract, marginMode, params);
5593
+ params['tradeType'] = tradeType;
5594
+ if (since !== undefined) {
5595
+ request['startAt'] = since;
5596
+ }
5597
+ [request, params] = this.handleUntilOption('endAt', request, params);
5598
+ if (limit !== undefined) {
5599
+ request['pageSize'] = limit;
5600
+ }
5601
+ let lowercaseStatus = status.toLowerCase();
5602
+ if (lowercaseStatus === 'open') {
5603
+ lowercaseStatus = 'active';
5604
+ }
5605
+ else if (lowercaseStatus === 'closed') {
5606
+ lowercaseStatus = 'done';
5607
+ }
5608
+ let response = undefined;
5609
+ if (lowercaseStatus === 'active') {
5610
+ //
5611
+ // {
5612
+ // "code": "200000",
5613
+ // "data": {
5614
+ // "pageNumber": 1,
5615
+ // "pageSize": 50,
5616
+ // "totalNum": 1,
5617
+ // "totalPage": 1,
5618
+ // "items": [
5619
+ // {
5620
+ // "orderId": "426328635071352832",
5621
+ // "symbol": "ETH-USDT",
5622
+ // "orderType": "LIMIT",
5623
+ // "side": "BUY",
5624
+ // "size": "0.001",
5625
+ // "price": "1000",
5626
+ // "timeInForce": "GTC",
5627
+ // "tags": "partner:ccxt",
5628
+ // "orderTime": 1774457869404794617,
5629
+ // "stp": "",
5630
+ // "cancelAfter": null,
5631
+ // "postOnly": false,
5632
+ // "reduceOnly": false,
5633
+ // "triggerDirection": "",
5634
+ // "triggerPrice": "",
5635
+ // "triggerPriceType": "",
5636
+ // "tpTriggerPrice": "",
5637
+ // "tpTriggerPriceType": "",
5638
+ // "slTriggerPrice": "",
5639
+ // "slTriggerPriceType": "",
5640
+ // "filledSize": "0",
5641
+ // "avgPrice": "0",
5642
+ // "fee": "0",
5643
+ // "feeCurrency": "USDT",
5644
+ // "tax": "0",
5645
+ // "updatedTime": 1774457869469028819,
5646
+ // "triggerOrderId": "",
5647
+ // "cancelReason": "",
5648
+ // "cancelSize": "0",
5649
+ // "clientOid": "708987d5-c346-487a-a70c-ea267377b0ca",
5650
+ // "sizeUnit": "BASECCY",
5651
+ // "status": 2
5652
+ // }
5653
+ // ],
5654
+ // "tradeType": "SPOT"
5655
+ // }
5656
+ // }
5657
+ //
5658
+ response = await this.utaPrivateGetAccountModeOrderOpenList(this.extend(request, params));
5659
+ }
5660
+ else {
5661
+ response = await this.utaPrivateGetAccountModeOrderHistory(this.extend(request, params));
5662
+ }
5663
+ const data = this.safeDict(response, 'data', {});
5664
+ const orders = this.safeList(data, 'items', []);
5665
+ return this.parseOrders(orders, market, since, limit);
5666
+ }
5069
5667
  /**
5070
5668
  * @method
5071
5669
  * @name kucoin#fetchClosedOrders
@@ -5076,6 +5674,7 @@ export default class kucoin extends Exchange {
5076
5674
  * @see https://www.kucoin.com/docs-new/rest/futures-trading/orders/get-stop-order-list
5077
5675
  * @see https://www.kucoin.com/docs-new/rest/margin-trading/orders/get-open-orders
5078
5676
  * @see https://www.kucoin.com/docs-new/rest/margin-trading/orders/get-closed-orders
5677
+ * @see https://www.kucoin.com/docs-new/rest/ua/get-order-history
5079
5678
  * @param {string} symbol unified market symbol of the market orders were made in
5080
5679
  * @param {int} [since] the earliest time in ms to fetch orders for
5081
5680
  * @param {int} [limit] the maximum number of order structures to retrieve
@@ -5109,6 +5708,7 @@ export default class kucoin extends Exchange {
5109
5708
  * @see https://www.kucoin.com/docs-new/rest/margin-trading/orders/get-open-orders
5110
5709
  * @see https://www.kucoin.com/docs-new/rest/margin-trading/orders/get-closed-orders
5111
5710
  * @see https://www.kucoin.com/docs-new/rest/margin-trading/orders/get-stop-order-list
5711
+ * @see https://www.kucoin.com/docs-new/rest/ua/get-open-order-list
5112
5712
  * @param {string} symbol unified market symbol
5113
5713
  * @param {int} [since] the earliest time in ms to fetch open orders for
5114
5714
  * @param {int} [limit] the maximum number of open orders structures to retrieve
@@ -5147,15 +5747,23 @@ export default class kucoin extends Exchange {
5147
5747
  * @see https://www.kucoin.com/docs-new/rest/margin-trading/orders/get-stop-order-by-clientoid
5148
5748
  * @see https://www.kucoin.com/docs-new/rest/futures-trading/orders/get-order-by-orderld
5149
5749
  * @see https://www.kucoin.com/docs-new/rest/futures-trading/get-stop-order-by-clientoid
5750
+ * @see https://www.kucoin.com/docs-new/rest/ua/get-order-details
5150
5751
  * @param {string} id order id
5151
5752
  * @param {string} symbol unified symbol of the market the order was made in
5152
5753
  * @param {object} [params] extra parameters specific to the exchange API endpoint
5153
5754
  * @param {string} [params.type] 'spot' or 'swap', used if symbol is not provided (default is 'spot')
5154
- * Check fetchSpotOrder() and fetchContractOrder() for more details on the extra parameters that can be used in params
5755
+ * @param {bool} [params.uta] true if fetching an order with uta endpoint (default is false)
5756
+ * Check fetchSpotOrder(), fetchContractOrder() and fetchUtaOrder() for more details on the extra parameters that can be used in params
5155
5757
  * @returns {object} An [order structure]{@link https://docs.ccxt.com/?id=order-structure}
5156
5758
  */
5157
5759
  async fetchOrder(id, symbol = undefined, params = {}) {
5158
5760
  await this.loadMarkets();
5761
+ let uta = await this.isUTAEnabled();
5762
+ [uta, params] = this.handleOptionAndParams(params, 'fetchOrder', 'uta', uta);
5763
+ if (uta) {
5764
+ params = this.omit(params, 'uta');
5765
+ return await this.fetchUtaOrder(id, symbol, params);
5766
+ }
5159
5767
  let marketType = undefined;
5160
5768
  if (symbol === undefined) {
5161
5769
  [marketType, params] = this.handleMarketTypeAndParams('fetchOrder', undefined, params);
@@ -5346,7 +5954,115 @@ export default class kucoin extends Exchange {
5346
5954
  const responseData = this.safeDict(response, 'data');
5347
5955
  return this.parseOrder(responseData, market);
5348
5956
  }
5957
+ /**
5958
+ * @method
5959
+ * @name kucoin#fetchUtaOrder
5960
+ * @description fetch uta order
5961
+ * @see https://www.kucoin.com/docs-new/rest/ua/get-order-details
5962
+ * @param {string} id order id
5963
+ * @param {string} symbol unified symbol of the market the order was made in
5964
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
5965
+ * @param {string} [params.accountMode] 'unified' or 'classic' (default is 'unified')
5966
+ * @param {string} [params.clientOrderId] client order id, required if id is not provided
5967
+ * @param {string} [params.marginMode] 'cross' or 'isolated', required if fetching a margin order
5968
+ * @returns {object} An [order structure]{@link https://docs.ccxt.com/?id=order-structure}
5969
+ */
5970
+ async fetchUtaOrder(id, symbol = undefined, params = {}) {
5971
+ if (symbol === undefined) {
5972
+ throw new ArgumentsRequired(this.id + ' fetchOrder() requires a symbol argument for uta orders');
5973
+ }
5974
+ const request = {};
5975
+ const clientOrderId = this.safeString2(params, 'clientOid', 'clientOrderId');
5976
+ if (clientOrderId !== undefined) {
5977
+ request['clientOid'] = clientOrderId;
5978
+ params = this.omit(params, ['clientOid', 'clientOrderId']);
5979
+ }
5980
+ else {
5981
+ if (id === undefined) {
5982
+ throw new ArgumentsRequired(this.id + ' fetchOrder() requires an id argument or clientOrderId parameter');
5983
+ }
5984
+ request['orderId'] = id;
5985
+ }
5986
+ await this.loadMarkets();
5987
+ const market = this.market(symbol);
5988
+ request['symbol'] = market['id'];
5989
+ let accountMode = 'unified';
5990
+ [accountMode, params] = this.handleOptionAndParams(params, 'fetchOrder', 'accountMode', accountMode);
5991
+ request['accountMode'] = accountMode;
5992
+ let marginMode = undefined;
5993
+ [marginMode, params] = this.handleMarginModeAndParams('fetchOrder', params);
5994
+ const tradeType = this.handleTradeType(market['contract'], marginMode, params);
5995
+ request['tradeType'] = tradeType;
5996
+ const response = await this.utaPrivateGetAccountModeOrderDetail(this.extend(request, params));
5997
+ //
5998
+ // {
5999
+ // "code": "200000",
6000
+ // "data": {
6001
+ // "orderId": "426319129738321920",
6002
+ // "symbol": "ETH-USDT",
6003
+ // "orderType": "LIMIT",
6004
+ // "side": "BUY",
6005
+ // "size": "0.001",
6006
+ // "price": "1000",
6007
+ // "timeInForce": "GTC",
6008
+ // "tags": "partner:ccxt",
6009
+ // "orderTime": 1774455603156417582,
6010
+ // "stp": "",
6011
+ // "cancelAfter": null,
6012
+ // "postOnly": false,
6013
+ // "reduceOnly": false,
6014
+ // "triggerDirection": "",
6015
+ // "triggerPrice": "",
6016
+ // "triggerPriceType": "",
6017
+ // "tpTriggerPrice": "",
6018
+ // "tpTriggerPriceType": "",
6019
+ // "slTriggerPrice": "",
6020
+ // "slTriggerPriceType": "",
6021
+ // "filledSize": "0",
6022
+ // "avgPrice": "0",
6023
+ // "fee": "0",
6024
+ // "feeCurrency": "USDT",
6025
+ // "tax": "0",
6026
+ // "updatedTime": 1774455603371523690,
6027
+ // "triggerOrderId": "",
6028
+ // "cancelReason": "",
6029
+ // "cancelSize": "0",
6030
+ // "clientOid": "b896c118-a674-4863-baf4-a9ea3cd696c5",
6031
+ // "sizeUnit": "BASECCY",
6032
+ // "tradeType": "SPOT",
6033
+ // "tradeId": "",
6034
+ // "status": 2
6035
+ // }
6036
+ // }
6037
+ //
6038
+ const data = this.safeDict(response, 'data', {});
6039
+ return this.parseOrder(data, market);
6040
+ }
6041
+ handleTradeType(isContractMarket = false, marginMode = undefined, params = {}) {
6042
+ let tradeType = this.safeString(params, 'tradeType');
6043
+ if (tradeType === undefined) {
6044
+ if (isContractMarket) {
6045
+ tradeType = 'FUTURES';
6046
+ }
6047
+ else if (marginMode !== undefined) {
6048
+ tradeType = marginMode.toUpperCase();
6049
+ }
6050
+ else {
6051
+ tradeType = 'SPOT';
6052
+ }
6053
+ }
6054
+ return tradeType;
6055
+ }
5349
6056
  parseOrder(order, market = undefined) {
6057
+ const tradeType = this.safeString(order, 'tradeType');
6058
+ const utaTradeTypes = ['SPOT', 'CROSS', 'ISOLATED', 'FUTURES']; // tradeType specific for uta endpoint
6059
+ let isUtaOrder = this.inArray(tradeType, utaTradeTypes);
6060
+ if ('sizeUnit' in order) { // property specific for uta endpoint
6061
+ isUtaOrder = true;
6062
+ }
6063
+ if (isUtaOrder) {
6064
+ return this.parseUtaOrder(order, market);
6065
+ }
5350
6066
  const marketId = this.safeString(order, 'symbol');
5351
6067
  market = this.safeMarket(marketId, market);
5352
6068
  if ((market !== undefined) && (market['contract'])) {
@@ -5671,6 +6387,128 @@ export default class kucoin extends Exchange {
5671
6387
  'trades': undefined,
5672
6388
  }, market);
5673
6389
  }
6390
+ parseUtaOrder(order, market = undefined) {
6391
+ //
6392
+ // createOrder
6393
+ // {
6394
+ // "orderId": "426319129738321920",
6395
+ // "tradeType": "SPOT",
6396
+ // "ts": 1774455603216000000,
6397
+ // "clientOid": "b896c118-a674-4863-baf4-a9ea3cd696c5"
6398
+ // }
6399
+ //
6400
+ // fetchOrder
6401
+ // {
6402
+ // "orderId": "426319129738321920",
6403
+ // "symbol": "ETH-USDT",
6404
+ // "orderType": "LIMIT",
6405
+ // "side": "BUY",
6406
+ // "size": "0.001",
6407
+ // "price": "1000",
6408
+ // "timeInForce": "GTC",
6409
+ // "tags": "partner:ccxt",
6410
+ // "orderTime": 1774455603156417582,
6411
+ // "stp": "",
6412
+ // "cancelAfter": null,
6413
+ // "postOnly": false,
6414
+ // "reduceOnly": false,
6415
+ // "triggerDirection": "",
6416
+ // "triggerPrice": "",
6417
+ // "triggerPriceType": "",
6418
+ // "tpTriggerPrice": "",
6419
+ // "tpTriggerPriceType": "",
6420
+ // "slTriggerPrice": "",
6421
+ // "slTriggerPriceType": "",
6422
+ // "filledSize": "0",
6423
+ // "avgPrice": "0",
6424
+ // "fee": "0",
6425
+ // "feeCurrency": "USDT",
6426
+ // "tax": "0",
6427
+ // "updatedTime": 1774455603371523690,
6428
+ // "triggerOrderId": "",
6429
+ // "cancelReason": "",
6430
+ // "cancelSize": "0",
6431
+ // "clientOid": "b896c118-a674-4863-baf4-a9ea3cd696c5",
6432
+ // "sizeUnit": "BASECCY",
6433
+ // "tradeType": "SPOT",
6434
+ // "tradeId": "",
6435
+ // "status": 2
6436
+ // }
6437
+ //
6438
+ const marketId = this.safeString(order, 'symbol');
6439
+ market = this.safeMarket(marketId, market);
6440
+ const symbol = market['symbol'];
6441
+ const timestamp = this.safeIntegerProduct2(order, 'orderTime', 'ts', 0.000001);
6442
+ const lastUpdateTimestamp = this.safeIntegerProduct(order, 'updatedTime', 0.000001);
6443
+ const rawTimeInForce = this.safeString(order, 'timeInForce');
6444
+ let amount = undefined;
6445
+ let cost = undefined;
6446
+ const sizeUnit = this.safeString(order, 'sizeUnit');
6447
+ const size = this.safeString(order, 'size');
6448
+ const rawStatus = this.safeString(order, 'status');
6449
+ const average = this.safeString(order, 'avgPrice');
6450
+ let filled = this.safeString(order, 'filledSize'); // might be in base or quote, need to check sizeUnit
6451
+ if ((sizeUnit === 'BASECCY') || (sizeUnit === 'UNIT')) {
6452
+ amount = size;
6453
+ }
6454
+ else {
6455
+ cost = filled;
6456
+ filled = Precise.stringDiv(filled, average);
6457
+ filled = this.amountToPrecision(symbol, filled);
6458
+ }
6459
+ const fee = {
6460
+ 'currency': this.safeCurrencyCode(this.safeString(order, 'feeCurrency')),
6461
+ 'cost': this.safeString(order, 'fee'),
6462
+ };
6463
+ return this.safeOrder({
6464
+ 'id': this.safeString(order, 'orderId'),
6465
+ 'clientOrderId': this.safeString(order, 'clientOid'),
6466
+ 'symbol': symbol,
6467
+ 'type': this.safeStringLower(order, 'orderType'),
6468
+ 'timeInForce': this.parseOrderTimeInForce(rawTimeInForce),
6469
+ 'postOnly': this.safeBool(order, 'postOnly'),
6470
+ 'reduceOnly': this.safeBool(order, 'reduceOnly'),
6471
+ 'side': this.safeStringLower(order, 'side'),
6472
+ 'amount': amount,
6473
+ 'price': this.safeString(order, 'price'),
6474
+ 'triggerPrice': this.safeString2(order, 'stopPrice', 'triggerPrice'),
6475
+ 'cost': cost,
6476
+ 'filled': filled,
6477
+ 'remaining': undefined,
6478
+ 'timestamp': timestamp,
6479
+ 'datetime': this.iso8601(timestamp),
6480
+ 'fee': fee,
6481
+ 'status': this.parseOrderStatus(rawStatus),
6482
+ 'lastTradeTimestamp': undefined,
6483
+ 'lastUpdateTimestamp': lastUpdateTimestamp,
6484
+ 'average': average,
6485
+ 'trades': undefined,
6486
+ 'stopLossPrice': this.safeString(order, 'slTriggerPrice'),
6487
+ 'takeProfitPrice': this.safeString(order, 'tpTriggerPrice'),
6488
+ 'info': order,
6489
+ }, market);
6490
+ }
6491
+ parseOrderTimeInForce(timeInForce) {
6492
+ const timeInForces = {
6493
+ 'GTC': 'GTC',
6494
+ 'IOC': 'IOC',
6495
+ 'FOK': 'FOK',
6496
+ 'GTT': 'GTD',
6497
+ };
6498
+ return this.safeString(timeInForces, timeInForce, timeInForce);
6499
+ }
6500
+ parseOrderStatus(status) {
6501
+ const statuses = {
6502
+ '0': 'open',
6503
+ '1': 'open',
6504
+ '2': 'open',
6505
+ '3': 'closed',
6506
+ '4': 'open',
6507
+ '5': 'canceled',
6508
+ '6': 'closed', // partial canceled
6509
+ };
6510
+ return this.safeString(statuses, status, status);
6511
+ }
5674
6512
  /**
5675
6513
  * @method
5676
6514
  * @name kucoin#fetchOrderTrades
@@ -5678,12 +6516,14 @@ export default class kucoin extends Exchange {
5678
6516
  * @see https://docs.kucoin.com/#list-fills
5679
6517
  * @see https://www.kucoin.com/docs-new/rest/futures-trading/orders/get-trade-history
5680
6518
  * @see https://www.kucoin.com/docs-new/rest/margin-trading/orders/get-trade-history
6519
+ * @see https://www.kucoin.com/docs-new/rest/ua/get-trade-history
5681
6520
  * @param {string} id order id
5682
6521
  * @param {string} symbol unified market symbol
5683
6522
  * @param {int} [since] the earliest time in ms to fetch trades for
5684
6523
  * @param {int} [limit] the maximum number of trades to retrieve
5685
6524
  * @param {object} [params] extra parameters specific to the exchange API endpoint
5686
6525
  * @param {string} [params.type] 'spot' or 'swap', used if symbol is not provided (default is 'spot')
6526
+ * @param {boolean} [params.uta] set to true if fetching trades from uta endpoint, default is false.
5687
6527
  * @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/?id=trade-structure}
5688
6528
  */
5689
6529
  async fetchOrderTrades(id, symbol = undefined, since = undefined, limit = undefined, params = {}) {
@@ -5697,6 +6537,7 @@ export default class kucoin extends Exchange {
5697
6537
  * @name kucoin#fetchMyTrades
5698
6538
  * @see https://www.kucoin.com/docs-new/rest/spot-trading/orders/get-trade-history
5699
6539
  * @see https://www.kucoin.com/docs-new/rest/margin-trading/orders/get-trade-history
6540
+ * @see https://www.kucoin.com/docs-new/rest/ua/get-trade-history
5700
6541
  * @description fetch all trades made by the user
5701
6542
  * @param {string} symbol unified market symbol
5702
6543
  * @param {int} [since] the earliest time in ms to fetch trades for
@@ -5715,6 +6556,12 @@ export default class kucoin extends Exchange {
5715
6556
  market = this.market(symbol);
5716
6557
  }
5717
6558
  [marketType, params] = this.handleMarketTypeAndParams('fetchMyTrades', market, params);
6559
+ let uta = await this.isUTAEnabled();
6560
+ [uta, params] = this.handleOptionAndParams(params, 'fetchMyTrades', 'uta', uta);
6561
+ if (uta) {
6562
+ params = this.extend(params, { 'marketType': marketType });
6563
+ return await this.fetchMyUtaTrades(symbol, since, limit, params);
6564
+ }
5718
6565
  if ((marketType === 'spot') || (marketType === 'margin')) {
5719
6566
  return await this.fetchMySpotTrades(symbol, since, limit, params);
5720
6567
  }
@@ -5931,57 +6778,144 @@ export default class kucoin extends Exchange {
5931
6778
  }
5932
6779
  /**
5933
6780
  * @method
5934
- * @name kucoin#fetchTrades
5935
- * @description get the list of most recent trades for a particular symbol
5936
- * @see https://www.kucoin.com/docs-new/rest/spot-trading/market-data/get-trade-history
5937
- * @see https://www.kucoin.com/docs-new/rest/ua/get-trades
5938
- * @see https://www.kucoin.com/docs-new/rest/futures-trading/market-data/get-trade-history
5939
- * @param {string} symbol unified symbol of the market to fetch trades for
5940
- * @param {int} [since] timestamp in ms of the earliest trade to fetch
5941
- * @param {int} [limit] the maximum amount of trades to fetch
6781
+ * @name kucoin#fetchMyUtaTrades
6782
+ * @see https://www.kucoin.com/docs-new/rest/ua/get-trade-history
6783
+ * @description fetch all trades made by the user
6784
+ * @param {string} symbol unified market symbol
6785
+ * @param {int} [since] the earliest time in ms to fetch trades for
6786
+ * @param {int} [limit] the maximum number of trades structures to retrieve (default is 50, max is 200)
5942
6787
  * @param {object} [params] extra parameters specific to the exchange API endpoint
5943
- * @param {boolean} [params.uta] set to true for the unified trading account (uta), defaults to false
5944
- * @returns {Trade[]} a list of [trade structures]{@link https://docs.ccxt.com/?id=public-trades}
6788
+ * @param {int} [params.until] the latest time in ms to fetch entries for
6789
+ * @param {string} [params.accountMode] 'unified' or 'classic', defaults to 'unified'
6790
+ * @param {string} [params.marginMode] 'cross' or 'isolated', only for margin trades
6791
+ * @param {string} [params.side] 'BUY' or 'SELL' (both if not provided)
6792
+ * @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)
6793
+ * @returns {Trade[]} a list of [trade structures]{@link https://docs.ccxt.com/?id=trade-structure}
5945
6794
  */
5946
- async fetchTrades(symbol, since = undefined, limit = undefined, params = {}) {
6795
+ async fetchMyUtaTrades(symbol = undefined, since = undefined, limit = undefined, params = {}) {
5947
6796
  await this.loadMarkets();
5948
- const market = this.market(symbol);
5949
- const request = {
5950
- 'symbol': market['id'],
5951
- };
5952
- // pagination is not supported on the exchange side anymore
5953
- // if (since !== undefined) {
5954
- // request['startAt'] = Math.floor (since / 1000);
5955
- // }
5956
- // if (limit !== undefined) {
5957
- // request['pageSize'] = limit;
5958
- // }
5959
- let uta = undefined;
5960
- [uta, params] = this.handleOptionAndParams(params, 'fetchTrades', 'uta', false);
5961
- let response = undefined;
5962
- let trades = undefined;
5963
- let type = undefined;
5964
- [type, params] = this.handleMarketTypeAndParams('fetchTrades', market, params);
5965
- if (uta) {
5966
- if ((type === 'spot') || (type === 'margin')) {
5967
- request['tradeType'] = 'SPOT';
5968
- }
5969
- else {
5970
- request['tradeType'] = 'FUTURES';
5971
- }
5972
- response = await this.utaGetMarketTrade(this.extend(request, params));
5973
- //
5974
- // {
5975
- // "code": "200000",
5976
- // "data": {
5977
- // "tradeType": "SPOT",
5978
- // "list": [
5979
- // {
5980
- // "sequence": "18746044393340932",
5981
- // "tradeId": "18746044393340932",
5982
- // "price": "104355.6",
5983
- // "size": "0.00011886",
5984
- // "side": "sell",
6797
+ let paginate = false;
6798
+ [paginate, params] = this.handleOptionAndParams(params, 'fetchMyTrades', 'paginate');
6799
+ if (paginate) {
6800
+ return await this.fetchPaginatedCallDynamic('fetchMyTrades', symbol, since, limit, params);
6801
+ }
6802
+ const marketType = this.safeString(params, 'marketType');
6803
+ if (marketType !== undefined) {
6804
+ params = this.omit(params, 'marketType');
6805
+ }
6806
+ let request = {};
6807
+ let isContract = false;
6808
+ let market = undefined;
6809
+ if (symbol !== undefined) {
6810
+ market = this.market(symbol);
6811
+ request['symbol'] = market['id'];
6812
+ isContract = market['contract'];
6813
+ }
6814
+ else if ((marketType === 'spot') || (marketType === 'margin')) {
6815
+ throw new ArgumentsRequired(this.id + ' fetchMyTrades() requires a symbol parameter for uta spot or margin trades');
6816
+ }
6817
+ else {
6818
+ isContract = true;
6819
+ }
6820
+ let marginMode = undefined;
6821
+ [marginMode, params] = this.handleMarginModeAndParams('fetchMyTrades', params);
6822
+ const tradeType = this.handleTradeType(isContract, marginMode, params);
6823
+ request['tradeType'] = tradeType;
6824
+ let accountMode = 'unified';
6825
+ [accountMode, params] = this.handleOptionAndParams(params, 'fetchMyTrades', 'accountMode', accountMode);
6826
+ request['accountMode'] = accountMode;
6827
+ if (since !== undefined) {
6828
+ request['startAt'] = since;
6829
+ }
6830
+ if (limit !== undefined) {
6831
+ request['pageSize'] = limit;
6832
+ }
6833
+ [request, params] = this.handleUntilOption('endAt', request, params);
6834
+ const response = await this.utaPrivateGetAccountModeOrderExecution(this.extend(request, params));
6835
+ //
6836
+ // {
6837
+ // "code": "200000",
6838
+ // "data": {
6839
+ // "tradeType": "FUTURES",
6840
+ // "lastId": 30000000000531982,
6841
+ // "items": [
6842
+ // {
6843
+ // "orderId": "426373228194254848",
6844
+ // "symbol": "DOGEUSDTM",
6845
+ // "orderType": "MARKET",
6846
+ // "side": "BUY",
6847
+ // "tradeId": "1711108516570",
6848
+ // "size": "1",
6849
+ // "price": "0.09641",
6850
+ // "value": "9.641",
6851
+ // "executionTime": 1774468501294000000,
6852
+ // "fee": "0.0057846",
6853
+ // "feeCurrency": "USDT",
6854
+ // "tax": "",
6855
+ // "liquidityRole": "TAKER",
6856
+ // "fillType": "NORMAL"
6857
+ // }
6858
+ // ]
6859
+ // }
6860
+ // }
6861
+ //
6862
+ const data = this.safeDict(response, 'data', {});
6863
+ const trades = this.safeList(data, 'items', []);
6864
+ return this.parseTrades(trades, market, since, limit);
6865
+ }
6866
+ /**
6867
+ * @method
6868
+ * @name kucoin#fetchTrades
6869
+ * @description get the list of most recent trades for a particular symbol
6870
+ * @see https://www.kucoin.com/docs-new/rest/spot-trading/market-data/get-trade-history
6871
+ * @see https://www.kucoin.com/docs-new/rest/ua/get-trades
6872
+ * @see https://www.kucoin.com/docs-new/rest/futures-trading/market-data/get-trade-history
6873
+ * @param {string} symbol unified symbol of the market to fetch trades for
6874
+ * @param {int} [since] timestamp in ms of the earliest trade to fetch
6875
+ * @param {int} [limit] the maximum amount of trades to fetch
6876
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
6877
+ * @param {boolean} [params.uta] set to true for the unified trading account (uta), defaults to false
6878
+ * @returns {Trade[]} a list of [trade structures]{@link https://docs.ccxt.com/?id=public-trades}
6879
+ */
6880
+ async fetchTrades(symbol, since = undefined, limit = undefined, params = {}) {
6881
+ await this.loadMarkets();
6882
+ const market = this.market(symbol);
6883
+ const request = {
6884
+ 'symbol': market['id'],
6885
+ };
6886
+ // pagination is not supported on the exchange side anymore
6887
+ // if (since !== undefined) {
6888
+ // request['startAt'] = Math.floor (since / 1000);
6889
+ // }
6890
+ // if (limit !== undefined) {
6891
+ // request['pageSize'] = limit;
6892
+ // }
6893
+ let uta = false;
6894
+ [uta, params] = this.handleOptionAndParams(params, 'fetchTrades', 'uta', uta);
6895
+ let response = undefined;
6896
+ let trades = undefined;
6897
+ let type = undefined;
6898
+ [type, params] = this.handleMarketTypeAndParams('fetchTrades', market, params);
6899
+ if (uta) {
6900
+ if ((type === 'spot') || (type === 'margin')) {
6901
+ request['tradeType'] = 'SPOT';
6902
+ }
6903
+ else {
6904
+ request['tradeType'] = 'FUTURES';
6905
+ }
6906
+ response = await this.utaGetMarketTrade(this.extend(request, params));
6907
+ //
6908
+ // {
6909
+ // "code": "200000",
6910
+ // "data": {
6911
+ // "tradeType": "SPOT",
6912
+ // "list": [
6913
+ // {
6914
+ // "sequence": "18746044393340932",
6915
+ // "tradeId": "18746044393340932",
6916
+ // "price": "104355.6",
6917
+ // "size": "0.00011886",
6918
+ // "side": "sell",
5985
6919
  // "ts": 1762242540829000000
5986
6920
  // },
5987
6921
  // ]
@@ -6033,6 +6967,9 @@ export default class kucoin extends Exchange {
6033
6967
  return this.parseTrades(trades, market, since, limit);
6034
6968
  }
6035
6969
  parseTrade(trade, market = undefined) {
6970
+ if ('liquidityRole' in trade) { // property specific to myTrades from uta endpoint
6971
+ return this.parseMyUtaTrade(trade, market);
6972
+ }
6036
6973
  const marketId = this.safeString(trade, 'symbol');
6037
6974
  market = this.safeMarket(marketId, market);
6038
6975
  if ((market === undefined) || (market['spot'])) {
@@ -6319,23 +7256,97 @@ export default class kucoin extends Exchange {
6319
7256
  'fee': fee,
6320
7257
  }, market);
6321
7258
  }
7259
+ parseMyUtaTrade(trade, market = undefined) {
7260
+ //
7261
+ // {
7262
+ // "orderId": "426373228194254848",
7263
+ // "symbol": "DOGEUSDTM",
7264
+ // "orderType": "MARKET",
7265
+ // "side": "BUY",
7266
+ // "tradeId": "1711108516570",
7267
+ // "size": "1",
7268
+ // "price": "0.09641",
7269
+ // "value": "9.641",
7270
+ // "executionTime": 1774468501294000000,
7271
+ // "fee": "0.0057846",
7272
+ // "feeCurrency": "USDT",
7273
+ // "tax": "",
7274
+ // "liquidityRole": "TAKER",
7275
+ // "fillType": "NORMAL"
7276
+ // }
7277
+ //
7278
+ const marketId = this.safeString(trade, 'symbol');
7279
+ market = this.safeMarket(marketId, market);
7280
+ const timestamp = this.safeIntegerProduct(trade, 'executionTime', 0.000001);
7281
+ const fee = {
7282
+ 'cost': this.safeString(trade, 'fee'),
7283
+ 'currency': this.safeCurrencyCode(this.safeString(trade, 'feeCurrency')),
7284
+ };
7285
+ return this.safeTrade({
7286
+ 'info': trade,
7287
+ 'id': this.safeString(trade, 'tradeId'),
7288
+ 'order': this.safeString(trade, 'orderId'),
7289
+ 'timestamp': timestamp,
7290
+ 'datetime': this.iso8601(timestamp),
7291
+ 'symbol': market['symbol'],
7292
+ 'type': this.safeStringLower(trade, 'orderType'),
7293
+ 'takerOrMaker': this.safeStringLower(trade, 'liquidityRole'),
7294
+ 'side': this.safeStringLower(trade, 'side'),
7295
+ 'price': this.safeString(trade, 'price'),
7296
+ 'amount': this.safeString(trade, 'size'),
7297
+ 'cost': this.safeString(trade, 'value'),
7298
+ 'fee': fee,
7299
+ }, market);
7300
+ }
6322
7301
  /**
6323
7302
  * @method
6324
7303
  * @name kucoin#fetchTradingFee
6325
7304
  * @description fetch the trading fees for a market
6326
7305
  * @see https://www.kucoin.com/docs-new/rest/account-info/trade-fee/get-actual-fee-spot-margin
6327
7306
  * @see https://www.kucoin.com/docs-new/rest/account-info/trade-fee/get-actual-fee-futures
7307
+ * @see https://www.kucoin.com/docs-new/rest/ua/get-actual-fee
6328
7308
  * @param {string} symbol unified market symbol
6329
7309
  * @param {object} [params] extra parameters specific to the exchange API endpoint
7310
+ * @param {boolean} [params.uta] set to true for the unified trading account (uta) endpoint, defaults to false
6330
7311
  * @returns {object} a [fee structure]{@link https://docs.ccxt.com/?id=fee-structure}
6331
7312
  */
6332
7313
  async fetchTradingFee(symbol, params = {}) {
6333
7314
  await this.loadMarkets();
6334
7315
  const market = this.market(symbol);
7316
+ let uta = await this.isUTAEnabled();
7317
+ [uta, params] = this.handleOptionAndParams(params, 'fetchTradingFee', 'uta', uta);
6335
7318
  const request = {};
6336
7319
  let response = undefined;
6337
7320
  let entry = undefined;
6338
- if (market['spot']) {
7321
+ if (uta) {
7322
+ if (market['spot']) {
7323
+ request['tradeType'] = 'SPOT';
7324
+ }
7325
+ else {
7326
+ request['tradeType'] = 'FUTURES';
7327
+ }
7328
+ request['symbol'] = market['id'];
7329
+ response = await this.utaPrivateGetUserFeeRate(this.extend(request, params));
7330
+ //
7331
+ // {
7332
+ // "code": "200000",
7333
+ // "data": {
7334
+ // "tradeType": "SPOT",
7335
+ // "list": [
7336
+ // {
7337
+ // "symbol": "ETH-USDT",
7338
+ // "takerFeeRate": "0.001",
7339
+ // "makerFeeRate": "0.001"
7340
+ // }
7341
+ // ]
7342
+ // }
7343
+ // }
7344
+ //
7345
+ const data = this.safeDict(response, 'data', {});
7346
+ const dataList = this.safeList(data, 'list', []);
7347
+ entry = this.safeDict(dataList, 0);
7348
+ }
7349
+ else if (market['spot']) {
6339
7350
  request['symbols'] = market['id'];
6340
7351
  response = await this.privateGetTradeFees(this.extend(request, params));
6341
7352
  //
@@ -6411,7 +7422,7 @@ export default class kucoin extends Exchange {
6411
7422
  let networkCode = undefined;
6412
7423
  [networkCode, params] = this.handleNetworkCodeAndParams(params);
6413
7424
  if (networkCode !== undefined) {
6414
- request['chain'] = this.networkCodeToId(networkCode).toLowerCase();
7425
+ request['chain'] = this.networkCodeToId(networkCode, currency['code']).toLowerCase();
6415
7426
  }
6416
7427
  request['amount'] = parseFloat(this.currencyToPrecision(code, amount, networkCode));
6417
7428
  let includeFee = undefined;
@@ -6532,12 +7543,13 @@ export default class kucoin extends Exchange {
6532
7543
  }
6533
7544
  const internal = this.safeBool(transaction, 'isInner');
6534
7545
  const tag = this.safeString(transaction, 'memo');
7546
+ const chainId = this.safeString(transaction, 'chain');
6535
7547
  return {
6536
7548
  'info': transaction,
6537
7549
  'id': this.safeString2(transaction, 'id', 'withdrawalId'),
6538
7550
  'timestamp': timestamp,
6539
7551
  'datetime': this.iso8601(timestamp),
6540
- 'network': this.networkIdToCode(this.safeString(transaction, 'chain')),
7552
+ 'network': this.networkIdToCode(chainId, code),
6541
7553
  'address': address,
6542
7554
  'addressTo': address,
6543
7555
  'addressFrom': undefined,
@@ -6729,10 +7741,11 @@ export default class kucoin extends Exchange {
6729
7741
  if (accountType === 'contract') {
6730
7742
  return await this.fetchContractWithdrawals(code, since, limit, params);
6731
7743
  }
7744
+ const maxLimit = 500;
6732
7745
  let paginate = false;
6733
7746
  [paginate, params] = this.handleOptionAndParams(params, 'fetchWithdrawals', 'paginate');
6734
7747
  if (paginate) {
6735
- return await this.fetchPaginatedCallDynamic('fetchWithdrawals', code, since, limit, params);
7748
+ return await this.fetchPaginatedCallDynamic('fetchWithdrawals', code, since, limit, params, maxLimit);
6736
7749
  }
6737
7750
  let request = {};
6738
7751
  let currency = undefined;
@@ -6872,14 +7885,24 @@ export default class kucoin extends Exchange {
6872
7885
  * @see https://www.kucoin.com/docs-new/rest/account-info/account-funding/get-account-cross-margin
6873
7886
  * @see https://www.kucoin.com/docs-new/rest/account-info/account-funding/get-account-isolated-margin
6874
7887
  * @see https://www.kucoin.com/docs-new/rest/account-info/account-funding/get-account-futures
7888
+ * @see https://www.kucoin.com/docs-new/rest/ua/get-account-currency-assets-uta
7889
+ * @see https://www.kucoin.com/docs-new/rest/ua/get-account-currency-assets-classic
6875
7890
  * @param {object} [params] extra parameters specific to the exchange API endpoint
6876
7891
  * @param {object} [params.marginMode] 'cross' or 'isolated', margin type for fetching margin balance
6877
7892
  * @param {object} [params.type] extra parameters specific to the exchange API endpoint
6878
7893
  * @param {object} [params.hf] *default if false* if true, the result includes the balance of the high frequency account
7894
+ * @param {boolean} [params.uta] set to true for the unified trading account (uta) endpoint, defaults to false
6879
7895
  * @returns {object} a [balance structure]{@link https://docs.ccxt.com/?id=balance-structure}
6880
7896
  */
6881
7897
  async fetchBalance(params = {}) {
6882
7898
  await this.loadMarkets();
7899
+ let uta = await this.isUTAEnabled();
7900
+ [uta, params] = this.handleOptionAndParams(params, 'fetchBalance', 'uta', uta);
7901
+ if (uta) {
7902
+ return await this.fetchUtaBalance(params);
7903
+ }
7904
+ let response = undefined;
7905
+ const request = {};
6883
7906
  const code = this.safeString(params, 'code');
6884
7907
  let currency = undefined;
6885
7908
  if (code !== undefined) {
@@ -6898,26 +7921,25 @@ export default class kucoin extends Exchange {
6898
7921
  if (hf && (type !== 'main')) {
6899
7922
  type = 'trade_hf';
6900
7923
  }
6901
- const [marginMode, query] = this.handleMarginModeAndParams('fetchBalance', params);
6902
- let response = undefined;
6903
- const request = {};
7924
+ let marginMode = undefined;
7925
+ [marginMode, params] = this.handleMarginModeAndParams('fetchBalance', params);
6904
7926
  const isolated = (marginMode === 'isolated') || (type === 'isolated');
6905
7927
  const cross = (marginMode === 'cross') || (type === 'margin');
6906
7928
  if (isolated) {
6907
7929
  if (currency !== undefined) {
6908
7930
  request['balanceCurrency'] = currency['id'];
6909
7931
  }
6910
- response = await this.privateGetIsolatedAccounts(this.extend(request, query));
7932
+ response = await this.privateGetIsolatedAccounts(this.extend(request, params));
6911
7933
  }
6912
7934
  else if (cross) {
6913
- response = await this.privateGetMarginAccount(this.extend(request, query));
7935
+ response = await this.privateGetMarginAccount(this.extend(request, params));
6914
7936
  }
6915
7937
  else {
6916
7938
  if (currency !== undefined) {
6917
7939
  request['currency'] = currency['id'];
6918
7940
  }
6919
7941
  request['type'] = type;
6920
- response = await this.privateGetAccounts(this.extend(request, query));
7942
+ response = await this.privateGetAccounts(this.extend(request, params));
6921
7943
  }
6922
7944
  //
6923
7945
  // Spot
@@ -7101,11 +8123,260 @@ export default class kucoin extends Exchange {
7101
8123
  result[currencyCode] = account;
7102
8124
  return this.safeBalance(result);
7103
8125
  }
8126
+ /**
8127
+ * @method
8128
+ * @name kucoin#fetchUtaBalance
8129
+ * @description helper method for fetching balance with unified trading account (uta) endpoint
8130
+ * @see https://www.kucoin.com/docs-new/rest/ua/get-account-currency-assets-uta
8131
+ * @see https://www.kucoin.com/docs-new/rest/ua/get-account-currency-assets-classic
8132
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
8133
+ * @param {string} [params.type] 'spot', 'unified', 'funding', 'cross', 'isolated' or 'swap' (default is 'spot')
8134
+ * @param {string} [params.marginMode] 'cross' or 'isolated', margin type for fetching margin balance, only applicable if type is margin (default is cross)
8135
+ * @returns {object} a [balance structure]{@link https://docs.ccxt.com/?id=balance-structure}
8136
+ */
8137
+ async fetchUtaBalance(params = {}) {
8138
+ await this.loadMarkets();
8139
+ let requestedType = undefined;
8140
+ [requestedType, params] = this.handleMarketTypeAndParams('fetchUtaBalance', undefined, params);
8141
+ if (requestedType === 'margin') {
8142
+ // assume cross margin if margin is specified but marginMode is not specified
8143
+ let marginMode = 'cross';
8144
+ [marginMode, params] = this.handleMarginModeAndParams('fetchUtaBalance', params, marginMode);
8145
+ requestedType = marginMode;
8146
+ }
8147
+ const utaAccountsByType = this.safeDict(this.options, 'utaAccountsByType', {});
8148
+ let type = undefined;
8149
+ type = this.safeString(utaAccountsByType, requestedType, type);
8150
+ const isIsolated = (type === 'ISOLATED');
8151
+ const request = {};
8152
+ let response = undefined;
8153
+ if (type === 'unified') {
8154
+ request['accountMode'] = type;
8155
+ // uta
8156
+ // {
8157
+ // "code": "200000",
8158
+ // "data": {
8159
+ // "accountType": "UNIFIED",
8160
+ // "ts": 1764731696945,
8161
+ // "accounts": [
8162
+ // {
8163
+ // "currencies": [
8164
+ // {
8165
+ // "currency": "USDT",
8166
+ // "equity": "97.9936711985",
8167
+ // "hold": "0.0000000000",
8168
+ // "balance": "97.9936711985",
8169
+ // "available": "97.9936711985",
8170
+ // "liability": "0.0000000000"
8171
+ // },
8172
+ // {
8173
+ // "currency": "BTC",
8174
+ // "equity": "0.0000216000",
8175
+ // "hold": "0.0000000000",
8176
+ // "balance": "0.0000216000",
8177
+ // "available": "0.0000216000",
8178
+ // "liability": "0.0000000000"
8179
+ // }
8180
+ // ]
8181
+ // }
8182
+ // ]
8183
+ // }
8184
+ // }
8185
+ //
8186
+ response = await this.utaPrivateGetAccountModeAccountBalance(this.extend(request, params));
8187
+ }
8188
+ else {
8189
+ request['accountType'] = type;
8190
+ //
8191
+ // isolated
8192
+ // {
8193
+ // "code": "200000",
8194
+ // "data": {
8195
+ // "accountType": "ISOLATED",
8196
+ // "ts": 1774244660519,
8197
+ // "accounts": [
8198
+ // {
8199
+ // "accountSubtype": "LTC-USDT",
8200
+ // "riskRatio": "0",
8201
+ // "currencies": [
8202
+ // {
8203
+ // "currency": "LTC",
8204
+ // "hold": "0",
8205
+ // "available": "0",
8206
+ // "liability": "0",
8207
+ // "balance": "0",
8208
+ // "equity": "0"},{
8209
+ // "currency": "USDT",
8210
+ // "hold": "0",
8211
+ // "available": "6",
8212
+ // "liability": "0",
8213
+ // "balance": "6",
8214
+ // "equity": "6"
8215
+ // }
8216
+ // ]
8217
+ // }
8218
+ // ]
8219
+ // }
8220
+ // }
8221
+ //
8222
+ response = await this.utaPrivateGetAccountBalance(this.extend(request, params));
8223
+ }
8224
+ const data = this.safeDict(response, 'data', {});
8225
+ const timestamp = this.safeInteger(data, 'ts');
8226
+ const result = {
8227
+ 'info': response,
8228
+ 'timestamp': timestamp,
8229
+ 'datetime': this.iso8601(timestamp),
8230
+ };
8231
+ const accounts = this.safeList(data, 'accounts', []);
8232
+ if (isIsolated) {
8233
+ for (let i = 0; i < accounts.length; i++) {
8234
+ const entry = accounts[i];
8235
+ const marketId = this.safeString(entry, 'accountSubtype');
8236
+ const symbol = this.safeSymbol(marketId, undefined, '-');
8237
+ const subResult = {};
8238
+ const currencies = this.safeList(entry, 'currencies', []);
8239
+ for (let j = 0; j < currencies.length; j++) {
8240
+ const currencyEntry = this.safeDict(currencies, j, {});
8241
+ const currencyId = this.safeString(currencyEntry, 'currency');
8242
+ const currencyCode = this.safeCurrencyCode(currencyId);
8243
+ subResult[currencyCode] = this.parseBalanceHelper(currencyEntry);
8244
+ }
8245
+ result[symbol] = this.safeBalance(subResult);
8246
+ }
8247
+ }
8248
+ else {
8249
+ const firstAccount = this.safeDict(accounts, 0, {});
8250
+ const currencies = this.safeList(firstAccount, 'currencies', []);
8251
+ for (let i = 0; i < currencies.length; i++) {
8252
+ const currencyEntry = this.safeDict(currencies, i, {});
8253
+ const currencyId = this.safeString(currencyEntry, 'currency');
8254
+ const currencyCode = this.safeCurrencyCode(currencyId);
8255
+ result[currencyCode] = this.parseBalanceHelper(currencyEntry);
8256
+ }
8257
+ }
8258
+ let returnType = result;
8259
+ if (!isIsolated) {
8260
+ returnType = this.safeBalance(result);
8261
+ }
8262
+ return returnType;
8263
+ }
7104
8264
  /**
7105
8265
  * @method
7106
8266
  * @name kucoin#transfer
7107
8267
  * @description transfer currency internally between wallets on the same account
7108
8268
  * @see https://www.kucoin.com/docs-new/rest/account-info/transfer/flex-transfer?lang=en_US&
8269
+ * @see https://www.kucoin.com/docs-new/rest/ua/flex-transfer
8270
+ * @param {string} code unified currency code
8271
+ * @param {float} amount amount to transfer
8272
+ * @param {string} fromAccount account to transfer from
8273
+ * @param {string} toAccount account to transfer to
8274
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
8275
+ * @param {boolean} [params.uta] set to true for the unified trading account (uta) endpoint, defaults to false
8276
+ * Check transferClassic() and transferUta() for more details on params
8277
+ * @returns {object} a [transfer structure]{@link https://docs.ccxt.com/?id=transfer-structure}
8278
+ */
8279
+ async transfer(code, amount, fromAccount, toAccount, params = {}) {
8280
+ await this.loadMarkets();
8281
+ let uta = await this.isUTAEnabled();
8282
+ [uta, params] = this.handleOptionAndParams(params, 'transfer', 'uta', uta);
8283
+ if (uta) {
8284
+ return await this.transferUta(code, amount, fromAccount, toAccount, params);
8285
+ }
8286
+ return await this.transferClassic(code, amount, fromAccount, toAccount, params);
8287
+ }
8288
+ /**
8289
+ * @method
8290
+ * @name kucoin#transferUta
8291
+ * @description transfer currency internally between wallets on the same account with uta endpoint
8292
+ * @see https://www.kucoin.com/docs-new/rest/ua/flex-transfer
8293
+ * @param {string} code unified currency code
8294
+ * @param {float} amount amount to transfer
8295
+ * @param {string} fromAccount account to transfer from
8296
+ * @param {string} toAccount account to transfer to
8297
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
8298
+ * @param {string} [params.transferType] INTERNAL, PARENT_TO_SUB, SUB_TO_PARENT, SUB_TO_SUB (default is INTERNAL)
8299
+ * @param {string} [params.fromUserId] required if transferType is SUB_TO_PARENT or SUB_TO_SUB
8300
+ * @param {string} [params.toUserId] required if transferType is PARENT_TO_SUB or SUB_TO_SUB
8301
+ * @returns {object} a [transfer structure]{@link https://docs.ccxt.com/?id=transfer-structure}
8302
+ */
8303
+ async transferUta(code, amount, fromAccount, toAccount, params = {}) {
8304
+ await this.loadMarkets();
8305
+ const currency = this.currency(code);
8306
+ const requestedAmount = this.currencyToPrecision(code, amount);
8307
+ const request = {
8308
+ 'currency': currency['id'],
8309
+ 'amount': requestedAmount,
8310
+ };
8311
+ let transferType = 'INTERNAL';
8312
+ [transferType, params] = this.handleParamString2(params, 'transferType', 'type', transferType);
8313
+ let fromUserId = undefined;
8314
+ [fromUserId, params] = this.handleParamString2(params, 'fromUserId', 'fromUid', fromUserId);
8315
+ let toUserId = undefined;
8316
+ [toUserId, params] = this.handleParamString2(params, 'toUserId', 'toUid', toUserId);
8317
+ if (transferType === 'PARENT_TO_SUB' || transferType === 'SUB_TO_SUB') {
8318
+ if (toUserId === undefined) {
8319
+ throw new ExchangeError(this.id + ' transfer() requires a toUserId param for PARENT_TO_SUB or SUB_TO_SUB transfers');
8320
+ }
8321
+ else {
8322
+ request['toUid'] = toUserId;
8323
+ }
8324
+ }
8325
+ else if (transferType === 'SUB_TO_PARENT' || transferType === 'SUB_TO_SUB') {
8326
+ if (fromUserId === undefined) {
8327
+ throw new ExchangeError(this.id + ' transfer() requires a fromUserId param for SUB_TO_PARENT or SUB_TO_SUB transfers');
8328
+ }
8329
+ else {
8330
+ request['fromUid'] = fromUserId;
8331
+ }
8332
+ }
8333
+ let clientOid = this.uuid();
8334
+ [clientOid, params] = this.handleParamString2(params, 'clientOid', 'clientOrderId', clientOid);
8335
+ request['clientOid'] = clientOid;
8336
+ let fromId = this.convertTypeToAccount(fromAccount);
8337
+ let toId = this.convertTypeToAccount(toAccount);
8338
+ const fromIsolated = this.inArray(fromId, this.ids);
8339
+ const toIsolated = this.inArray(toId, this.ids);
8340
+ if (fromIsolated) {
8341
+ request['fromAccountSymbol'] = fromId;
8342
+ fromId = 'ISOLATED';
8343
+ }
8344
+ if (toIsolated) {
8345
+ request['toAccountSymbol'] = toId;
8346
+ toId = 'ISOLATED';
8347
+ }
8348
+ const utaAccountsByType = this.safeDict(this.options, 'utaAccountsByType', {});
8349
+ fromId = this.safeString(utaAccountsByType, fromId, fromId);
8350
+ toId = this.safeString(utaAccountsByType, toId, toId);
8351
+ request['fromAccountType'] = fromId.toUpperCase();
8352
+ request['toAccountType'] = toId.toUpperCase();
8353
+ const types = {
8354
+ 'INTERNAL': '0',
8355
+ 'PARENT_TO_SUB': '1',
8356
+ 'SUB_TO_PARENT': '2',
8357
+ 'SUB_TO_SUB': '3',
8358
+ };
8359
+ request['type'] = this.safeString(types, transferType, transferType);
8360
+ const response = await this.utaPrivatePostAccountTransfer(this.extend(request, params));
8361
+ //
8362
+ //
8363
+ const data = this.safeDict(response, 'data');
8364
+ const transfer = this.parseTransfer(data, currency);
8365
+ const transferOptions = this.safeDict(this.options, 'transfer', {});
8366
+ const fillResponseFromRequest = this.safeBool(transferOptions, 'fillResponseFromRequest', true);
8367
+ if (fillResponseFromRequest) {
8368
+ transfer['amount'] = amount;
8369
+ transfer['fromAccount'] = fromAccount;
8370
+ transfer['toAccount'] = toAccount;
8371
+ transfer['status'] = 'ok';
8372
+ }
8373
+ return transfer;
8374
+ }
8375
+ /**
8376
+ * @method
8377
+ * @name kucoin#transferClassic
8378
+ * @description transfer currency internally between wallets on the same account with classic endpoints
8379
+ * @see https://www.kucoin.com/docs-new/rest/account-info/transfer/flex-transfer?lang=en_US&
7109
8380
  * @param {string} code unified currency code
7110
8381
  * @param {float} amount amount to transfer
7111
8382
  * @param {string} fromAccount account to transfer from
@@ -7116,7 +8387,7 @@ export default class kucoin extends Exchange {
7116
8387
  * @param {string} [params.toUserId] required if transferType is PARENT_TO_SUB
7117
8388
  * @returns {object} a [transfer structure]{@link https://docs.ccxt.com/?id=transfer-structure}
7118
8389
  */
7119
- async transfer(code, amount, fromAccount, toAccount, params = {}) {
8390
+ async transferClassic(code, amount, fromAccount, toAccount, params = {}) {
7120
8391
  await this.loadMarkets();
7121
8392
  const currency = this.currency(code);
7122
8393
  const requestedAmount = this.currencyToPrecision(code, amount);
@@ -7330,12 +8601,32 @@ export default class kucoin extends Exchange {
7330
8601
  // 'Pool transactions': 'Pool transactions', // Pool-X transactions
7331
8602
  'Instant Exchange': 'trade',
7332
8603
  'Sub-account transfer': 'transfer',
7333
- 'Liquidation Fees': 'fee', // Liquidation Fees
8604
+ 'Liquidation Fees': 'fee',
7334
8605
  // 'Soft Staking Profits': 'Soft Staking Profits', // Soft Staking Profits
7335
8606
  // 'Voting Earnings': 'Voting Earnings', // Voting Earnings on Pool-X
7336
8607
  // 'Redemption of Voting': 'Redemption of Voting', // Redemption of Voting on Pool-X
7337
8608
  // 'Voting': 'Voting', // Voting on Pool-X
7338
8609
  // 'Convert to KCS': 'Convert to KCS', // Convert to KCS
8610
+ 'RealisedPNL': 'trade',
8611
+ 'TransferIn': 'transfer',
8612
+ 'TransferOut': 'transfer',
8613
+ 'TRADE_EXCHANGE': 'trade',
8614
+ 'TRANSFER': 'transfer',
8615
+ 'SUB_TRANSFER': 'transfer',
8616
+ 'RETURNED_FEES': 'fee',
8617
+ 'DEDUCTION_FEES': 'fee',
8618
+ 'OTHER': 'other',
8619
+ 'SUB_TO_SUB_TRANSFER': 'transfer',
8620
+ 'SPOT_EXCHANGE': 'trade',
8621
+ 'SPOT_EXCHANGE_REBATE': 'rebate',
8622
+ 'FUTURES_EXCHANGE_OPEN': 'trade',
8623
+ 'FUTURES_EXCHANGE_CLOSE': 'trade',
8624
+ 'FUTURES_EXCHANGE_REBATE': 'rebate',
8625
+ 'FUNDING_FEE': 'fee',
8626
+ 'LIABILITY_INTEREST': 'fee',
8627
+ 'KCS_DEDUCTION_FEES': 'fee',
8628
+ 'KCS_RETURNED_FEES': 'fee',
8629
+ 'AUTO_EXCHANGE_USER': 'trade',
7339
8630
  };
7340
8631
  return this.safeString(types, type, type);
7341
8632
  }
@@ -7345,6 +8636,8 @@ export default class kucoin extends Exchange {
7345
8636
  'out': 'out',
7346
8637
  'TransferIn': 'in',
7347
8638
  'TransferOut': 'out',
8639
+ 'IN': 'in',
8640
+ 'OUT': 'out',
7348
8641
  };
7349
8642
  return this.safeString(directions, direction, direction);
7350
8643
  }
@@ -7383,14 +8676,28 @@ export default class kucoin extends Exchange {
7383
8676
  // "currency": "USDT"
7384
8677
  // }
7385
8678
  //
8679
+ // ledger entry from UTA API
8680
+ // {
8681
+ // "accountType": "UNIFIED",
8682
+ // "id": "30000000001200350",
8683
+ // "currency": "USDT",
8684
+ // "direction": "IN",
8685
+ // "businessType": "TRANSFER",
8686
+ // "amount": "30",
8687
+ // "balance": "30",
8688
+ // "fee": "0",
8689
+ // "tax": "0",
8690
+ // "remark": "Funding Account",
8691
+ // "ts": 1774241648267000000
8692
+ // }
8693
+ //
7386
8694
  const id = this.safeString(item, 'id');
7387
8695
  const currencyId = this.safeString(item, 'currency');
7388
8696
  const code = this.safeCurrencyCode(currencyId, currency);
7389
8697
  currency = this.safeCurrency(currencyId, currency);
7390
8698
  const amount = this.safeString(item, 'amount');
7391
- const balanceAfter = undefined;
7392
- // const balanceAfter = this.safeNumber (item, 'balance'); only returns zero string
7393
- const bizType = this.safeString(item, 'bizType');
8699
+ const balanceAfter = this.safeNumberOmitZero(item, 'balance');
8700
+ const bizType = this.safeStringN(item, ['bizType', 'businessType', 'type']);
7394
8701
  const type = this.parseLedgerEntryType(bizType);
7395
8702
  const direction = this.safeString2(item, 'direction', 'type');
7396
8703
  let account = this.safeString(item, 'accountType'); // MAIN, TRADE, MARGIN, or CONTRACT
@@ -7400,6 +8707,9 @@ export default class kucoin extends Exchange {
7400
8707
  if (timestamp !== undefined) {
7401
8708
  account = 'CONTRACT'; // contract ledger entries do not have an accountType field, so we set it to CONTRACT if the time field is present
7402
8709
  }
8710
+ else {
8711
+ timestamp = this.safeIntegerProduct(item, 'ts', 0.000001); // for UTA API
8712
+ }
7403
8713
  }
7404
8714
  const datetime = this.iso8601(timestamp);
7405
8715
  const context = this.safeString(item, 'context'); // contains other information about the ledger entry
@@ -7468,6 +8778,7 @@ export default class kucoin extends Exchange {
7468
8778
  * @see https://www.kucoin.com/docs-new/rest/account-info/account-funding/get-account-ledgers-tradehf
7469
8779
  * @see https://www.kucoin.com/docs-new/rest/account-info/account-funding/get-account-ledgers-marginhf
7470
8780
  * @see https://www.kucoin.com/docs-new/rest/account-info/account-funding/get-account-ledgers-futures
8781
+ * @see https://www.kucoin.com/docs-new/rest/ua/get-account-ledger
7471
8782
  * @param {string} [code] unified currency code, default is undefined
7472
8783
  * @param {int} [since] timestamp in ms of the earliest ledger entry, default is undefined
7473
8784
  * @param {int} [limit] max number of ledger entries to return, default is undefined
@@ -7475,18 +8786,50 @@ export default class kucoin extends Exchange {
7475
8786
  * @param {object} [params.type] extra parameters specific to the exchange API endpoint
7476
8787
  * @param {boolean} [params.hf] default false, when true will fetch ledger entries for the high frequency trading account
7477
8788
  * @param {int} [params.until] the latest time in ms to fetch entries for
8789
+ * @param {boolean} [params.uta] default false, when true will fetch ledger entries for the unified trading account (UTA) instead of the regular accounts endpoint
7478
8790
  * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [available parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
7479
8791
  * @returns {object} a [ledger structure]{@link https://docs.ccxt.com/?id=ledger-entry-structure}
7480
8792
  */
7481
8793
  async fetchLedger(code = undefined, since = undefined, limit = undefined, params = {}) {
7482
8794
  await this.loadMarkets();
7483
8795
  await this.loadAccounts();
7484
- let paginate = false;
7485
- [paginate, params] = this.handleOptionAndParams(params, 'fetchLedger', 'paginate');
8796
+ let uta = await this.isUTAEnabled();
8797
+ [uta, params] = this.handleOptionAndParams(params, 'fetchLedger', 'uta', uta);
7486
8798
  let hf = undefined;
7487
8799
  [hf, params] = this.handleHfAndParams(params);
8800
+ let requestedType = undefined;
8801
+ [requestedType, params] = this.handleMarketTypeAndParams('fetchLedger', undefined, params);
8802
+ let marginMode = undefined;
8803
+ [marginMode, params] = this.handleMarginModeAndParams('fetchLedger', params);
8804
+ if (uta && (requestedType === 'margin')) {
8805
+ marginMode = (marginMode === undefined) ? 'cross' : marginMode; // default to cross margin for UTA if margin is requested but marginMode is not specified
8806
+ requestedType = marginMode;
8807
+ }
8808
+ let accountsByType = this.safeDict(this.options, 'accountsByType');
8809
+ if (uta) {
8810
+ accountsByType = this.safeDict(this.options, 'utaAccountsByType');
8811
+ }
8812
+ let type = undefined;
8813
+ type = this.safeString(accountsByType, requestedType, requestedType);
8814
+ let maxLimit = 500; // for spot non-uta and margin
8815
+ if (hf) {
8816
+ maxLimit = 200;
8817
+ }
8818
+ else if (type === 'contract') {
8819
+ maxLimit = 50;
8820
+ }
8821
+ else if (uta) {
8822
+ if ((type === 'UNIFIED') || (type === 'SPOT')) {
8823
+ maxLimit = 200;
8824
+ }
8825
+ else if (type === 'FUTURES') {
8826
+ maxLimit = 100;
8827
+ }
8828
+ }
8829
+ let paginate = false;
8830
+ [paginate, params] = this.handleOptionAndParams(params, 'fetchLedger', 'paginate');
7488
8831
  if (paginate) {
7489
- return await this.fetchPaginatedCallDynamic('fetchLedger', code, since, limit, params);
8832
+ return await this.fetchPaginatedCallDynamic('fetchLedger', code, since, limit, params, maxLimit);
7490
8833
  }
7491
8834
  let request = {
7492
8835
  // 'currency': currency['id'], // can choose up to 10, if not provided returns for all currencies by default
@@ -7505,14 +8848,23 @@ export default class kucoin extends Exchange {
7505
8848
  request['currency'] = currency['id'];
7506
8849
  }
7507
8850
  [request, params] = this.handleUntilOption('endAt', request, params);
7508
- let marginMode = undefined;
7509
- [marginMode, params] = this.handleMarginModeAndParams('fetchLedger', params);
7510
- let type = undefined;
7511
- [type, params] = this.handleMarketTypeAndParams('fetchLedger', undefined, params);
7512
- const accountsByType = this.safeDict(this.options, 'accountsByType');
7513
- type = this.safeString(accountsByType, type, type);
8851
+ if (limit !== undefined) {
8852
+ if (type === 'contract') {
8853
+ request['maxCount'] = limit;
8854
+ }
8855
+ else if (hf) {
8856
+ request['limit'] = limit;
8857
+ }
8858
+ else {
8859
+ request['pageSize'] = limit;
8860
+ }
8861
+ }
7514
8862
  let response = undefined;
7515
- if (hf) {
8863
+ if (uta) {
8864
+ request['accountType'] = type;
8865
+ response = await this.utaPrivateGetAccountLedger(this.extend(request, params));
8866
+ }
8867
+ else if (hf) {
7516
8868
  if (marginMode !== undefined) {
7517
8869
  response = await this.privateGetHfMarginAccountLedgers(this.extend(request, params));
7518
8870
  }
@@ -7754,12 +9106,14 @@ export default class kucoin extends Exchange {
7754
9106
  // Cross
7755
9107
  //
7756
9108
  // {
7757
- // "currency": "1INCH",
7758
- // "total": "0",
7759
- // "available": "0",
9109
+ // "currency": "DOGE",
9110
+ // "total": "119.99995308",
9111
+ // "available": "119.99995308",
7760
9112
  // "hold": "0",
7761
- // "liability": "0",
7762
- // "maxBorrowSize": "0",
9113
+ // "liability": "10.00004692",
9114
+ // "liabilityPrincipal": "10",
9115
+ // "liabilityInterest": "0.00004692",
9116
+ // "maxBorrowSize": "1140",
7763
9117
  // "borrowEnabled": true,
7764
9118
  // "transferInEnabled": true
7765
9119
  // }
@@ -7767,30 +9121,32 @@ export default class kucoin extends Exchange {
7767
9121
  // Isolated
7768
9122
  //
7769
9123
  // {
7770
- // "symbol": "MANA-USDT",
7771
- // "debtRatio": "0",
7772
- // "status": "BORROW",
9124
+ // "symbol": "DOGE-USDT",
9125
+ // "status": "EFFECTIVE",
9126
+ // "debtRatio": "0.0822",
7773
9127
  // "baseAsset": {
7774
- // "currency": "MANA",
9128
+ // "currency": "DOGE",
7775
9129
  // "borrowEnabled": true,
7776
- // "repayEnabled": true,
7777
- // "transferEnabled": true,
7778
- // "borrowed": "0",
7779
- // "totalAsset": "0",
7780
- // "available": "0",
9130
+ // "transferInEnabled": true,
9131
+ // "liability": "10.00009385",
9132
+ // "liabilityPrincipal": "10.00004692",
9133
+ // "liabilityInterest": "0.00004693",
9134
+ // "total": "10",
9135
+ // "available": "10",
7781
9136
  // "hold": "0",
7782
- // "maxBorrowSize": "1000"
9137
+ // "maxBorrowSize": "990"
7783
9138
  // },
7784
9139
  // "quoteAsset": {
7785
9140
  // "currency": "USDT",
7786
9141
  // "borrowEnabled": true,
7787
- // "repayEnabled": true,
7788
- // "transferEnabled": true,
7789
- // "borrowed": "0",
7790
- // "totalAsset": "0",
7791
- // "available": "0",
9142
+ // "transferInEnabled": true,
9143
+ // "liability": "0",
9144
+ // "liabilityPrincipal": "0",
9145
+ // "liabilityInterest": "0",
9146
+ // "total": "10",
9147
+ // "available": "10",
7792
9148
  // "hold": "0",
7793
- // "maxBorrowSize": "50000"
9149
+ // "maxBorrowSize": "89"
7794
9150
  // }
7795
9151
  // }
7796
9152
  //
@@ -7798,19 +9154,18 @@ export default class kucoin extends Exchange {
7798
9154
  const marginMode = (marketId === undefined) ? 'cross' : 'isolated';
7799
9155
  market = this.safeMarket(marketId, market);
7800
9156
  const symbol = this.safeString(market, 'symbol');
7801
- const timestamp = this.safeInteger(info, 'createdAt');
7802
9157
  const isolatedBase = this.safeDict(info, 'baseAsset', {});
7803
9158
  let amountBorrowed = undefined;
7804
9159
  let interest = undefined;
7805
9160
  let currencyId = undefined;
7806
9161
  if (marginMode === 'isolated') {
7807
- amountBorrowed = this.safeNumber(isolatedBase, 'liability');
7808
- interest = this.safeNumber(isolatedBase, 'interest');
9162
+ amountBorrowed = this.safeNumber(isolatedBase, 'liabilityPrincipal');
9163
+ interest = this.safeNumber(isolatedBase, 'liabilityInterest');
7809
9164
  currencyId = this.safeString(isolatedBase, 'currency');
7810
9165
  }
7811
9166
  else {
7812
- amountBorrowed = this.safeNumber(info, 'liability');
7813
- interest = this.safeNumber(info, 'accruedInterest');
9167
+ amountBorrowed = this.safeNumber(info, 'liabilityPrincipal');
9168
+ interest = this.safeNumber(info, 'liabilityInterest');
7814
9169
  currencyId = this.safeString(info, 'currency');
7815
9170
  }
7816
9171
  return {
@@ -7821,8 +9176,8 @@ export default class kucoin extends Exchange {
7821
9176
  'interestRate': this.safeNumber(info, 'dailyIntRate'),
7822
9177
  'amountBorrowed': amountBorrowed,
7823
9178
  'marginMode': marginMode,
7824
- 'timestamp': timestamp,
7825
- 'datetime': this.iso8601(timestamp),
9179
+ 'timestamp': undefined,
9180
+ 'datetime': undefined,
7826
9181
  };
7827
9182
  }
7828
9183
  /**
@@ -8205,9 +9560,11 @@ export default class kucoin extends Exchange {
8205
9560
  * @description set the level of leverage for a market
8206
9561
  * @see https://www.kucoin.com/docs-new/rest/margin-trading/debit/modify-leverage
8207
9562
  * @see https://www.kucoin.com/docs-new/rest/futures-trading/positions/modify-cross-margin-leverage
9563
+ * @see https://www.kucoin.com/docs-new/rest/ua/modify-leverage-uta
8208
9564
  * @param {int } [leverage] New leverage multiplier. Must be greater than 1 and up to two decimal places, and cannot be less than the user's current debt leverage or greater than the system's maximum leverage
8209
9565
  * @param {string} [symbol] unified market symbol
8210
9566
  * @param {object} [params] extra parameters specific to the exchange API endpoint
9567
+ * @param {boolean} [params.uta] *contract markets only* set to true for the unified trading account (uta)
8211
9568
  * @returns {object} response from the exchange
8212
9569
  */
8213
9570
  async setLeverage(leverage, symbol = undefined, params = {}) {
@@ -8216,11 +9573,19 @@ export default class kucoin extends Exchange {
8216
9573
  let marketType = undefined;
8217
9574
  [marketType, params] = this.handleMarketTypeAndParams('setLeverage', undefined, params);
8218
9575
  if ((symbol !== undefined) || ((marketType !== 'spot') && (marketType !== 'margin'))) {
9576
+ if (symbol === undefined) {
9577
+ throw new ArgumentsRequired(this.id + ' setLeverage requires a symbol argument for contract markets');
9578
+ }
8219
9579
  market = this.market(symbol);
8220
9580
  if (market['contract']) {
8221
9581
  return await this.setContractLeverage(leverage, symbol, params);
8222
9582
  }
8223
9583
  }
9584
+ let uta = await this.isUTAEnabled();
9585
+ [uta, params] = this.handleOptionAndParams(params, 'setLeverage', 'uta', uta);
9586
+ if (uta) {
9587
+ throw new NotSupported(this.id + ' setLeverage with params["uta"] is supported for contract markets only');
9588
+ }
8224
9589
  let marginMode = undefined;
8225
9590
  [marginMode, params] = this.handleMarginModeAndParams('setLeverage', params);
8226
9591
  if (marginMode === undefined) {
@@ -8242,15 +9607,17 @@ export default class kucoin extends Exchange {
8242
9607
  * @name kucoin#setContractLeverage
8243
9608
  * @description set the level of leverage for a market
8244
9609
  * @see https://www.kucoin.com/docs-new/rest/futures-trading/positions/modify-cross-margin-leverage
9610
+ * @see https://www.kucoin.com/docs-new/rest/ua/modify-leverage-uta
8245
9611
  * @param {float} leverage the rate of leverage
8246
9612
  * @param {string} symbol unified market symbol
8247
9613
  * @param {object} [params] extra parameters specific to the exchange API endpoint
9614
+ * @param {boolean} [params.uta] set to true for the unified trading account (uta)
8248
9615
  * @returns {object} response from the exchange
8249
9616
  */
8250
9617
  async setContractLeverage(leverage, symbol = undefined, params = {}) {
8251
9618
  let marginMode = undefined;
8252
9619
  [marginMode, params] = this.handleMarginModeAndParams(symbol, params);
8253
- if (marginMode !== 'cross') {
9620
+ if ((marginMode !== undefined) && (marginMode !== 'cross')) {
8254
9621
  throw new NotSupported(this.id + ' setLeverage() currently supports only params["marginMode"] = "cross" for contracts');
8255
9622
  }
8256
9623
  await this.loadMarkets();
@@ -8259,14 +9626,24 @@ export default class kucoin extends Exchange {
8259
9626
  'symbol': market['id'],
8260
9627
  'leverage': leverage.toString(),
8261
9628
  };
8262
- const response = await this.futuresPrivatePostChangeCrossUserLeverage(this.extend(request, params));
8263
- //
8264
- // {
8265
- // "code": "200000",
8266
- // "data": true
8267
- // }
8268
- //
8269
- const leverageNum = this.safeInteger(response, 'leverage');
9629
+ let uta = await this.isUTAEnabled();
9630
+ [uta, params] = this.handleOptionAndParams(params, 'setLeverage', 'uta', uta);
9631
+ let response = undefined;
9632
+ if (uta) {
9633
+ request['accountMode'] = 'unified';
9634
+ response = await this.utaPrivatePostAccountModeAccountModifyLeverage(this.extend(request, params));
9635
+ }
9636
+ else {
9637
+ //
9638
+ // {
9639
+ // "code": "200000",
9640
+ // "data": true
9641
+ // }
9642
+ //
9643
+ response = await this.futuresPrivatePostChangeCrossUserLeverage(this.extend(request, params));
9644
+ }
9645
+ const data = this.safeDict(response, 'data', {});
9646
+ const leverageNum = this.safeNumber(data, 'leverage');
8270
9647
  return {
8271
9648
  'info': response,
8272
9649
  'symbol': market['symbol'],
@@ -8425,7 +9802,7 @@ export default class kucoin extends Exchange {
8425
9802
  'symbol': market['id'],
8426
9803
  };
8427
9804
  const until = this.safeInteger(params, 'until');
8428
- let uta = true; // for backward compatibility, dafult endpoint is uta
9805
+ let uta = false;
8429
9806
  [uta, params] = this.handleOptionAndParams(params, 'fetchFundingRateHistory', 'uta', uta);
8430
9807
  params = this.omit(params, 'until');
8431
9808
  let start = since;
@@ -8580,9 +9957,11 @@ export default class kucoin extends Exchange {
8580
9957
  * @method
8581
9958
  * @name kucoin#fetchPosition
8582
9959
  * @see https://www.kucoin.com/docs-new/rest/futures-trading/positions/get-position-details
9960
+ * @see https://www.kucoin.com/docs-new/rest/ua/get-position-list-uta
8583
9961
  * @description fetch data on an open position
8584
9962
  * @param {string} symbol unified market symbol of the market the position is held in
8585
9963
  * @param {object} [params] extra parameters specific to the exchange API endpoint
9964
+ * @param {boolean} [params.uta] set to true for the unified trading account (uta), defaults to false
8586
9965
  * @returns {object} a [position structure]{@link https://docs.ccxt.com/?id=position-structure}
8587
9966
  */
8588
9967
  async fetchPosition(symbol, params = {}) {
@@ -8591,112 +9970,157 @@ export default class kucoin extends Exchange {
8591
9970
  const request = {
8592
9971
  'symbol': market['id'],
8593
9972
  };
8594
- const response = await this.futuresPrivateGetPosition(this.extend(request, params));
8595
- //
8596
- // {
8597
- // "code": "200000",
8598
- // "data": {
8599
- // "id": "6505ee6eaff4070001f651c4",
8600
- // "symbol": "XBTUSDTM",
8601
- // "autoDeposit": false,
8602
- // "maintMarginReq": 0,
8603
- // "riskLimit": 200,
8604
- // "realLeverage": 0.0,
8605
- // "crossMode": false,
8606
- // "delevPercentage": 0.0,
8607
- // "currentTimestamp": 1694887534594,
8608
- // "currentQty": 0,
8609
- // "currentCost": 0.0,
8610
- // "currentComm": 0.0,
8611
- // "unrealisedCost": 0.0,
8612
- // "realisedGrossCost": 0.0,
8613
- // "realisedCost": 0.0,
8614
- // "isOpen": false,
8615
- // "markPrice": 26611.71,
8616
- // "markValue": 0.0,
8617
- // "posCost": 0.0,
8618
- // "posCross": 0,
8619
- // "posInit": 0.0,
8620
- // "posComm": 0.0,
8621
- // "posLoss": 0.0,
8622
- // "posMargin": 0.0,
8623
- // "posMaint": 0.0,
8624
- // "maintMargin": 0.0,
8625
- // "realisedGrossPnl": 0.0,
8626
- // "realisedPnl": 0.0,
8627
- // "unrealisedPnl": 0.0,
8628
- // "unrealisedPnlPcnt": 0,
8629
- // "unrealisedRoePcnt": 0,
8630
- // "avgEntryPrice": 0.0,
8631
- // "liquidationPrice": 0.0,
8632
- // "bankruptPrice": 0.0,
8633
- // "settleCurrency": "USDT",
8634
- // "maintainMargin": 0,
8635
- // "riskLimitLevel": 1
8636
- // }
8637
- // }
8638
- //
8639
- const data = this.safeDict(response, 'data', {});
8640
- return this.parsePosition(data, market);
9973
+ let uta = await this.isUTAEnabled();
9974
+ [uta, params] = this.handleOptionAndParams(params, 'fetchPosition', 'uta', uta);
9975
+ let response = undefined;
9976
+ let position = undefined;
9977
+ if (uta) {
9978
+ request['accountMode'] = 'unified';
9979
+ response = await this.utaPrivateGetAccountModePositionOpenList(this.extend(request, params));
9980
+ //
9981
+ // {
9982
+ // "code": "200000",
9983
+ // "data": [
9984
+ // {
9985
+ // "symbol": "DOGEUSDTM",
9986
+ // "id": "30000000000084351",
9987
+ // "marginMode": "CROSS",
9988
+ // "size": "2",
9989
+ // "entryPrice": "0.093795",
9990
+ // "positionValue": "18.298",
9991
+ // "markPrice": "0.09149",
9992
+ // "leverage": "3",
9993
+ // "unrealizedPnL": "-0.461",
9994
+ // "realizedPnL": "-0.01122489",
9995
+ // "initialMargin": "6.0993333327234",
9996
+ // "mmr": "0.007",
9997
+ // "maintenanceMargin": "0.128086",
9998
+ // "creationTime": 1774469753178000000
9999
+ // }
10000
+ // ]
10001
+ // }
10002
+ //
10003
+ const data = this.safeList(response, 'data', []);
10004
+ position = this.safeDict(data, 0, {});
10005
+ }
10006
+ else {
10007
+ response = await this.futuresPrivateGetPosition(this.extend(request, params));
10008
+ //
10009
+ // {
10010
+ // "code": "200000",
10011
+ // "data": {
10012
+ // "id": "6505ee6eaff4070001f651c4",
10013
+ // "symbol": "XBTUSDTM",
10014
+ // "autoDeposit": false,
10015
+ // "maintMarginReq": 0,
10016
+ // "riskLimit": 200,
10017
+ // "realLeverage": 0.0,
10018
+ // "crossMode": false,
10019
+ // "delevPercentage": 0.0,
10020
+ // "currentTimestamp": 1694887534594,
10021
+ // "currentQty": 0,
10022
+ // "currentCost": 0.0,
10023
+ // "currentComm": 0.0,
10024
+ // "unrealisedCost": 0.0,
10025
+ // "realisedGrossCost": 0.0,
10026
+ // "realisedCost": 0.0,
10027
+ // "isOpen": false,
10028
+ // "markPrice": 26611.71,
10029
+ // "markValue": 0.0,
10030
+ // "posCost": 0.0,
10031
+ // "posCross": 0,
10032
+ // "posInit": 0.0,
10033
+ // "posComm": 0.0,
10034
+ // "posLoss": 0.0,
10035
+ // "posMargin": 0.0,
10036
+ // "posMaint": 0.0,
10037
+ // "maintMargin": 0.0,
10038
+ // "realisedGrossPnl": 0.0,
10039
+ // "realisedPnl": 0.0,
10040
+ // "unrealisedPnl": 0.0,
10041
+ // "unrealisedPnlPcnt": 0,
10042
+ // "unrealisedRoePcnt": 0,
10043
+ // "avgEntryPrice": 0.0,
10044
+ // "liquidationPrice": 0.0,
10045
+ // "bankruptPrice": 0.0,
10046
+ // "settleCurrency": "USDT",
10047
+ // "maintainMargin": 0,
10048
+ // "riskLimitLevel": 1
10049
+ // }
10050
+ // }
10051
+ //
10052
+ position = this.safeDict(response, 'data', {});
10053
+ }
10054
+ return this.parsePosition(position, market);
8641
10055
  }
8642
10056
  /**
8643
10057
  * @method
8644
10058
  * @name kucoin#fetchPositions
8645
10059
  * @description fetch all open positions
8646
10060
  * @see https://www.kucoin.com/docs-new/rest/futures-trading/positions/get-position-list
10061
+ * @see https://www.kucoin.com/docs-new/rest/ua/get-position-list-uta
8647
10062
  * @param {string[]|undefined} symbols list of unified market symbols
8648
10063
  * @param {object} [params] extra parameters specific to the exchange API endpoint
10064
+ * @param {boolean} [params.uta] set to true for the unified trading account (uta), defaults to false
8649
10065
  * @returns {object[]} a list of [position structure]{@link https://docs.ccxt.com/?id=position-structure}
8650
10066
  */
8651
10067
  async fetchPositions(symbols = undefined, params = {}) {
8652
10068
  await this.loadMarkets();
8653
- const response = await this.futuresPrivateGetPositions(params);
8654
- //
8655
- // {
8656
- // "code": "200000",
8657
- // "data": [
8658
- // {
8659
- // "id": "615ba79f83a3410001cde321",
8660
- // "symbol": "ETHUSDTM",
8661
- // "autoDeposit": false,
8662
- // "maintMarginReq": 0.005,
8663
- // "riskLimit": 1000000,
8664
- // "realLeverage": 18.61,
8665
- // "crossMode": false,
8666
- // "delevPercentage": 0.86,
8667
- // "openingTimestamp": 1638563515618,
8668
- // "currentTimestamp": 1638576872774,
8669
- // "currentQty": 2,
8670
- // "currentCost": 83.64200000,
8671
- // "currentComm": 0.05018520,
8672
- // "unrealisedCost": 83.64200000,
8673
- // "realisedGrossCost": 0.00000000,
8674
- // "realisedCost": 0.05018520,
8675
- // "isOpen": true,
8676
- // "markPrice": 4225.01,
8677
- // "markValue": 84.50020000,
8678
- // "posCost": 83.64200000,
8679
- // "posCross": 0.0000000000,
8680
- // "posInit": 3.63660870,
8681
- // "posComm": 0.05236717,
8682
- // "posLoss": 0.00000000,
8683
- // "posMargin": 3.68897586,
8684
- // "posMaint": 0.50637594,
8685
- // "maintMargin": 4.54717586,
8686
- // "realisedGrossPnl": 0.00000000,
8687
- // "realisedPnl": -0.05018520,
8688
- // "unrealisedPnl": 0.85820000,
8689
- // "unrealisedPnlPcnt": 0.0103,
8690
- // "unrealisedRoePcnt": 0.2360,
8691
- // "avgEntryPrice": 4182.10,
8692
- // "liquidationPrice": 4023.00,
8693
- // "bankruptPrice": 4000.25,
8694
- // "settleCurrency": "USDT",
8695
- // "isInverse": false
8696
- // }
8697
- // ]
8698
- // }
8699
- //
10069
+ let uta = await this.isUTAEnabled();
10070
+ [uta, params] = this.handleOptionAndParams(params, 'fetchPositions', 'uta', uta);
10071
+ let response = undefined;
10072
+ if (uta) {
10073
+ response = await this.utaPrivateGetAccountModePositionOpenList(this.extend(params, { 'accountMode': 'unified' }));
10074
+ }
10075
+ else {
10076
+ response = await this.futuresPrivateGetPositions(params);
10077
+ //
10078
+ // {
10079
+ // "code": "200000",
10080
+ // "data": [
10081
+ // {
10082
+ // "id": "615ba79f83a3410001cde321",
10083
+ // "symbol": "ETHUSDTM",
10084
+ // "autoDeposit": false,
10085
+ // "maintMarginReq": 0.005,
10086
+ // "riskLimit": 1000000,
10087
+ // "realLeverage": 18.61,
10088
+ // "crossMode": false,
10089
+ // "delevPercentage": 0.86,
10090
+ // "openingTimestamp": 1638563515618,
10091
+ // "currentTimestamp": 1638576872774,
10092
+ // "currentQty": 2,
10093
+ // "currentCost": 83.64200000,
10094
+ // "currentComm": 0.05018520,
10095
+ // "unrealisedCost": 83.64200000,
10096
+ // "realisedGrossCost": 0.00000000,
10097
+ // "realisedCost": 0.05018520,
10098
+ // "isOpen": true,
10099
+ // "markPrice": 4225.01,
10100
+ // "markValue": 84.50020000,
10101
+ // "posCost": 83.64200000,
10102
+ // "posCross": 0.0000000000,
10103
+ // "posInit": 3.63660870,
10104
+ // "posComm": 0.05236717,
10105
+ // "posLoss": 0.00000000,
10106
+ // "posMargin": 3.68897586,
10107
+ // "posMaint": 0.50637594,
10108
+ // "maintMargin": 4.54717586,
10109
+ // "realisedGrossPnl": 0.00000000,
10110
+ // "realisedPnl": -0.05018520,
10111
+ // "unrealisedPnl": 0.85820000,
10112
+ // "unrealisedPnlPcnt": 0.0103,
10113
+ // "unrealisedRoePcnt": 0.2360,
10114
+ // "avgEntryPrice": 4182.10,
10115
+ // "liquidationPrice": 4023.00,
10116
+ // "bankruptPrice": 4000.25,
10117
+ // "settleCurrency": "USDT",
10118
+ // "isInverse": false
10119
+ // }
10120
+ // ]
10121
+ // }
10122
+ //
10123
+ }
8700
10124
  const data = this.safeList(response, 'data');
8701
10125
  return this.parsePositions(data, symbols);
8702
10126
  }
@@ -8705,69 +10129,120 @@ export default class kucoin extends Exchange {
8705
10129
  * @name kucoin#fetchPositionsHistory
8706
10130
  * @description fetches historical positions
8707
10131
  * @see https://www.kucoin.com/docs-new/rest/futures-trading/positions/get-positions-history
10132
+ * @see https://www.kucoin.com/docs-new/rest/ua/get-position-history-uta
8708
10133
  * @param {string[]} [symbols] list of unified market symbols
8709
10134
  * @param {int} [since] the earliest time in ms to fetch position history for
8710
10135
  * @param {int} [limit] the maximum number of entries to retrieve
8711
10136
  * @param {object} [params] extra parameters specific to the exchange API endpoint
8712
10137
  * @param {int} [params.until] closing end time
8713
10138
  * @param {int} [params.pageId] page id
10139
+ * @param {boolean} [params.uta] set to true for the unified trading account (uta), defaults to false
8714
10140
  * @returns {object[]} a list of [position structure]{@link https://docs.ccxt.com/?id=position-structure}
8715
10141
  */
8716
10142
  async fetchPositionsHistory(symbols = undefined, since = undefined, limit = undefined, params = {}) {
8717
10143
  await this.loadMarkets();
8718
- if (limit === undefined) {
8719
- limit = 200;
10144
+ let uta = await this.isUTAEnabled();
10145
+ [uta, params] = this.handleOptionAndParams(params, 'fetchPositionsHistory', 'uta', uta);
10146
+ let response = undefined;
10147
+ let request = {};
10148
+ symbols = this.marketSymbols(symbols);
10149
+ if (symbols !== undefined) {
10150
+ const length = symbols.length;
10151
+ if (length === 1) {
10152
+ const market = this.market(symbols[0]);
10153
+ request['symbol'] = market['id'];
10154
+ }
8720
10155
  }
8721
- const request = {
8722
- 'limit': limit,
8723
- };
8724
- if (since !== undefined) {
8725
- request['from'] = since;
10156
+ if (uta) {
10157
+ if (since !== undefined) {
10158
+ request['startAt'] = since;
10159
+ }
10160
+ if (limit !== undefined) {
10161
+ request['pageSize'] = limit;
10162
+ }
10163
+ [request, params] = this.handleUntilOption('endAt', request, params);
10164
+ //
10165
+ // {
10166
+ // "code": "200000",
10167
+ // "data": {
10168
+ // "items": [
10169
+ // {
10170
+ // "symbol": "DOGEUSDTM",
10171
+ // "closeId": "30000000000162175",
10172
+ // "marginMode": "CROSS",
10173
+ // "side": "LONG",
10174
+ // "entryPrice": "0.09641",
10175
+ // "closePrice": "0.09613",
10176
+ // "maxSize": "1",
10177
+ // "avgClosePrice": "0.09613",
10178
+ // "leverage": "3",
10179
+ // "realizedPnL": "-0.0395524",
10180
+ // "fee": "0.0115524",
10181
+ // "tax": "0",
10182
+ // "fundingFee": "0",
10183
+ // "closingTime": 1774469647311000000,
10184
+ // "creationTime": 1774468501294000000
10185
+ // }
10186
+ // ],
10187
+ // "lastId": 30000000000162175
10188
+ // }
10189
+ // }
10190
+ //
10191
+ response = await this.utaPrivateGetPositionHistory(this.extend(request, params));
8726
10192
  }
8727
- const until = this.safeInteger(params, 'until');
8728
- if (until !== undefined) {
8729
- params = this.omit(params, 'until');
8730
- request['to'] = until;
10193
+ else {
10194
+ if (limit === undefined) {
10195
+ limit = 200;
10196
+ }
10197
+ request['limit'] = limit;
10198
+ if (since !== undefined) {
10199
+ request['from'] = since;
10200
+ }
10201
+ const until = this.safeInteger(params, 'until');
10202
+ if (until !== undefined) {
10203
+ params = this.omit(params, 'until');
10204
+ request['to'] = until;
10205
+ }
10206
+ //
10207
+ // {
10208
+ // "success": true,
10209
+ // "code": "200",
10210
+ // "msg": "success",
10211
+ // "retry": false,
10212
+ // "data": {
10213
+ // "currentPage": 1,
10214
+ // "pageSize": 10,
10215
+ // "totalNum": 25,
10216
+ // "totalPage": 3,
10217
+ // "items": [
10218
+ // {
10219
+ // "closeId": "300000000000000030",
10220
+ // "positionId": "300000000000000009",
10221
+ // "uid": 99996908309485,
10222
+ // "userId": "6527d4fc8c7f3d0001f40f5f",
10223
+ // "symbol": "XBTUSDM",
10224
+ // "settleCurrency": "XBT",
10225
+ // "leverage": "0.0",
10226
+ // "type": "LIQUID_LONG",
10227
+ // "side": null,
10228
+ // "closeSize": null,
10229
+ // "pnl": "-1.0000003793999999",
10230
+ // "realisedGrossCost": "0.9993849748999999",
10231
+ // "withdrawPnl": "0.0",
10232
+ // "roe": null,
10233
+ // "tradeFee": "0.0006154045",
10234
+ // "fundingFee": "0.0",
10235
+ // "openTime": 1713785751181,
10236
+ // "closeTime": 1713785752784,
10237
+ // "openPrice": null,
10238
+ // "closePrice": null
10239
+ // }
10240
+ // ]
10241
+ // }
10242
+ // }
10243
+ //
10244
+ response = await this.futuresPrivateGetHistoryPositions(this.extend(request, params));
8731
10245
  }
8732
- const response = await this.futuresPrivateGetHistoryPositions(this.extend(request, params));
8733
- //
8734
- // {
8735
- // "success": true,
8736
- // "code": "200",
8737
- // "msg": "success",
8738
- // "retry": false,
8739
- // "data": {
8740
- // "currentPage": 1,
8741
- // "pageSize": 10,
8742
- // "totalNum": 25,
8743
- // "totalPage": 3,
8744
- // "items": [
8745
- // {
8746
- // "closeId": "300000000000000030",
8747
- // "positionId": "300000000000000009",
8748
- // "uid": 99996908309485,
8749
- // "userId": "6527d4fc8c7f3d0001f40f5f",
8750
- // "symbol": "XBTUSDM",
8751
- // "settleCurrency": "XBT",
8752
- // "leverage": "0.0",
8753
- // "type": "LIQUID_LONG",
8754
- // "side": null,
8755
- // "closeSize": null,
8756
- // "pnl": "-1.0000003793999999",
8757
- // "realisedGrossCost": "0.9993849748999999",
8758
- // "withdrawPnl": "0.0",
8759
- // "roe": null,
8760
- // "tradeFee": "0.0006154045",
8761
- // "fundingFee": "0.0",
8762
- // "openTime": 1713785751181,
8763
- // "closeTime": 1713785752784,
8764
- // "openPrice": null,
8765
- // "closePrice": null
8766
- // }
8767
- // ]
8768
- // }
8769
- // }
8770
- //
8771
10246
  const data = this.safeDict(response, 'data');
8772
10247
  const items = this.safeList(data, 'items', []);
8773
10248
  return this.parsePositions(items, symbols);
@@ -8842,61 +10317,107 @@ export default class kucoin extends Exchange {
8842
10317
  // "closePrice": null
8843
10318
  // }
8844
10319
  //
10320
+ // uta fetchPositions
10321
+ // {
10322
+ // "symbol": "DOGEUSDTM",
10323
+ // "id": "30000000000084351",
10324
+ // "marginMode": "CROSS",
10325
+ // "size": "2",
10326
+ // "entryPrice": "0.093795",
10327
+ // "positionValue": "18.298",
10328
+ // "markPrice": "0.09149",
10329
+ // "leverage": "3",
10330
+ // "unrealizedPnL": "-0.461",
10331
+ // "realizedPnL": "-0.01122489",
10332
+ // "initialMargin": "6.0993333327234",
10333
+ // "mmr": "0.007",
10334
+ // "maintenanceMargin": "0.128086",
10335
+ // "creationTime": 1774469753178000000
10336
+ // }
10337
+ //
10338
+ // uta fetchPositionsHistory
10339
+ // {
10340
+ // "symbol": "DOGEUSDTM",
10341
+ // "closeId": "30000000000162175",
10342
+ // "marginMode": "CROSS",
10343
+ // "side": "LONG",
10344
+ // "entryPrice": "0.09641",
10345
+ // "closePrice": "0.09613",
10346
+ // "maxSize": "1",
10347
+ // "avgClosePrice": "0.09613",
10348
+ // "leverage": "3",
10349
+ // "realizedPnL": "-0.0395524",
10350
+ // "fee": "0.0115524",
10351
+ // "tax": "0",
10352
+ // "fundingFee": "0",
10353
+ // "closingTime": 1774469647311000000,
10354
+ // "creationTime": 1774468501294000000
10355
+ // }
10356
+ //
8845
10357
  const symbol = this.safeString(position, 'symbol');
8846
10358
  market = this.safeMarket(symbol, market);
8847
- const timestamp = this.safeInteger(position, 'currentTimestamp');
8848
- const size = this.safeString(position, 'currentQty');
8849
- let side = undefined;
8850
- const type = this.safeStringLower(position, 'type');
8851
- if (size !== undefined) {
8852
- if (Precise.stringGt(size, '0')) {
8853
- side = 'long';
8854
- }
8855
- else if (Precise.stringLt(size, '0')) {
8856
- side = 'short';
8857
- }
10359
+ let timestamp = this.safeInteger(position, 'currentTimestamp');
10360
+ if (timestamp === undefined) {
10361
+ timestamp = this.safeIntegerProduct(position, 'creationTime', 0.000001);
8858
10362
  }
8859
- else if (type !== undefined) {
8860
- if (type.indexOf('long') > -1) {
8861
- side = 'long';
10363
+ const size = this.safeStringN(position, ['currentQty', 'size', 'maxSize', 'closeSize']);
10364
+ let side = this.safeStringLower(position, 'side');
10365
+ const type = this.safeStringLower(position, 'type');
10366
+ if (side === undefined) {
10367
+ if (size !== undefined) {
10368
+ if (Precise.stringGt(size, '0')) {
10369
+ side = 'long';
10370
+ }
10371
+ else if (Precise.stringLt(size, '0')) {
10372
+ side = 'short';
10373
+ }
8862
10374
  }
8863
- else {
8864
- side = 'short';
10375
+ else if (type !== undefined) {
10376
+ if (type.indexOf('long') > -1) {
10377
+ side = 'long';
10378
+ }
10379
+ else {
10380
+ side = 'short';
10381
+ }
8865
10382
  }
8866
10383
  }
8867
- const notional = Precise.stringAbs(this.safeString(position, 'posCost'));
8868
- const initialMargin = this.safeString(position, 'posInit');
10384
+ const notional = Precise.stringAbs(this.safeString2(position, 'posCost', 'positionValue'));
10385
+ const initialMargin = this.safeString2(position, 'posInit', 'initialMargin');
8869
10386
  const initialMarginPercentage = Precise.stringDiv(initialMargin, notional);
8870
10387
  // const marginRatio = Precise.stringDiv (maintenanceRate, collateral);
8871
- const unrealisedPnl = this.safeString(position, 'unrealisedPnl');
10388
+ const unrealisedPnl = this.safeString2(position, 'unrealisedPnl', 'unrealizedPnL');
8872
10389
  const crossMode = this.safeValue(position, 'crossMode');
8873
10390
  // currently crossMode is always set to false and only isolated positions are supported
8874
- let marginMode = undefined;
10391
+ let marginMode = this.safeStringLower(position, 'marginMode');
8875
10392
  if (crossMode !== undefined) {
8876
10393
  marginMode = crossMode ? 'cross' : 'isolated';
8877
10394
  }
10395
+ let lastUpdateTimestamp = this.safeInteger(position, 'closeTime');
10396
+ if (lastUpdateTimestamp === undefined) {
10397
+ lastUpdateTimestamp = this.safeIntegerProduct(position, 'closingTime', 0.000001);
10398
+ }
8878
10399
  return this.safePosition({
8879
10400
  'info': position,
8880
- 'id': this.safeString2(position, 'id', 'positionId'),
10401
+ 'id': this.safeStringN(position, ['id', 'positionId', 'closeId']),
8881
10402
  'symbol': this.safeString(market, 'symbol'),
8882
10403
  'timestamp': timestamp,
8883
10404
  'datetime': this.iso8601(timestamp),
8884
- 'lastUpdateTimestamp': this.safeInteger(position, 'closeTime'),
10405
+ 'lastUpdateTimestamp': lastUpdateTimestamp,
8885
10406
  'initialMargin': this.parseNumber(initialMargin),
8886
10407
  'initialMarginPercentage': this.parseNumber(initialMarginPercentage),
8887
- 'maintenanceMargin': this.safeNumber(position, 'posMaint'),
8888
- 'maintenanceMarginPercentage': this.safeNumber(position, 'maintMarginReq'),
8889
- 'entryPrice': this.safeNumber2(position, 'avgEntryPrice', 'openPrice'),
10408
+ 'maintenanceMargin': this.safeNumber2(position, 'posMaint', 'maintenanceMargin'),
10409
+ 'maintenanceMarginPercentage': this.safeNumber2(position, 'maintMarginReq', 'mmr'),
10410
+ 'entryPrice': this.safeNumberN(position, ['avgEntryPrice', 'openPrice', 'entryPrice']),
8890
10411
  'notional': this.parseNumber(notional),
8891
10412
  'leverage': this.safeNumber2(position, 'realLeverage', 'leverage'),
8892
10413
  'unrealizedPnl': this.parseNumber(unrealisedPnl),
8893
10414
  'contracts': this.parseNumber(Precise.stringAbs(size)),
8894
10415
  'contractSize': this.safeValue(market, 'contractSize'),
8895
- 'realizedPnl': this.safeNumber2(position, 'realisedPnl', 'pnl'),
10416
+ 'realizedPnl': this.safeNumberN(position, ['realisedPnl', 'pnl', 'realizedPnL']),
8896
10417
  'marginRatio': undefined,
8897
10418
  'liquidationPrice': this.safeNumber(position, 'liquidationPrice'),
8898
10419
  'markPrice': this.safeNumber(position, 'markPrice'),
8899
- 'lastPrice': undefined,
10420
+ 'lastPrice': this.safeNumber(position, 'closePrice'),
8900
10421
  'collateral': this.safeNumber(position, 'maintMargin'),
8901
10422
  'marginMode': marginMode,
8902
10423
  'side': side,
@@ -8910,18 +10431,31 @@ export default class kucoin extends Exchange {
8910
10431
  * @name kucoin#cancelOrders
8911
10432
  * @description cancel multiple orders for contract markets
8912
10433
  * @see https://www.kucoin.com/docs-new/3470241e0
10434
+ * @see https://www.kucoin.com/docs-new/rest/ua/batch-cancel-order-by-id
8913
10435
  * @param {string[]} ids order ids
8914
10436
  * @param {string} symbol unified symbol of the market the order was made in
8915
10437
  * @param {object} [params] extra parameters specific to the exchange API endpoint
8916
10438
  * @param {string[]} [params.clientOrderIds] client order ids
10439
+ * @param {boolean} [params.uta] set to true to use the unified trading account (uta) endpoint, defaults to false for the contract orders
10440
+ * @param {string} [params.accountMode] *for uta endpoint only* 'unified' or 'classic' (default is 'unified')
10441
+ * @param {string} [params.marginMode] *for margin orders only* 'cross' or 'isolated'
8917
10442
  * @returns {object} an list of [order structures]{@link https://docs.ccxt.com/?id=order-structure}
8918
10443
  */
8919
10444
  async cancelOrders(ids, symbol = undefined, params = {}) {
8920
- // contract markets only
8921
10445
  await this.loadMarkets();
10446
+ let uta = await this.isUTAEnabled();
10447
+ [uta, params] = this.handleOptionAndParams(params, 'cancelOrders', 'uta', uta);
8922
10448
  let market = undefined;
10449
+ let isContractMarket = true; // default to contract market orders if symbol is not provided, uta endpoint requires a symbol to be provided
8923
10450
  if (symbol !== undefined) {
8924
10451
  market = this.market(symbol);
10452
+ isContractMarket = market['contract'];
10453
+ if (!isContractMarket) {
10454
+ uta = true; // spot market orders can only be cancelled via the uta endpoint
10455
+ }
10456
+ }
10457
+ else if (uta) {
10458
+ throw new ArgumentsRequired(this.id + ' cancelOrders() requires a symbol argument for uta endpoint');
8925
10459
  }
8926
10460
  const ordersRequests = [];
8927
10461
  const clientOrderIds = this.safeList2(params, 'clientOrderIds', 'clientOids', []);
@@ -8938,33 +10472,59 @@ export default class kucoin extends Exchange {
8938
10472
  });
8939
10473
  }
8940
10474
  for (let i = 0; i < ids.length; i++) {
8941
- ordersRequests.push(ids[i]);
10475
+ const orderId = ids[i];
10476
+ if (uta) {
10477
+ ordersRequests.push({
10478
+ 'orderId': orderId,
10479
+ 'symbol': market['id'],
10480
+ });
10481
+ }
10482
+ else {
10483
+ ordersRequests.push(ids[i]);
10484
+ }
8942
10485
  }
8943
- const requestKey = useClientorderId ? 'clientOidsList' : 'orderIdsList';
8944
10486
  const request = {};
8945
- request[requestKey] = ordersRequests;
8946
- const response = await this.futuresPrivateDeleteOrdersMultiCancel(this.extend(request, params));
8947
- //
8948
- // {
8949
- // "code": "200000",
8950
- // "data":
8951
- // [
8952
- // {
8953
- // "orderId": "80465574458560512",
8954
- // "clientOid": null,
8955
- // "code": "200",
8956
- // "msg": "success"
8957
- // },
8958
- // {
8959
- // "orderId": "80465575289094144",
8960
- // "clientOid": null,
8961
- // "code": "200",
8962
- // "msg": "success"
8963
- // }
8964
- // ]
8965
- // }
8966
- //
8967
- const orders = this.safeList(response, 'data', []);
10487
+ let response = undefined;
10488
+ let orders = [];
10489
+ if (uta) {
10490
+ let accountMode = 'unified';
10491
+ [accountMode, params] = this.handleOptionAndParams(params, 'cancelOrders', 'accountMode', accountMode);
10492
+ request['accountMode'] = accountMode;
10493
+ let marginMode = undefined;
10494
+ [marginMode, params] = this.handleMarginModeAndParams('fetchOrder', params);
10495
+ const tradeType = this.handleTradeType(isContractMarket, marginMode, params);
10496
+ request['tradeType'] = tradeType;
10497
+ request['cancelOrderList'] = ordersRequests;
10498
+ response = await this.utaPrivatePostAccountModeOrderCancelBatch(this.extend(request, params));
10499
+ const data = this.safeDict(response, 'data', {});
10500
+ orders = this.safeList(data, 'items', []);
10501
+ }
10502
+ else {
10503
+ const requestKey = useClientorderId ? 'clientOidsList' : 'orderIdsList';
10504
+ request[requestKey] = ordersRequests;
10505
+ response = await this.futuresPrivateDeleteOrdersMultiCancel(this.extend(request, params));
10506
+ //
10507
+ // {
10508
+ // "code": "200000",
10509
+ // "data":
10510
+ // [
10511
+ // {
10512
+ // "orderId": "80465574458560512",
10513
+ // "clientOid": null,
10514
+ // "code": "200",
10515
+ // "msg": "success"
10516
+ // },
10517
+ // {
10518
+ // "orderId": "80465575289094144",
10519
+ // "clientOid": null,
10520
+ // "code": "200",
10521
+ // "msg": "success"
10522
+ // }
10523
+ // ]
10524
+ // }
10525
+ //
10526
+ orders = this.safeList(response, 'data', []);
10527
+ }
8968
10528
  return this.parseOrders(orders, market);
8969
10529
  }
8970
10530
  /**
@@ -9429,6 +10989,139 @@ export default class kucoin extends Exchange {
9429
10989
  }
9430
10990
  return result;
9431
10991
  }
10992
+ /**
10993
+ * @method
10994
+ * @name kucoin#fetchOpenInterests
10995
+ * @description Retrieves the open interest for a list of symbols
10996
+ * @see https://www.kucoin.com/docs-new/rest/ua/get-futures-open-interset
10997
+ * @param {string[]} [symbols] Unified CCXT market symbol
10998
+ * @param {object} [params] exchange specific parameters
10999
+ * @returns {object} an open interest structure{@link https://docs.ccxt.com/?id=open-interest-structure}
11000
+ */
11001
+ async fetchOpenInterests(symbols = undefined, params = {}) {
11002
+ await this.loadMarkets();
11003
+ symbols = this.marketSymbols(symbols);
11004
+ const request = {};
11005
+ if (symbols !== undefined) {
11006
+ const length = symbols.length;
11007
+ if (length < 11) {
11008
+ // the endpoint does not accept more than 10 symbols at a time
11009
+ // if user provided more than 10 symbols, we will fetch all symbols
11010
+ const marketIds = this.marketIds(symbols);
11011
+ request['symbol'] = marketIds.join(',');
11012
+ }
11013
+ }
11014
+ const response = await this.utaGetMarketOpenInterest(this.extend(request, params));
11015
+ //
11016
+ // {
11017
+ // "code": "200000",
11018
+ // "data": [
11019
+ // {
11020
+ // "symbol": "ETHUSDTM",
11021
+ // "openInterest": "8053960",
11022
+ // "ts": 1774007467050
11023
+ // }
11024
+ // ]
11025
+ // }
11026
+ //
11027
+ const data = this.safeList(response, 'data', []);
11028
+ return this.parseOpenInterests(data, symbols);
11029
+ }
11030
+ parseOpenInterest(interest, market = undefined) {
11031
+ //
11032
+ // {
11033
+ // "symbol": "ETHUSDTM",
11034
+ // "openInterest": "8053960",
11035
+ // "ts": 1774007467050
11036
+ // }
11037
+ //
11038
+ const marketId = this.safeString(interest, 'symbol');
11039
+ market = this.safeMarket(marketId, market);
11040
+ const timestamp = this.safeInteger(interest, 'ts');
11041
+ return this.safeOpenInterest({
11042
+ 'symbol': this.safeSymbol(marketId),
11043
+ 'openInterestAmount': this.safeNumber(interest, 'openInterest'),
11044
+ 'openInterestValue': undefined,
11045
+ 'timestamp': timestamp,
11046
+ 'datetime': this.iso8601(timestamp),
11047
+ 'info': interest,
11048
+ }, market);
11049
+ }
11050
+ /**
11051
+ * @method
11052
+ * @name kucoin#fetchOpenInterestHistory
11053
+ * @description Retrieves the open interest history of a currency
11054
+ * @see https://www.kucoin.com/docs-new/rest/ua/get-futures-open-interset
11055
+ * @param {string} symbol Unified CCXT market symbol
11056
+ * @param {string} timeframe '5m', '15m', '30m', '1h', '4h' or '1d'
11057
+ * @param {int} [since] the time(ms) of the earliest record to retrieve as a unix timestamp
11058
+ * @param {int} [limit] default 30,max 200
11059
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
11060
+ * @param {int} [params.until] the latest time in ms to fetch entries for
11061
+ * @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)
11062
+ * @returns {object} an array of [open interest structures]{@link https://docs.ccxt.com/?id=open-interest-structure}
11063
+ */
11064
+ async fetchOpenInterestHistory(symbol, timeframe = '5m', since = undefined, limit = undefined, params = {}) {
11065
+ const timeframes = {
11066
+ '5m': '5min',
11067
+ '15m': '15min',
11068
+ '30m': '30min',
11069
+ '1h': '1hour',
11070
+ '4h': '4hour',
11071
+ '1d': '1day',
11072
+ '5min': '5min',
11073
+ '15min': '15min',
11074
+ '30min': '30min',
11075
+ '1hour': '1hour',
11076
+ '4hour': '4hour',
11077
+ '1day': '1day',
11078
+ };
11079
+ const interval = this.safeString(timeframes, timeframe);
11080
+ if (interval === undefined) {
11081
+ throw new BadRequest(this.id + ' fetchOpenInterestHistory() invalid timeframe, supported are 5m, 15m, 30m, 1h, 4h, 1d');
11082
+ }
11083
+ await this.loadMarkets();
11084
+ const market = this.market(symbol);
11085
+ const maxLimit = 200;
11086
+ let paginate = false;
11087
+ [paginate, params] = this.handleOptionAndParams(params, 'fetchOpenInterestHistory', 'paginate', paginate);
11088
+ if (paginate) {
11089
+ return await this.fetchPaginatedCallDeterministic('fetchOpenInterestHistory', symbol, since, limit, timeframe, params, maxLimit);
11090
+ }
11091
+ let request = {
11092
+ 'symbol': market['id'],
11093
+ 'interval': interval,
11094
+ };
11095
+ if (since !== undefined) {
11096
+ request['startAt'] = since;
11097
+ }
11098
+ if (limit !== undefined) {
11099
+ request['pageSize'] = limit;
11100
+ }
11101
+ [request, params] = this.handleUntilOption('endAt', request, params);
11102
+ const response = await this.utaGetMarketOpenInterest(this.extend(request, params));
11103
+ const data = this.safeList(response, 'data');
11104
+ return this.parseOpenInterestsHistory(data, market, since, limit);
11105
+ }
11106
+ /**
11107
+ * @method
11108
+ * @name kucoin#isUTAEnabled
11109
+ * @see https://www.kucoin.com/docs-new/rest/ua/get-account-mode
11110
+ * @description returns true or false so the user can check if unified account is enabled
11111
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
11112
+ * @returns {boolean} true if unified account is enabled, false otherwise
11113
+ */
11114
+ async isUTAEnabled(params = {}) {
11115
+ let uta = this.safeBool(this.options, 'uta');
11116
+ if (uta === undefined) {
11117
+ const response = await this.utaPrivateGetAccountMode(params);
11118
+ const data = this.safeDict(response, 'data', {});
11119
+ const accountMode = this.safeString(data, 'selfAccountMode');
11120
+ uta = (accountMode === 'UNIFIED');
11121
+ this.options['uta'] = uta;
11122
+ }
11123
+ return this.safeBool(this.options, 'uta', false);
11124
+ }
9432
11125
  sign(path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
9433
11126
  //
9434
11127
  // the v2 URL is https://openapi-v2.kucoin.com/api/v1/endpoint
@@ -9459,11 +11152,15 @@ export default class kucoin extends Exchange {
9459
11152
  let endpart = '';
9460
11153
  headers = (headers !== undefined) ? headers : {};
9461
11154
  let url = this.urls['api'][api];
11155
+ const tradeType = this.safeString(query, 'tradeType');
9462
11156
  if (!this.isEmpty(query)) {
9463
11157
  if (((method === 'GET') || (method === 'DELETE')) && (path !== 'orders/multi-cancel')) {
9464
11158
  endpoint += '?' + this.rawencode(query);
9465
11159
  }
9466
11160
  else {
11161
+ if (endpoint === '/api/ua/v1/classic/order/place') {
11162
+ endpoint += '?tradeType=' + tradeType;
11163
+ }
9467
11164
  body = this.json(query);
9468
11165
  endpart = body;
9469
11166
  headers['Content-Type'] = 'application/json';
@@ -9494,7 +11191,9 @@ export default class kucoin extends Exchange {
9494
11191
  const signature = this.hmac(this.encode(payload), this.encode(this.secret), sha256, 'base64');
9495
11192
  headers['KC-API-SIGN'] = signature;
9496
11193
  let partner = this.safeDict(this.options, 'partner', {});
9497
- partner = isFuturePrivate ? this.safeValue(partner, 'future', partner) : this.safeValue(partner, 'spot', partner);
11194
+ const isUtaFuturePrivate = isUtaPrivate && (tradeType === 'FUTURES');
11195
+ const isFuturePartner = isFuturePrivate || isUtaFuturePrivate;
11196
+ partner = isFuturePartner ? this.safeValue(partner, 'future', partner) : this.safeValue(partner, 'spot', partner);
9498
11197
  const partnerId = this.safeString(partner, 'id');
9499
11198
  const partnerSecret = this.safeString2(partner, 'secret', 'key');
9500
11199
  if ((partnerId !== undefined) && (partnerSecret !== undefined)) {