ccxt 4.1.30 → 4.1.32

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 (56) hide show
  1. package/CHANGELOG.md +186 -0
  2. package/README.md +3 -3
  3. package/dist/ccxt.browser.js +428 -174
  4. package/dist/ccxt.browser.min.js +3 -3
  5. package/dist/cjs/ccxt.js +1 -1
  6. package/dist/cjs/src/ascendex.js +89 -12
  7. package/dist/cjs/src/base/Exchange.js +6 -0
  8. package/dist/cjs/src/bitget.js +43 -27
  9. package/dist/cjs/src/bitvavo.js +43 -7
  10. package/dist/cjs/src/bybit.js +0 -3
  11. package/dist/cjs/src/coinex.js +2 -1
  12. package/dist/cjs/src/gemini.js +1 -2
  13. package/dist/cjs/src/hitbtc.js +32 -22
  14. package/dist/cjs/src/huobi.js +18 -12
  15. package/dist/cjs/src/krakenfutures.js +1 -0
  16. package/dist/cjs/src/mexc.js +2 -6
  17. package/dist/cjs/src/okx.js +1 -0
  18. package/dist/cjs/src/phemex.js +8 -6
  19. package/dist/cjs/src/pro/bittrex.js +68 -2
  20. package/dist/cjs/src/pro/huobi.js +76 -32
  21. package/dist/cjs/src/woo.js +27 -31
  22. package/js/ccxt.d.ts +3 -3
  23. package/js/ccxt.js +1 -1
  24. package/js/src/ascendex.d.ts +11 -1
  25. package/js/src/ascendex.js +89 -12
  26. package/js/src/base/Exchange.d.ts +5 -3
  27. package/js/src/base/Exchange.js +6 -0
  28. package/js/src/base/types.d.ts +9 -0
  29. package/js/src/binance.d.ts +1 -1
  30. package/js/src/bitget.d.ts +3 -3
  31. package/js/src/bitget.js +43 -27
  32. package/js/src/bitvavo.d.ts +13 -13
  33. package/js/src/bitvavo.js +43 -7
  34. package/js/src/bybit.js +0 -3
  35. package/js/src/coinex.d.ts +2 -2
  36. package/js/src/coinex.js +2 -1
  37. package/js/src/gate.d.ts +3 -3
  38. package/js/src/gemini.js +1 -2
  39. package/js/src/hitbtc.js +33 -23
  40. package/js/src/huobi.d.ts +1 -1
  41. package/js/src/huobi.js +18 -12
  42. package/js/src/krakenfutures.js +1 -0
  43. package/js/src/kucoinfutures.d.ts +2 -2
  44. package/js/src/mexc.d.ts +2 -2
  45. package/js/src/mexc.js +2 -6
  46. package/js/src/okx.d.ts +2 -2
  47. package/js/src/okx.js +1 -0
  48. package/js/src/phemex.d.ts +2 -2
  49. package/js/src/phemex.js +8 -6
  50. package/js/src/poloniexfutures.d.ts +2 -2
  51. package/js/src/pro/bittrex.d.ts +1 -0
  52. package/js/src/pro/bittrex.js +69 -3
  53. package/js/src/pro/huobi.js +76 -32
  54. package/js/src/woo.d.ts +1 -1
  55. package/js/src/woo.js +27 -31
  56. package/package.json +2 -2
@@ -6,7 +6,7 @@
6
6
 
7
7
  // ---------------------------------------------------------------------------
8
8
  import bittrexRest from '../bittrex.js';
9
- import { InvalidNonce, BadRequest } from '../base/errors.js';
9
+ import { InvalidNonce, BadRequest, ExchangeError, AuthenticationError } from '../base/errors.js';
10
10
  import { ArrayCache, ArrayCacheByTimestamp, ArrayCacheBySymbolById } from '../base/ws/Cache.js';
11
11
  import { sha512 } from '../static_dependencies/noble-hashes/sha512.js';
12
12
  import { inflateSync as inflate } from '../static_dependencies/fflake/browser.js';
@@ -49,6 +49,12 @@ export default class bittrex extends bittrexRest {
49
49
  'maxRetries': 3,
50
50
  },
51
51
  },
52
+ 'exceptions': {
53
+ 'exact': {
54
+ 'INVALID_APIKEY': AuthenticationError,
55
+ 'UNAUTHORIZED_USER': AuthenticationError,
56
+ },
57
+ },
52
58
  });
53
59
  }
54
60
  getSignalRUrl(negotiation) {
@@ -99,6 +105,7 @@ export default class bittrex extends bittrexRest {
99
105
  return await this.watch(url, messageHash, request, messageHash, subscription);
100
106
  }
101
107
  async authenticate(params = {}) {
108
+ this.checkRequiredCredentials();
102
109
  await this.loadMarkets();
103
110
  const request = await this.negotiate();
104
111
  return await this.sendRequestToAuthenticate(request, false, params);
@@ -119,7 +126,7 @@ export default class bittrex extends bittrexRest {
119
126
  'negotiation': negotiation,
120
127
  'method': this.handleAuthenticate,
121
128
  };
122
- this.spawn(this.watch, url, messageHash, request, requestId, subscription);
129
+ this.watch(url, messageHash, request, requestId, subscription);
123
130
  }
124
131
  return await future;
125
132
  }
@@ -526,7 +533,9 @@ export default class bittrex extends bittrexRest {
526
533
  * @returns {object[]} a list of [trade structures]{@link https://github.com/ccxt/ccxt/wiki/Manual#trade-structure
527
534
  */
528
535
  await this.loadMarkets();
529
- symbol = this.symbol(symbol);
536
+ if (symbol !== undefined) {
537
+ symbol = this.symbol(symbol);
538
+ }
530
539
  const authentication = await this.authenticate();
531
540
  const trades = await this.subscribeToMyTrades(authentication, params);
532
541
  if (this.newUpdates) {
@@ -791,6 +800,60 @@ export default class bittrex extends bittrexRest {
791
800
  }
792
801
  return message;
793
802
  }
803
+ handleErrorMessage(client, message) {
804
+ //
805
+ // {
806
+ // R: [{ Success: false, ErrorCode: 'UNAUTHORIZED_USER' }, ... ],
807
+ // I: '1698601759267'
808
+ // }
809
+ // {
810
+ // R: { Success: false, ErrorCode: 'INVALID_APIKEY' },
811
+ // I: '1698601759266'
812
+ // }
813
+ //
814
+ const R = this.safeValue(message, 'R');
815
+ if (R === undefined) {
816
+ // Return there is no error
817
+ return false;
818
+ }
819
+ const I = this.safeString(message, 'I');
820
+ let errorCode = undefined;
821
+ if (Array.isArray(R)) {
822
+ for (let i = 0; i < R.length; i++) {
823
+ const response = this.safeValue(R, i);
824
+ const success = this.safeValue(response, 'Success', true);
825
+ if (!success) {
826
+ errorCode = this.safeString(response, 'ErrorCode');
827
+ break;
828
+ }
829
+ }
830
+ }
831
+ else {
832
+ const success = this.safeValue(R, 'Success', true);
833
+ if (!success) {
834
+ errorCode = this.safeString(R, 'ErrorCode');
835
+ }
836
+ }
837
+ if (errorCode === undefined) {
838
+ // Return there is no error
839
+ return false;
840
+ }
841
+ const feedback = this.id + ' ' + errorCode;
842
+ try {
843
+ this.throwExactlyMatchedException(this.exceptions['exact'], errorCode, feedback);
844
+ if (message !== undefined) {
845
+ this.throwBroadlyMatchedException(this.exceptions['broad'], errorCode, feedback);
846
+ }
847
+ throw new ExchangeError(feedback);
848
+ }
849
+ catch (e) {
850
+ if (e instanceof AuthenticationError) {
851
+ client.reject(e, 'authenticate');
852
+ }
853
+ client.reject(e, I);
854
+ }
855
+ return true;
856
+ }
794
857
  handleMessage(client, message) {
795
858
  //
796
859
  // subscription confirmation
@@ -837,6 +900,9 @@ export default class bittrex extends bittrexRest {
837
900
  // M: [ { H: 'C3', M: 'authenticationExpiring', A: [] } ]
838
901
  // }
839
902
  //
903
+ if (this.handleErrorMessage(client, message)) {
904
+ return;
905
+ }
840
906
  const methods = {
841
907
  'authenticationExpiring': this.handleAuthenticationExpiring,
842
908
  'order': this.handleOrder,
@@ -105,7 +105,8 @@ export default class huobi extends huobiRest {
105
105
  '2021': BadRequest,
106
106
  '2001': BadSymbol,
107
107
  '2011': BadSymbol,
108
- '2040': BadRequest, // { op: 'sub', cid: '1649152947', 'err-code': 2040, 'err-msg': 'Missing required parameter.', ts: 1649152948684 }
108
+ '2040': BadRequest,
109
+ '4007': BadRequest, // { op: 'sub', cid: '1', topic: 'accounts_unify.USDT', 'err-code': 4007, 'err-msg': 'Non - single account user is not available, please check through the cross and isolated account asset interface', ts: 1698419318540 }
109
110
  },
110
111
  },
111
112
  },
@@ -1194,12 +1195,12 @@ export default class huobi extends huobiRest {
1194
1195
  * @param {object} [params] extra parameters specific to the huobi api endpoint
1195
1196
  * @returns {object} a [balance structure]{@link https://github.com/ccxt/ccxt/wiki/Manual#balance-structure}
1196
1197
  */
1197
- let type = this.safeString2(this.options, 'watchBalance', 'defaultType', 'spot');
1198
- type = this.safeString(params, 'type', type);
1199
- let subType = this.safeString2(this.options, 'watchBalance', 'subType', 'linear');
1200
- subType = this.safeString(params, 'subType', subType);
1201
- params = this.omit(params, ['type', 'subType']);
1202
- params = this.omit(params, 'type');
1198
+ let type = undefined;
1199
+ [type, params] = this.handleMarketTypeAndParams('watchBalance', undefined, params);
1200
+ let subType = undefined;
1201
+ [subType, params] = this.handleSubTypeAndParams('watchBalance', undefined, params, 'linear');
1202
+ const isUnifiedAccount = this.safeValue2(params, 'isUnifiedAccount', 'unified', false);
1203
+ params = this.omit(params, ['isUnifiedAccount', 'unified']);
1203
1204
  await this.loadMarkets();
1204
1205
  let messageHash = undefined;
1205
1206
  let channel = undefined;
@@ -1220,29 +1221,37 @@ export default class huobi extends huobiRest {
1220
1221
  let prefix = 'accounts';
1221
1222
  messageHash = prefix;
1222
1223
  if (subType === 'linear') {
1223
- // usdt contracts account
1224
- prefix = (marginMode === 'cross') ? prefix + '_cross' : prefix;
1225
- messageHash = prefix;
1226
- if (marginMode === 'isolated') {
1227
- // isolated margin only allows filtering by symbol3
1228
- if (symbol !== undefined) {
1229
- messageHash += '.' + market['id'];
1230
- channel = messageHash;
1231
- }
1232
- else {
1233
- // subscribe to all
1234
- channel = prefix + '.' + '*';
1235
- }
1224
+ if (isUnifiedAccount) {
1225
+ // usdt contracts account
1226
+ prefix = 'accounts_unify';
1227
+ messageHash = prefix;
1228
+ channel = prefix + '.' + 'usdt';
1236
1229
  }
1237
1230
  else {
1238
- // cross margin
1239
- if (currencyCode !== undefined) {
1240
- channel = prefix + '.' + currencyCode['id'];
1241
- messageHash = channel;
1231
+ // usdt contracts account
1232
+ prefix = (marginMode === 'cross') ? prefix + '_cross' : prefix;
1233
+ messageHash = prefix;
1234
+ if (marginMode === 'isolated') {
1235
+ // isolated margin only allows filtering by symbol3
1236
+ if (symbol !== undefined) {
1237
+ messageHash += '.' + market['id'];
1238
+ channel = messageHash;
1239
+ }
1240
+ else {
1241
+ // subscribe to all
1242
+ channel = prefix + '.' + '*';
1243
+ }
1242
1244
  }
1243
1245
  else {
1244
- // subscribe to all
1245
- channel = prefix + '.' + '*';
1246
+ // cross margin
1247
+ if (currencyCode !== undefined) {
1248
+ channel = prefix + '.' + currencyCode['id'];
1249
+ messageHash = channel;
1250
+ }
1251
+ else {
1252
+ // subscribe to all
1253
+ channel = prefix + '.' + '*';
1254
+ }
1246
1255
  }
1247
1256
  }
1248
1257
  }
@@ -1420,7 +1429,9 @@ export default class huobi extends huobiRest {
1420
1429
  return;
1421
1430
  }
1422
1431
  const first = this.safeValue(data, 0, {});
1423
- let messageHash = this.safeString(message, 'topic');
1432
+ const topic = this.safeString(message, 'topic');
1433
+ const splitTopic = topic.split('.');
1434
+ let messageHash = this.safeString(splitTopic, 0);
1424
1435
  let subscription = this.safeValue2(client.subscriptions, messageHash, messageHash + '.*');
1425
1436
  if (subscription === undefined) {
1426
1437
  // if subscription not found means that we subscribed to a specific currency/symbol
@@ -1428,13 +1439,37 @@ export default class huobi extends huobiRest {
1428
1439
  // Example: topic = 'accounts'
1429
1440
  // client.subscription hash = 'accounts.usdt'
1430
1441
  // we do 'accounts' + '.' + data[0]]['margin_asset'] to get it
1431
- const marginAsset = this.safeString(first, 'margin_asset');
1432
- messageHash += '.' + marginAsset.toLowerCase();
1442
+ const currencyId = this.safeString2(first, 'margin_asset', 'symbol');
1443
+ messageHash += '.' + currencyId.toLowerCase();
1433
1444
  subscription = this.safeValue(client.subscriptions, messageHash);
1434
1445
  }
1435
1446
  const type = this.safeString(subscription, 'type');
1436
1447
  const subType = this.safeString(subscription, 'subType');
1437
- if (subType === 'linear') {
1448
+ if (topic === 'accounts_unify') {
1449
+ // {
1450
+ // margin_asset: 'USDT',
1451
+ // margin_static: 10,
1452
+ // cross_margin_static: 10,
1453
+ // margin_balance: 10,
1454
+ // cross_profit_unreal: 0,
1455
+ // margin_frozen: 0,
1456
+ // withdraw_available: 10,
1457
+ // cross_risk_rate: null,
1458
+ // cross_swap: [],
1459
+ // cross_future: [],
1460
+ // isolated_swap: []
1461
+ // }
1462
+ const marginAsset = this.safeString(first, 'margin_asset');
1463
+ const code = this.safeCurrencyCode(marginAsset);
1464
+ const marginFrozen = this.safeString(first, 'margin_frozen');
1465
+ const unifiedAccount = this.account();
1466
+ unifiedAccount['free'] = this.safeString(first, 'withdraw_available');
1467
+ unifiedAccount['used'] = marginFrozen;
1468
+ this.balance[code] = unifiedAccount;
1469
+ this.balance = this.safeBalance(this.balance);
1470
+ client.resolve(this.balance, 'accounts_unify');
1471
+ }
1472
+ else if (subType === 'linear') {
1438
1473
  const margin = this.safeString(subscription, 'margin');
1439
1474
  if (margin === 'cross') {
1440
1475
  const fieldName = (type === 'future') ? 'futures_contract_detail' : 'contract_detail';
@@ -1732,6 +1767,15 @@ export default class huobi extends huobiRest {
1732
1767
  // id: '2'
1733
1768
  // }
1734
1769
  //
1770
+ // {
1771
+ // op: 'sub',
1772
+ // cid: '1',
1773
+ // topic: 'accounts_unify.USDT',
1774
+ // 'err-code': 4007,
1775
+ // 'err-msg': 'Non - single account user is not available, please check through the cross and isolated account asset interface',
1776
+ // ts: 1698419490189
1777
+ // }
1778
+ //
1735
1779
  const status = this.safeString(message, 'status');
1736
1780
  if (status === 'error') {
1737
1781
  const id = this.safeString(message, 'id');
@@ -1753,8 +1797,8 @@ export default class huobi extends huobiRest {
1753
1797
  }
1754
1798
  return false;
1755
1799
  }
1756
- const code = this.safeInteger(message, 'code');
1757
- if (code !== undefined && code !== 200) {
1800
+ const code = this.safeInteger2(message, 'code', 'err-code');
1801
+ if (code !== undefined && ((code !== 200) && (code !== 0))) {
1758
1802
  const feedback = this.id + ' ' + this.json(message);
1759
1803
  try {
1760
1804
  this.throwExactlyMatchedException(this.exceptions['ws']['exact'], code, feedback);
package/js/src/woo.d.ts CHANGED
@@ -160,7 +160,7 @@ export default class woo extends Exchange {
160
160
  amount: number;
161
161
  rate: number;
162
162
  };
163
- fetchFundingHistory(symbol?: string, since?: Int, limit?: Int, params?: {}): Promise<any>;
163
+ fetchFundingHistory(symbol?: string, since?: Int, limit?: Int, params?: {}): Promise<import("./base/types.js").FundingHistory[]>;
164
164
  parseFundingRate(fundingRate: any, market?: any): {
165
165
  info: any;
166
166
  symbol: any;
package/js/src/woo.js CHANGED
@@ -950,29 +950,27 @@ export default class woo extends Exchange {
950
950
  if (stopPrice !== undefined) {
951
951
  request['triggerPrice'] = this.priceToPrecision(symbol, stopPrice);
952
952
  }
953
+ params = this.omit(params, ['clOrdID', 'clientOrderId', 'client_order_id', 'stopPrice', 'triggerPrice', 'takeProfitPrice', 'stopLossPrice']);
953
954
  const isStop = (stopPrice !== undefined) || (this.safeValue(params, 'childOrders') !== undefined);
954
- let method = undefined;
955
+ let response = undefined;
955
956
  if (isByClientOrder) {
957
+ request['client_order_id'] = clientOrderIdExchangeSpecific;
956
958
  if (isStop) {
957
- method = 'v3PrivatePutAlgoOrderClientClientOrderId';
958
- request['oid'] = id;
959
+ response = await this.v3PrivatePutAlgoOrderClientClientOrderId(this.extend(request, params));
959
960
  }
960
961
  else {
961
- method = 'v3PrivatePutOrderClientClientOrderId';
962
- request['client_order_id'] = clientOrderIdExchangeSpecific;
962
+ response = await this.v3PrivatePutOrderClientClientOrderId(this.extend(request, params));
963
963
  }
964
964
  }
965
965
  else {
966
+ request['oid'] = id;
966
967
  if (isStop) {
967
- method = 'v3PrivatePutAlgoOrderOid';
968
+ response = await this.v3PrivatePutAlgoOrderOid(this.extend(request, params));
968
969
  }
969
970
  else {
970
- method = 'v3PrivatePutOrderOid';
971
+ response = await this.v3PrivatePutOrderOid(this.extend(request, params));
971
972
  }
972
- request['oid'] = id;
973
973
  }
974
- params = this.omit(params, ['clOrdID', 'clientOrderId', 'client_order_id', 'stopPrice', 'triggerPrice', 'takeProfitPrice', 'stopLossPrice']);
975
- const response = await this[method](this.extend(request, params));
976
974
  //
977
975
  // {
978
976
  // "code": 0,
@@ -1008,32 +1006,31 @@ export default class woo extends Exchange {
1008
1006
  this.checkRequiredSymbol('cancelOrder', symbol);
1009
1007
  }
1010
1008
  await this.loadMarkets();
1009
+ let market = undefined;
1010
+ if (symbol !== undefined) {
1011
+ market = this.market(symbol);
1012
+ }
1011
1013
  const request = {};
1012
1014
  const clientOrderIdUnified = this.safeString2(params, 'clOrdID', 'clientOrderId');
1013
1015
  const clientOrderIdExchangeSpecific = this.safeString(params, 'client_order_id', clientOrderIdUnified);
1014
1016
  const isByClientOrder = clientOrderIdExchangeSpecific !== undefined;
1015
- let method = undefined;
1017
+ let response = undefined;
1016
1018
  if (stop) {
1017
- method = 'v3PrivateDeleteAlgoOrderOrderId';
1018
1019
  request['order_id'] = id;
1019
- }
1020
- else if (isByClientOrder) {
1021
- method = 'v1PrivateDeleteClientOrder';
1022
- request['client_order_id'] = clientOrderIdExchangeSpecific;
1023
- params = this.omit(params, ['clOrdID', 'clientOrderId', 'client_order_id']);
1020
+ response = await this.v3PrivateDeleteAlgoOrderOrderId(this.extend(request, params));
1024
1021
  }
1025
1022
  else {
1026
- method = 'v1PrivateDeleteOrder';
1027
- request['order_id'] = id;
1028
- }
1029
- let market = undefined;
1030
- if (symbol !== undefined) {
1031
- market = this.market(symbol);
1032
- }
1033
- if (!stop) {
1034
1023
  request['symbol'] = market['id'];
1024
+ if (isByClientOrder) {
1025
+ request['client_order_id'] = clientOrderIdExchangeSpecific;
1026
+ params = this.omit(params, ['clOrdID', 'clientOrderId', 'client_order_id']);
1027
+ response = await this.v1PrivateDeleteClientOrder(this.extend(request, params));
1028
+ }
1029
+ else {
1030
+ request['order_id'] = id;
1031
+ response = await this.v1PrivateDeleteOrder(this.extend(request, params));
1032
+ }
1035
1033
  }
1036
- const response = await this[method](this.extend(request, params));
1037
1034
  //
1038
1035
  // { success: true, status: 'CANCEL_SENT' }
1039
1036
  //
@@ -1097,20 +1094,19 @@ export default class woo extends Exchange {
1097
1094
  params = this.omit(params, 'stop');
1098
1095
  const request = {};
1099
1096
  const clientOrderId = this.safeString2(params, 'clOrdID', 'clientOrderId');
1100
- let method = undefined;
1097
+ let response = undefined;
1101
1098
  if (stop) {
1102
- method = 'v3PrivateGetAlgoOrderOid';
1103
1099
  request['oid'] = id;
1100
+ response = await this.v3PrivateGetAlgoOrderOid(this.extend(request, params));
1104
1101
  }
1105
1102
  else if (clientOrderId) {
1106
- method = 'v1PrivateGetClientOrderClientOrderId';
1107
1103
  request['client_order_id'] = clientOrderId;
1104
+ response = await this.v1PrivateGetClientOrderClientOrderId(this.extend(request, params));
1108
1105
  }
1109
1106
  else {
1110
- method = 'v1PrivateGetOrderOid';
1111
1107
  request['oid'] = id;
1108
+ response = await this.v1PrivateGetOrderOid(this.extend(request, params));
1112
1109
  }
1113
- const response = await this[method](this.extend(request, params));
1114
1110
  //
1115
1111
  // {
1116
1112
  // success: true,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ccxt",
3
- "version": "4.1.30",
3
+ "version": "4.1.32",
4
4
  "description": "A JavaScript / TypeScript / Python / C# / PHP cryptocurrency trading library with support for 130+ exchanges",
5
5
  "unpkg": "dist/ccxt.browser.js",
6
6
  "type": "module",
@@ -39,7 +39,7 @@
39
39
  "fast-test": "npm run commonjs-test && node run-tests --js",
40
40
  "commonjs-test": "node test-commonjs.cjs",
41
41
  "fast-test-ws": "node run-tests-ws --js",
42
- "test-js": "npm run commonjs-test && node run-tests --js",
42
+ "test-js": "npm run commonjs-test && node js/src/test/static/test.ids && node run-tests --js",
43
43
  "test-js-ws": "node run-tests-ws --js",
44
44
  "test-py": "node run-tests --python",
45
45
  "test-py-ws": "node run-tests-ws --python",