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
@@ -33,6 +33,7 @@ class hitbtc extends hitbtc$1 {
33
33
  'cancelOrder': true,
34
34
  'createDepositAddress': true,
35
35
  'createOrder': true,
36
+ 'createPostOnlyOrder': true,
36
37
  'createReduceOnlyOrder': true,
37
38
  'createStopLimitOrder': true,
38
39
  'createStopMarketOrder': true,
@@ -2047,14 +2048,24 @@ class hitbtc extends hitbtc$1 {
2047
2048
  * @param {float} amount how much of currency you want to trade in units of base currency
2048
2049
  * @param {float} [price] the price at which the order is to be fullfilled, in units of the quote currency, ignored in market orders
2049
2050
  * @param {object} [params] extra parameters specific to the hitbtc api endpoint
2050
- * @param {string} [params.marginMode] 'cross' or 'isolated' only 'isolated' is supported, defaults to spot-margin endpoint if this is set
2051
+ * @param {string} [params.marginMode] 'cross' or 'isolated' only 'isolated' is supported for spot-margin, swap supports both
2051
2052
  * @param {bool} [params.margin] true for creating a margin order
2052
2053
  * @param {float} [params.triggerPrice] The price at which a trigger order is triggered at
2054
+ * @param {bool} [params.postOnly] if true, the order will only be posted to the order book and not executed immediately
2055
+ * @param {string} [params.timeInForce] "GTC", "IOC", "FOK", "Day", "GTD"
2053
2056
  * @returns {object} an [order structure]{@link https://github.com/ccxt/ccxt/wiki/Manual#order-structure}
2054
2057
  */
2055
2058
  await this.loadMarkets();
2056
2059
  const market = this.market(symbol);
2057
2060
  const isLimit = (type === 'limit');
2061
+ const reduceOnly = this.safeValue(params, 'reduceOnly');
2062
+ const timeInForce = this.safeString(params, 'timeInForce');
2063
+ const triggerPrice = this.safeNumberN(params, ['triggerPrice', 'stopPrice', 'stop_price']);
2064
+ let marketType = undefined;
2065
+ [marketType, params] = this.handleMarketTypeAndParams('createOrder', market, params);
2066
+ let marginMode = undefined;
2067
+ [marginMode, params] = this.handleMarginModeAndParams('createOrder', params);
2068
+ const isPostOnly = this.isPostOnly(type === 'market', undefined, params);
2058
2069
  const request = {
2059
2070
  'type': type,
2060
2071
  'side': side,
@@ -2072,7 +2083,6 @@ class hitbtc extends hitbtc$1 {
2072
2083
  // 'take_rate': 0.001, // Optional
2073
2084
  // 'make_rate': 0.001, // Optional
2074
2085
  };
2075
- const reduceOnly = this.safeValue(params, 'reduceOnly');
2076
2086
  if (reduceOnly !== undefined) {
2077
2087
  if ((market['type'] !== 'swap') && (market['type'] !== 'margin')) {
2078
2088
  throw new errors.InvalidOrder(this.id + ' createOrder() does not support reduce_only for ' + market['type'] + ' orders, reduce_only orders are supported for swap and margin markets only');
@@ -2081,8 +2091,12 @@ class hitbtc extends hitbtc$1 {
2081
2091
  if (reduceOnly === true) {
2082
2092
  request['reduce_only'] = reduceOnly;
2083
2093
  }
2084
- const timeInForce = this.safeString2(params, 'timeInForce', 'time_in_force');
2085
- const triggerPrice = this.safeNumberN(params, ['triggerPrice', 'stopPrice', 'stop_price']);
2094
+ if (isPostOnly) {
2095
+ request['post_only'] = true;
2096
+ }
2097
+ if (timeInForce !== undefined) {
2098
+ request['time_in_force'] = timeInForce;
2099
+ }
2086
2100
  if (isLimit || (type === 'stopLimit') || (type === 'takeProfitLimit')) {
2087
2101
  if (price === undefined) {
2088
2102
  throw new errors.ExchangeError(this.id + ' createOrder() requires a price argument for limit orders');
@@ -2107,19 +2121,20 @@ class hitbtc extends hitbtc$1 {
2107
2121
  else if ((type === 'stopLimit') || (type === 'stopMarket') || (type === 'takeProfitLimit') || (type === 'takeProfitMarket')) {
2108
2122
  throw new errors.ExchangeError(this.id + ' createOrder() requires a stopPrice parameter for stop-loss and take-profit orders');
2109
2123
  }
2110
- let marketType = undefined;
2111
- [marketType, params] = this.handleMarketTypeAndParams('createOrder', market, params);
2112
- let method = this.getSupportedMapping(marketType, {
2113
- 'spot': 'privatePostSpotOrder',
2114
- 'swap': 'privatePostFuturesOrder',
2115
- 'margin': 'privatePostMarginOrder',
2116
- });
2117
- const [marginMode, query] = this.handleMarginModeAndParams('createOrder', params);
2118
- if (marginMode !== undefined) {
2119
- method = 'privatePostMarginOrder';
2124
+ params = this.omit(params, ['triggerPrice', 'timeInForce', 'stopPrice', 'stop_price', 'reduceOnly', 'postOnly']);
2125
+ if ((marketType === 'swap') && (marginMode !== undefined)) {
2126
+ request['margin_mode'] = marginMode;
2127
+ }
2128
+ let response = undefined;
2129
+ if (marketType === 'swap') {
2130
+ response = await this.privatePostFuturesOrder(this.extend(request, params));
2131
+ }
2132
+ else if ((marketType === 'margin') || (marginMode !== undefined)) {
2133
+ response = await this.privatePostMarginOrder(this.extend(request, params));
2134
+ }
2135
+ else {
2136
+ response = await this.privatePostSpotOrder(this.extend(request, params));
2120
2137
  }
2121
- params = this.omit(params, ['triggerPrice', 'timeInForce', 'time_in_force', 'stopPrice', 'stop_price', 'reduceOnly']);
2122
- const response = await this[method](this.extend(request, query));
2123
2138
  return this.parseOrder(response, market);
2124
2139
  }
2125
2140
  parseOrderStatus(status) {
@@ -3042,12 +3057,7 @@ class hitbtc extends hitbtc$1 {
3042
3057
  const isMargin = this.safeValue(params, 'margin', false);
3043
3058
  let marginMode = undefined;
3044
3059
  [marginMode, params] = super.handleMarginModeAndParams(methodName, params, defaultValue);
3045
- if (marginMode !== undefined) {
3046
- if (marginMode !== 'isolated') {
3047
- throw new errors.NotSupported(this.id + ' only isolated margin is supported');
3048
- }
3049
- }
3050
- else {
3060
+ if (marginMode === undefined) {
3051
3061
  if ((defaultType === 'margin') || (isMargin === true)) {
3052
3062
  marginMode = 'isolated';
3053
3063
  }
@@ -872,6 +872,7 @@ class huobi extends huobi$1 {
872
872
  '1220': errors.AccountNotEnabled,
873
873
  '1303': errors.BadRequest,
874
874
  '1461': errors.InvalidOrder,
875
+ '4007': errors.BadRequest,
875
876
  'bad-request': errors.BadRequest,
876
877
  'validation-format-error': errors.BadRequest,
877
878
  'validation-constraints-required': errors.BadRequest,
@@ -3014,6 +3015,13 @@ class huobi extends huobi$1 {
3014
3015
  /**
3015
3016
  * @method
3016
3017
  * @name huobi#fetchBalance
3018
+ * @see https://huobiapi.github.io/docs/spot/v1/en/#get-account-balance-of-a-specific-account
3019
+ * @see https://www.htx.com/en-us/opend/newApiPages/?id=7ec4b429-7773-11ed-9966-0242ac110003
3020
+ * @see https://www.htx.com/en-us/opend/newApiPages/?id=10000074-77b7-11ed-9966-0242ac110003
3021
+ * @see https://huobiapi.github.io/docs/dm/v1/en/#query-asset-valuation
3022
+ * @see https://huobiapi.github.io/docs/coin_margined_swap/v1/en/#query-user-s-account-information
3023
+ * @see https://huobiapi.github.io/docs/usdt_swap/v1/en/#isolated-query-user-s-account-information
3024
+ * @see https://huobiapi.github.io/docs/usdt_swap/v1/en/#cross-query-user-39-s-account-information
3017
3025
  * @description query for balance and get the amount of funds available for trading or funds locked in orders
3018
3026
  * @param {object} [params] extra parameters specific to the huobi api endpoint
3019
3027
  * @param {bool} [params.unified] provide this parameter if you have a recent account with unified cross+isolated margin account
@@ -3026,10 +3034,8 @@ class huobi extends huobi$1 {
3026
3034
  const isUnifiedAccount = this.safeValue2(params, 'isUnifiedAccount', 'unified', false);
3027
3035
  params = this.omit(params, ['isUnifiedAccount', 'unified']);
3028
3036
  const request = {};
3029
- let method = undefined;
3030
3037
  const spot = (type === 'spot');
3031
3038
  const future = (type === 'future');
3032
- const swap = (type === 'swap');
3033
3039
  const defaultSubType = this.safeString2(this.options, 'defaultSubType', 'subType', 'linear');
3034
3040
  let subType = this.safeString2(options, 'defaultSubType', 'subType', defaultSubType);
3035
3041
  subType = this.safeString2(params, 'defaultSubType', 'subType', subType);
@@ -3041,42 +3047,42 @@ class huobi extends huobi$1 {
3041
3047
  const isolated = (marginMode === 'isolated');
3042
3048
  const cross = (marginMode === 'cross');
3043
3049
  const margin = (type === 'margin') || (spot && (cross || isolated));
3050
+ let response = undefined;
3044
3051
  if (spot || margin) {
3045
3052
  if (margin) {
3046
3053
  if (isolated) {
3047
- method = 'spotPrivateGetV1MarginAccountsBalance';
3054
+ response = await this.spotPrivateGetV1MarginAccountsBalance(this.extend(request, params));
3048
3055
  }
3049
3056
  else {
3050
- method = 'spotPrivateGetV1CrossMarginAccountsBalance';
3057
+ response = await this.spotPrivateGetV1CrossMarginAccountsBalance(this.extend(request, params));
3051
3058
  }
3052
3059
  }
3053
3060
  else {
3054
3061
  await this.loadAccounts();
3055
3062
  const accountId = await this.fetchAccountIdByType(type, undefined, undefined, params);
3056
3063
  request['account-id'] = accountId;
3057
- method = 'spotPrivateGetV1AccountAccountsAccountIdBalance';
3064
+ response = await this.spotPrivateGetV1AccountAccountsAccountIdBalance(this.extend(request, params));
3058
3065
  }
3059
3066
  }
3060
3067
  else if (isUnifiedAccount) {
3061
- method = 'contractPrivateGetLinearSwapApiV3UnifiedAccountInfo';
3068
+ response = await this.contractPrivateGetLinearSwapApiV3UnifiedAccountInfo(this.extend(request, params));
3062
3069
  }
3063
3070
  else if (linear) {
3064
3071
  if (isolated) {
3065
- method = 'contractPrivatePostLinearSwapApiV1SwapAccountInfo';
3072
+ response = await this.contractPrivatePostLinearSwapApiV1SwapAccountInfo(this.extend(request, params));
3066
3073
  }
3067
3074
  else {
3068
- method = 'contractPrivatePostLinearSwapApiV1SwapCrossAccountInfo';
3075
+ response = await this.contractPrivatePostLinearSwapApiV1SwapCrossAccountInfo(this.extend(request, params));
3069
3076
  }
3070
3077
  }
3071
3078
  else if (inverse) {
3072
3079
  if (future) {
3073
- method = 'contractPrivatePostApiV1ContractAccountInfo';
3080
+ response = await this.contractPrivatePostApiV1ContractAccountInfo(this.extend(request, params));
3074
3081
  }
3075
- else if (swap) {
3076
- method = 'contractPrivatePostSwapApiV1SwapAccountInfo';
3082
+ else {
3083
+ response = await this.contractPrivatePostSwapApiV1SwapAccountInfo(this.extend(request, params));
3077
3084
  }
3078
3085
  }
3079
- const response = await this[method](this.extend(request, params));
3080
3086
  //
3081
3087
  // spot
3082
3088
  //
@@ -2343,6 +2343,7 @@ class krakenfutures extends krakenfutures$1 {
2343
2343
  }
2344
2344
  const url = this.urls['api'][api] + query;
2345
2345
  if (api === 'private' || access === 'private') {
2346
+ this.checkRequiredCredentials();
2346
2347
  let auth = postData + '/api/';
2347
2348
  if (api !== 'private') {
2348
2349
  auth += api + '/';
@@ -27,8 +27,8 @@ class mexc extends mexc$1 {
27
27
  'spot': true,
28
28
  'margin': true,
29
29
  'swap': true,
30
- 'future': true,
31
- 'option': undefined,
30
+ 'future': false,
31
+ 'option': false,
32
32
  'addMargin': true,
33
33
  'borrowMargin': true,
34
34
  'cancelAllOrders': true,
@@ -396,10 +396,6 @@ class mexc extends mexc$1 {
396
396
  'fetchMarkets': {
397
397
  'types': {
398
398
  'spot': true,
399
- 'future': {
400
- 'linear': false,
401
- 'inverse': false,
402
- },
403
399
  'swap': {
404
400
  'linear': true,
405
401
  'inverse': false,
@@ -3085,6 +3085,7 @@ class okx extends okx$1 {
3085
3085
  parseOrderStatus(status) {
3086
3086
  const statuses = {
3087
3087
  'canceled': 'canceled',
3088
+ 'order_failed': 'canceled',
3088
3089
  'live': 'open',
3089
3090
  'partially_filled': 'open',
3090
3091
  'filled': 'closed',
@@ -3633,17 +3633,19 @@ class phemex extends phemex$1 {
3633
3633
  // 'limit': 20, // Page size default 20, max 200
3634
3634
  // 'offset': 0, // Page start default 0
3635
3635
  };
3636
- if (limit > 200) {
3637
- throw new errors.BadRequest(this.id + ' fetchFundingHistory() limit argument cannot exceed 200');
3638
- }
3639
3636
  if (limit !== undefined) {
3637
+ if (limit > 200) {
3638
+ throw new errors.BadRequest(this.id + ' fetchFundingHistory() limit argument cannot exceed 200');
3639
+ }
3640
3640
  request['limit'] = limit;
3641
3641
  }
3642
- let method = 'privateGetApiDataFuturesFundingFees';
3642
+ let response = undefined;
3643
3643
  if (market['settle'] === 'USDT') {
3644
- method = 'privateGetApiDataGFuturesFundingFees';
3644
+ response = await this.privateGetApiDataGFuturesFundingFees(this.extend(request, params));
3645
+ }
3646
+ else {
3647
+ response = await this.privateGetApiDataFuturesFundingFees(this.extend(request, params));
3645
3648
  }
3646
- const response = await this[method](this.extend(request, params));
3647
3649
  //
3648
3650
  // {
3649
3651
  // "code": 0,
@@ -46,6 +46,12 @@ class bittrex extends bittrex$1 {
46
46
  'maxRetries': 3,
47
47
  },
48
48
  },
49
+ 'exceptions': {
50
+ 'exact': {
51
+ 'INVALID_APIKEY': errors.AuthenticationError,
52
+ 'UNAUTHORIZED_USER': errors.AuthenticationError,
53
+ },
54
+ },
49
55
  });
50
56
  }
51
57
  getSignalRUrl(negotiation) {
@@ -96,6 +102,7 @@ class bittrex extends bittrex$1 {
96
102
  return await this.watch(url, messageHash, request, messageHash, subscription);
97
103
  }
98
104
  async authenticate(params = {}) {
105
+ this.checkRequiredCredentials();
99
106
  await this.loadMarkets();
100
107
  const request = await this.negotiate();
101
108
  return await this.sendRequestToAuthenticate(request, false, params);
@@ -116,7 +123,7 @@ class bittrex extends bittrex$1 {
116
123
  'negotiation': negotiation,
117
124
  'method': this.handleAuthenticate,
118
125
  };
119
- this.spawn(this.watch, url, messageHash, request, requestId, subscription);
126
+ this.watch(url, messageHash, request, requestId, subscription);
120
127
  }
121
128
  return await future;
122
129
  }
@@ -523,7 +530,9 @@ class bittrex extends bittrex$1 {
523
530
  * @returns {object[]} a list of [trade structures]{@link https://github.com/ccxt/ccxt/wiki/Manual#trade-structure
524
531
  */
525
532
  await this.loadMarkets();
526
- symbol = this.symbol(symbol);
533
+ if (symbol !== undefined) {
534
+ symbol = this.symbol(symbol);
535
+ }
527
536
  const authentication = await this.authenticate();
528
537
  const trades = await this.subscribeToMyTrades(authentication, params);
529
538
  if (this.newUpdates) {
@@ -788,6 +797,60 @@ class bittrex extends bittrex$1 {
788
797
  }
789
798
  return message;
790
799
  }
800
+ handleErrorMessage(client, message) {
801
+ //
802
+ // {
803
+ // R: [{ Success: false, ErrorCode: 'UNAUTHORIZED_USER' }, ... ],
804
+ // I: '1698601759267'
805
+ // }
806
+ // {
807
+ // R: { Success: false, ErrorCode: 'INVALID_APIKEY' },
808
+ // I: '1698601759266'
809
+ // }
810
+ //
811
+ const R = this.safeValue(message, 'R');
812
+ if (R === undefined) {
813
+ // Return there is no error
814
+ return false;
815
+ }
816
+ const I = this.safeString(message, 'I');
817
+ let errorCode = undefined;
818
+ if (Array.isArray(R)) {
819
+ for (let i = 0; i < R.length; i++) {
820
+ const response = this.safeValue(R, i);
821
+ const success = this.safeValue(response, 'Success', true);
822
+ if (!success) {
823
+ errorCode = this.safeString(response, 'ErrorCode');
824
+ break;
825
+ }
826
+ }
827
+ }
828
+ else {
829
+ const success = this.safeValue(R, 'Success', true);
830
+ if (!success) {
831
+ errorCode = this.safeString(R, 'ErrorCode');
832
+ }
833
+ }
834
+ if (errorCode === undefined) {
835
+ // Return there is no error
836
+ return false;
837
+ }
838
+ const feedback = this.id + ' ' + errorCode;
839
+ try {
840
+ this.throwExactlyMatchedException(this.exceptions['exact'], errorCode, feedback);
841
+ if (message !== undefined) {
842
+ this.throwBroadlyMatchedException(this.exceptions['broad'], errorCode, feedback);
843
+ }
844
+ throw new errors.ExchangeError(feedback);
845
+ }
846
+ catch (e) {
847
+ if (e instanceof errors.AuthenticationError) {
848
+ client.reject(e, 'authenticate');
849
+ }
850
+ client.reject(e, I);
851
+ }
852
+ return true;
853
+ }
791
854
  handleMessage(client, message) {
792
855
  //
793
856
  // subscription confirmation
@@ -834,6 +897,9 @@ class bittrex extends bittrex$1 {
834
897
  // M: [ { H: 'C3', M: 'authenticationExpiring', A: [] } ]
835
898
  // }
836
899
  //
900
+ if (this.handleErrorMessage(client, message)) {
901
+ return;
902
+ }
837
903
  const methods = {
838
904
  'authenticationExpiring': this.handleAuthenticationExpiring,
839
905
  'order': this.handleOrder,
@@ -102,7 +102,8 @@ class huobi extends huobi$1 {
102
102
  '2021': errors.BadRequest,
103
103
  '2001': errors.BadSymbol,
104
104
  '2011': errors.BadSymbol,
105
- '2040': errors.BadRequest, // { op: 'sub', cid: '1649152947', 'err-code': 2040, 'err-msg': 'Missing required parameter.', ts: 1649152948684 }
105
+ '2040': errors.BadRequest,
106
+ '4007': errors.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 }
106
107
  },
107
108
  },
108
109
  },
@@ -1191,12 +1192,12 @@ class huobi extends huobi$1 {
1191
1192
  * @param {object} [params] extra parameters specific to the huobi api endpoint
1192
1193
  * @returns {object} a [balance structure]{@link https://github.com/ccxt/ccxt/wiki/Manual#balance-structure}
1193
1194
  */
1194
- let type = this.safeString2(this.options, 'watchBalance', 'defaultType', 'spot');
1195
- type = this.safeString(params, 'type', type);
1196
- let subType = this.safeString2(this.options, 'watchBalance', 'subType', 'linear');
1197
- subType = this.safeString(params, 'subType', subType);
1198
- params = this.omit(params, ['type', 'subType']);
1199
- params = this.omit(params, 'type');
1195
+ let type = undefined;
1196
+ [type, params] = this.handleMarketTypeAndParams('watchBalance', undefined, params);
1197
+ let subType = undefined;
1198
+ [subType, params] = this.handleSubTypeAndParams('watchBalance', undefined, params, 'linear');
1199
+ const isUnifiedAccount = this.safeValue2(params, 'isUnifiedAccount', 'unified', false);
1200
+ params = this.omit(params, ['isUnifiedAccount', 'unified']);
1200
1201
  await this.loadMarkets();
1201
1202
  let messageHash = undefined;
1202
1203
  let channel = undefined;
@@ -1217,29 +1218,37 @@ class huobi extends huobi$1 {
1217
1218
  let prefix = 'accounts';
1218
1219
  messageHash = prefix;
1219
1220
  if (subType === 'linear') {
1220
- // usdt contracts account
1221
- prefix = (marginMode === 'cross') ? prefix + '_cross' : prefix;
1222
- messageHash = prefix;
1223
- if (marginMode === 'isolated') {
1224
- // isolated margin only allows filtering by symbol3
1225
- if (symbol !== undefined) {
1226
- messageHash += '.' + market['id'];
1227
- channel = messageHash;
1228
- }
1229
- else {
1230
- // subscribe to all
1231
- channel = prefix + '.' + '*';
1232
- }
1221
+ if (isUnifiedAccount) {
1222
+ // usdt contracts account
1223
+ prefix = 'accounts_unify';
1224
+ messageHash = prefix;
1225
+ channel = prefix + '.' + 'usdt';
1233
1226
  }
1234
1227
  else {
1235
- // cross margin
1236
- if (currencyCode !== undefined) {
1237
- channel = prefix + '.' + currencyCode['id'];
1238
- messageHash = channel;
1228
+ // usdt contracts account
1229
+ prefix = (marginMode === 'cross') ? prefix + '_cross' : prefix;
1230
+ messageHash = prefix;
1231
+ if (marginMode === 'isolated') {
1232
+ // isolated margin only allows filtering by symbol3
1233
+ if (symbol !== undefined) {
1234
+ messageHash += '.' + market['id'];
1235
+ channel = messageHash;
1236
+ }
1237
+ else {
1238
+ // subscribe to all
1239
+ channel = prefix + '.' + '*';
1240
+ }
1239
1241
  }
1240
1242
  else {
1241
- // subscribe to all
1242
- channel = prefix + '.' + '*';
1243
+ // cross margin
1244
+ if (currencyCode !== undefined) {
1245
+ channel = prefix + '.' + currencyCode['id'];
1246
+ messageHash = channel;
1247
+ }
1248
+ else {
1249
+ // subscribe to all
1250
+ channel = prefix + '.' + '*';
1251
+ }
1243
1252
  }
1244
1253
  }
1245
1254
  }
@@ -1417,7 +1426,9 @@ class huobi extends huobi$1 {
1417
1426
  return;
1418
1427
  }
1419
1428
  const first = this.safeValue(data, 0, {});
1420
- let messageHash = this.safeString(message, 'topic');
1429
+ const topic = this.safeString(message, 'topic');
1430
+ const splitTopic = topic.split('.');
1431
+ let messageHash = this.safeString(splitTopic, 0);
1421
1432
  let subscription = this.safeValue2(client.subscriptions, messageHash, messageHash + '.*');
1422
1433
  if (subscription === undefined) {
1423
1434
  // if subscription not found means that we subscribed to a specific currency/symbol
@@ -1425,13 +1436,37 @@ class huobi extends huobi$1 {
1425
1436
  // Example: topic = 'accounts'
1426
1437
  // client.subscription hash = 'accounts.usdt'
1427
1438
  // we do 'accounts' + '.' + data[0]]['margin_asset'] to get it
1428
- const marginAsset = this.safeString(first, 'margin_asset');
1429
- messageHash += '.' + marginAsset.toLowerCase();
1439
+ const currencyId = this.safeString2(first, 'margin_asset', 'symbol');
1440
+ messageHash += '.' + currencyId.toLowerCase();
1430
1441
  subscription = this.safeValue(client.subscriptions, messageHash);
1431
1442
  }
1432
1443
  const type = this.safeString(subscription, 'type');
1433
1444
  const subType = this.safeString(subscription, 'subType');
1434
- if (subType === 'linear') {
1445
+ if (topic === 'accounts_unify') {
1446
+ // {
1447
+ // margin_asset: 'USDT',
1448
+ // margin_static: 10,
1449
+ // cross_margin_static: 10,
1450
+ // margin_balance: 10,
1451
+ // cross_profit_unreal: 0,
1452
+ // margin_frozen: 0,
1453
+ // withdraw_available: 10,
1454
+ // cross_risk_rate: null,
1455
+ // cross_swap: [],
1456
+ // cross_future: [],
1457
+ // isolated_swap: []
1458
+ // }
1459
+ const marginAsset = this.safeString(first, 'margin_asset');
1460
+ const code = this.safeCurrencyCode(marginAsset);
1461
+ const marginFrozen = this.safeString(first, 'margin_frozen');
1462
+ const unifiedAccount = this.account();
1463
+ unifiedAccount['free'] = this.safeString(first, 'withdraw_available');
1464
+ unifiedAccount['used'] = marginFrozen;
1465
+ this.balance[code] = unifiedAccount;
1466
+ this.balance = this.safeBalance(this.balance);
1467
+ client.resolve(this.balance, 'accounts_unify');
1468
+ }
1469
+ else if (subType === 'linear') {
1435
1470
  const margin = this.safeString(subscription, 'margin');
1436
1471
  if (margin === 'cross') {
1437
1472
  const fieldName = (type === 'future') ? 'futures_contract_detail' : 'contract_detail';
@@ -1729,6 +1764,15 @@ class huobi extends huobi$1 {
1729
1764
  // id: '2'
1730
1765
  // }
1731
1766
  //
1767
+ // {
1768
+ // op: 'sub',
1769
+ // cid: '1',
1770
+ // topic: 'accounts_unify.USDT',
1771
+ // 'err-code': 4007,
1772
+ // 'err-msg': 'Non - single account user is not available, please check through the cross and isolated account asset interface',
1773
+ // ts: 1698419490189
1774
+ // }
1775
+ //
1732
1776
  const status = this.safeString(message, 'status');
1733
1777
  if (status === 'error') {
1734
1778
  const id = this.safeString(message, 'id');
@@ -1750,8 +1794,8 @@ class huobi extends huobi$1 {
1750
1794
  }
1751
1795
  return false;
1752
1796
  }
1753
- const code = this.safeInteger(message, 'code');
1754
- if (code !== undefined && code !== 200) {
1797
+ const code = this.safeInteger2(message, 'code', 'err-code');
1798
+ if (code !== undefined && ((code !== 200) && (code !== 0))) {
1755
1799
  const feedback = this.id + ' ' + this.json(message);
1756
1800
  try {
1757
1801
  this.throwExactlyMatchedException(this.exceptions['ws']['exact'], code, feedback);
@@ -947,29 +947,27 @@ class woo extends woo$1 {
947
947
  if (stopPrice !== undefined) {
948
948
  request['triggerPrice'] = this.priceToPrecision(symbol, stopPrice);
949
949
  }
950
+ params = this.omit(params, ['clOrdID', 'clientOrderId', 'client_order_id', 'stopPrice', 'triggerPrice', 'takeProfitPrice', 'stopLossPrice']);
950
951
  const isStop = (stopPrice !== undefined) || (this.safeValue(params, 'childOrders') !== undefined);
951
- let method = undefined;
952
+ let response = undefined;
952
953
  if (isByClientOrder) {
954
+ request['client_order_id'] = clientOrderIdExchangeSpecific;
953
955
  if (isStop) {
954
- method = 'v3PrivatePutAlgoOrderClientClientOrderId';
955
- request['oid'] = id;
956
+ response = await this.v3PrivatePutAlgoOrderClientClientOrderId(this.extend(request, params));
956
957
  }
957
958
  else {
958
- method = 'v3PrivatePutOrderClientClientOrderId';
959
- request['client_order_id'] = clientOrderIdExchangeSpecific;
959
+ response = await this.v3PrivatePutOrderClientClientOrderId(this.extend(request, params));
960
960
  }
961
961
  }
962
962
  else {
963
+ request['oid'] = id;
963
964
  if (isStop) {
964
- method = 'v3PrivatePutAlgoOrderOid';
965
+ response = await this.v3PrivatePutAlgoOrderOid(this.extend(request, params));
965
966
  }
966
967
  else {
967
- method = 'v3PrivatePutOrderOid';
968
+ response = await this.v3PrivatePutOrderOid(this.extend(request, params));
968
969
  }
969
- request['oid'] = id;
970
970
  }
971
- params = this.omit(params, ['clOrdID', 'clientOrderId', 'client_order_id', 'stopPrice', 'triggerPrice', 'takeProfitPrice', 'stopLossPrice']);
972
- const response = await this[method](this.extend(request, params));
973
971
  //
974
972
  // {
975
973
  // "code": 0,
@@ -1005,32 +1003,31 @@ class woo extends woo$1 {
1005
1003
  this.checkRequiredSymbol('cancelOrder', symbol);
1006
1004
  }
1007
1005
  await this.loadMarkets();
1006
+ let market = undefined;
1007
+ if (symbol !== undefined) {
1008
+ market = this.market(symbol);
1009
+ }
1008
1010
  const request = {};
1009
1011
  const clientOrderIdUnified = this.safeString2(params, 'clOrdID', 'clientOrderId');
1010
1012
  const clientOrderIdExchangeSpecific = this.safeString(params, 'client_order_id', clientOrderIdUnified);
1011
1013
  const isByClientOrder = clientOrderIdExchangeSpecific !== undefined;
1012
- let method = undefined;
1014
+ let response = undefined;
1013
1015
  if (stop) {
1014
- method = 'v3PrivateDeleteAlgoOrderOrderId';
1015
1016
  request['order_id'] = id;
1016
- }
1017
- else if (isByClientOrder) {
1018
- method = 'v1PrivateDeleteClientOrder';
1019
- request['client_order_id'] = clientOrderIdExchangeSpecific;
1020
- params = this.omit(params, ['clOrdID', 'clientOrderId', 'client_order_id']);
1017
+ response = await this.v3PrivateDeleteAlgoOrderOrderId(this.extend(request, params));
1021
1018
  }
1022
1019
  else {
1023
- method = 'v1PrivateDeleteOrder';
1024
- request['order_id'] = id;
1025
- }
1026
- let market = undefined;
1027
- if (symbol !== undefined) {
1028
- market = this.market(symbol);
1029
- }
1030
- if (!stop) {
1031
1020
  request['symbol'] = market['id'];
1021
+ if (isByClientOrder) {
1022
+ request['client_order_id'] = clientOrderIdExchangeSpecific;
1023
+ params = this.omit(params, ['clOrdID', 'clientOrderId', 'client_order_id']);
1024
+ response = await this.v1PrivateDeleteClientOrder(this.extend(request, params));
1025
+ }
1026
+ else {
1027
+ request['order_id'] = id;
1028
+ response = await this.v1PrivateDeleteOrder(this.extend(request, params));
1029
+ }
1032
1030
  }
1033
- const response = await this[method](this.extend(request, params));
1034
1031
  //
1035
1032
  // { success: true, status: 'CANCEL_SENT' }
1036
1033
  //
@@ -1094,20 +1091,19 @@ class woo extends woo$1 {
1094
1091
  params = this.omit(params, 'stop');
1095
1092
  const request = {};
1096
1093
  const clientOrderId = this.safeString2(params, 'clOrdID', 'clientOrderId');
1097
- let method = undefined;
1094
+ let response = undefined;
1098
1095
  if (stop) {
1099
- method = 'v3PrivateGetAlgoOrderOid';
1100
1096
  request['oid'] = id;
1097
+ response = await this.v3PrivateGetAlgoOrderOid(this.extend(request, params));
1101
1098
  }
1102
1099
  else if (clientOrderId) {
1103
- method = 'v1PrivateGetClientOrderClientOrderId';
1104
1100
  request['client_order_id'] = clientOrderId;
1101
+ response = await this.v1PrivateGetClientOrderClientOrderId(this.extend(request, params));
1105
1102
  }
1106
1103
  else {
1107
- method = 'v1PrivateGetOrderOid';
1108
1104
  request['oid'] = id;
1105
+ response = await this.v1PrivateGetOrderOid(this.extend(request, params));
1109
1106
  }
1110
- const response = await this[method](this.extend(request, params));
1111
1107
  //
1112
1108
  // {
1113
1109
  // success: true,