ccxt 4.5.30 → 4.5.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 (73) hide show
  1. package/README.md +4 -4
  2. package/dist/ccxt.browser.min.js +18 -18
  3. package/dist/cjs/ccxt.js +6 -4
  4. package/dist/cjs/src/aster.js +3802 -0
  5. package/dist/cjs/src/backpack.js +1 -1
  6. package/dist/cjs/src/base/Exchange.js +35 -2
  7. package/dist/cjs/src/base/ws/WsClient.js +1 -0
  8. package/dist/cjs/src/bigone.js +1 -1
  9. package/dist/cjs/src/binance.js +1 -0
  10. package/dist/cjs/src/bingx.js +73 -0
  11. package/dist/cjs/src/cryptomus.js +1 -1
  12. package/dist/cjs/src/gate.js +52 -6
  13. package/dist/cjs/src/hyperliquid.js +9 -1
  14. package/dist/cjs/src/kucoin.js +63 -64
  15. package/dist/cjs/src/okx.js +14 -5
  16. package/dist/cjs/src/pro/apex.js +2 -2
  17. package/dist/cjs/src/pro/ascendex.js +1 -1
  18. package/dist/cjs/src/pro/aster.js +1046 -0
  19. package/dist/cjs/src/pro/bingx.js +1 -1
  20. package/dist/cjs/src/pro/bybit.js +1 -1
  21. package/dist/cjs/src/pro/cryptocom.js +1 -1
  22. package/dist/cjs/src/pro/dydx.js +1 -1
  23. package/dist/cjs/src/pro/htx.js +1 -1
  24. package/dist/cjs/src/pro/hyperliquid.js +1 -1
  25. package/dist/cjs/src/pro/p2b.js +1 -1
  26. package/dist/cjs/src/pro/toobit.js +1 -1
  27. package/js/ccxt.d.ts +8 -5
  28. package/js/ccxt.js +6 -4
  29. package/js/src/abstract/aster.d.ts +88 -0
  30. package/js/src/abstract/binance.d.ts +1 -0
  31. package/js/src/abstract/binancecoinm.d.ts +1 -0
  32. package/js/src/abstract/binanceus.d.ts +1 -0
  33. package/js/src/abstract/binanceusdm.d.ts +1 -0
  34. package/js/src/abstract/kucoin.d.ts +2 -0
  35. package/js/src/abstract/kucoinfutures.d.ts +2 -0
  36. package/js/src/aster.d.ts +563 -0
  37. package/js/src/aster.js +3801 -0
  38. package/js/src/backpack.js +1 -1
  39. package/js/src/base/Exchange.d.ts +4 -0
  40. package/js/src/base/Exchange.js +35 -1
  41. package/js/src/base/ws/WsClient.js +1 -0
  42. package/js/src/bigone.js +1 -1
  43. package/js/src/binance.d.ts +1 -1
  44. package/js/src/binance.js +1 -0
  45. package/js/src/bingx.d.ts +12 -1
  46. package/js/src/bingx.js +73 -0
  47. package/js/src/cryptomus.js +1 -1
  48. package/js/src/exmo.d.ts +1 -1
  49. package/js/src/gate.js +52 -6
  50. package/js/src/hyperliquid.d.ts +1 -0
  51. package/js/src/hyperliquid.js +9 -1
  52. package/js/src/kucoin.d.ts +5 -3
  53. package/js/src/kucoin.js +63 -64
  54. package/js/src/okx.js +14 -5
  55. package/js/src/pro/apex.js +2 -2
  56. package/js/src/pro/ascendex.js +1 -1
  57. package/js/src/pro/aster.d.ts +273 -0
  58. package/js/src/pro/aster.js +1045 -0
  59. package/js/src/pro/bingx.js +1 -1
  60. package/js/src/pro/bybit.js +1 -1
  61. package/js/src/pro/cryptocom.js +1 -1
  62. package/js/src/pro/dydx.js +1 -1
  63. package/js/src/pro/htx.js +1 -1
  64. package/js/src/pro/hyperliquid.js +1 -1
  65. package/js/src/pro/p2b.js +1 -1
  66. package/js/src/pro/toobit.js +1 -1
  67. package/package.json +1 -1
  68. package/dist/cjs/src/oceanex.js +0 -1125
  69. package/js/src/abstract/oceanex.d.ts +0 -30
  70. package/js/src/oceanex.d.ts +0 -231
  71. package/js/src/oceanex.js +0 -1124
  72. /package/dist/cjs/src/abstract/{oceanex.js → aster.js} +0 -0
  73. /package/js/src/abstract/{oceanex.js → aster.js} +0 -0
@@ -522,7 +522,7 @@ export default class backpack extends Exchange {
522
522
  // "depositEnabled": true,
523
523
  // "displayName": "Jito",
524
524
  // "maximumWithdrawal": null,
525
- // "minimumDeposit": "0.29",
525
+ // "minimumDeposit": "0.28",
526
526
  // "minimumWithdrawal": "0.58",
527
527
  // "withdrawEnabled": true,
528
528
  // "withdrawalFee": "0.29"
@@ -387,10 +387,12 @@ export default class Exchange {
387
387
  arraySlice(array: any, first: any, second?: any): any;
388
388
  getProperty(obj: any, property: any, defaultValue?: any): any;
389
389
  setProperty(obj: any, property: any, defaultValue?: any): void;
390
+ exceptionMessage(exc: any, includeStack?: boolean): string;
390
391
  axolotl(payload: any, hexKey: any, ed25519: any): string;
391
392
  fixStringifiedJsonMembers(content: string): string;
392
393
  ethAbiEncode(types: any, args: any): Uint8Array;
393
394
  ethEncodeStructuredData(domain: any, messageTypes: any, messageData: any): Uint8Array;
395
+ ethGetAddressFromPrivateKey(privateKey: string): string;
394
396
  retrieveStarkAccount(signature: any, accountClassHash: any, accountProxyClassHash: any): {
395
397
  privateKey: string;
396
398
  publicKey: string;
@@ -823,6 +825,7 @@ export default class Exchange {
823
825
  fetchOpenOrders(symbol?: Str, since?: Int, limit?: Int, params?: {}): Promise<Order[]>;
824
826
  fetchOpenOrdersWs(symbol?: Str, since?: Int, limit?: Int, params?: {}): Promise<Order[]>;
825
827
  fetchClosedOrders(symbol?: Str, since?: Int, limit?: Int, params?: {}): Promise<Order[]>;
828
+ fetchCanceledOrders(symbol?: Str, since?: Int, limit?: Int, params?: {}): Promise<Order[]>;
826
829
  fetchCanceledAndClosedOrders(symbol?: Str, since?: Int, limit?: Int, params?: {}): Promise<Order[]>;
827
830
  fetchClosedOrdersWs(symbol?: Str, since?: Int, limit?: Int, params?: {}): Promise<Order[]>;
828
831
  fetchMyTrades(symbol?: Str, since?: Int, limit?: Int, params?: {}): Promise<Trade[]>;
@@ -973,6 +976,7 @@ export default class Exchange {
973
976
  convertExpireDateToMarketIdDate(date: string): string;
974
977
  convertMarketIdExpireDate(date: string): string;
975
978
  fetchPositionHistory(symbol: string, since?: Int, limit?: Int, params?: {}): Promise<Position[]>;
979
+ loadMarketsAndSignIn(): Promise<void>;
976
980
  fetchPositionsHistory(symbols?: Strings, since?: Int, limit?: Int, params?: {}): Promise<Position[]>;
977
981
  parseMarginModification(data: Dict, market?: Market): MarginModification;
978
982
  parseMarginModifications(response: object[], symbols?: Strings, symbolKey?: Str, marketType?: MarketType): MarginModification[];
@@ -23,6 +23,8 @@ import { axolotl } from './functions/crypto.js';
23
23
  import { totp } from './functions/totp.js';
24
24
  import ethers from '../static_dependencies/ethers/index.js';
25
25
  import { TypedDataEncoder } from '../static_dependencies/ethers/hash/index.js';
26
+ import { secp256k1 } from '../static_dependencies/noble-curves/secp256k1.js';
27
+ import { keccak_256 } from '../static_dependencies/noble-hashes/sha3.js';
26
28
  import { SecureRandom } from '../static_dependencies/jsencrypt/lib/jsbn/rng.js';
27
29
  import { getStarkKey, ethSigToPrivate, sign as starknetCurveSign } from '../static_dependencies/scure-starknet/index.js';
28
30
  import init, * as zklink from '../static_dependencies/zklink/zklink-sdk-web.js';
@@ -597,12 +599,16 @@ export default class Exchange {
597
599
  return undefined;
598
600
  }
599
601
  isBinaryMessage(msg) {
600
- return msg instanceof Uint8Array;
602
+ return msg instanceof Uint8Array || msg instanceof ArrayBuffer;
601
603
  }
602
604
  decodeProtoMsg(data) {
603
605
  if (!protobufMexc) {
604
606
  throw new NotSupported(this.id + ' requires protobuf to decode messages, please install it with `npm install protobufjs`');
605
607
  }
608
+ if (data instanceof ArrayBuffer) {
609
+ // browser case
610
+ data = new Uint8Array(data);
611
+ }
606
612
  if (data instanceof Uint8Array) {
607
613
  const decoded = protobufMexc.default.PushDataV3ApiWrapper.decode(data);
608
614
  const dict = decoded.toJSON();
@@ -1275,6 +1281,11 @@ export default class Exchange {
1275
1281
  setProperty(obj, property, defaultValue = undefined) {
1276
1282
  obj[property] = defaultValue;
1277
1283
  }
1284
+ exceptionMessage(exc, includeStack = true) {
1285
+ const message = '[' + exc.constructor.name + '] ' + (!includeStack ? exc.message : exc.stack);
1286
+ const length = Math.min(100000, message.length);
1287
+ return message.slice(0, length);
1288
+ }
1278
1289
  axolotl(payload, hexKey, ed25519) {
1279
1290
  return axolotl(payload, hexKey, ed25519);
1280
1291
  }
@@ -1295,6 +1306,23 @@ export default class Exchange {
1295
1306
  ethEncodeStructuredData(domain, messageTypes, messageData) {
1296
1307
  return this.base16ToBinary(TypedDataEncoder.encode(domain, messageTypes, messageData).slice(-132));
1297
1308
  }
1309
+ ethGetAddressFromPrivateKey(privateKey) {
1310
+ // Accepts a "0x"-prefixed hexstring private key and returns the corresponding Ethereum address
1311
+ // Removes the "0x" prefix if present
1312
+ const cleanPrivateKey = this.remove0xPrefix(privateKey);
1313
+ // Get the public key from the private key using secp256k1 curve
1314
+ const publicKeyBytes = secp256k1.getPublicKey(cleanPrivateKey);
1315
+ // For Ethereum, we need to use the uncompressed public key (without the first byte which indicates compression)
1316
+ // secp256k1.getPublicKey returns compressed key, we need uncompressed
1317
+ const publicKeyUncompressed = secp256k1.ProjectivePoint.fromHex(publicKeyBytes).toRawBytes(false).slice(1); // Remove 0x04 prefix
1318
+ // Hash the public key with Keccak256
1319
+ const publicKeyHash = keccak_256(publicKeyUncompressed);
1320
+ // Take the last 20 bytes (40 hex chars)
1321
+ const addressBytes = publicKeyHash.slice(-20);
1322
+ // Convert to hex and add 0x prefix
1323
+ const addressHex = '0x' + this.binaryToBase16(addressBytes);
1324
+ return addressHex;
1325
+ }
1298
1326
  retrieveStarkAccount(signature, accountClassHash, accountProxyClassHash) {
1299
1327
  const privateKey = ethSigToPrivate(signature);
1300
1328
  const publicKey = getStarkKey(privateKey);
@@ -5967,6 +5995,9 @@ export default class Exchange {
5967
5995
  }
5968
5996
  throw new NotSupported(this.id + ' fetchClosedOrders() is not supported yet');
5969
5997
  }
5998
+ async fetchCanceledOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
5999
+ throw new NotSupported(this.id + ' fetchCanceledOrders() is not supported yet');
6000
+ }
5970
6001
  async fetchCanceledAndClosedOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
5971
6002
  throw new NotSupported(this.id + ' fetchCanceledAndClosedOrders() is not supported yet');
5972
6003
  }
@@ -7717,6 +7748,9 @@ export default class Exchange {
7717
7748
  throw new NotSupported(this.id + ' fetchPositionHistory () is not supported yet');
7718
7749
  }
7719
7750
  }
7751
+ async loadMarketsAndSignIn() {
7752
+ await Promise.all([this.loadMarkets(), this.signIn()]);
7753
+ }
7720
7754
  async fetchPositionsHistory(symbols = undefined, since = undefined, limit = undefined, params = {}) {
7721
7755
  /**
7722
7756
  * @method
@@ -42,6 +42,7 @@ export default class WsClient extends Client {
42
42
  }
43
43
  else {
44
44
  this.connection = new WebSocketPlatform(this.url, this.protocols);
45
+ this.connection.binaryType = "arraybuffer"; // for browsers not to use blob by default
45
46
  }
46
47
  this.connection.onopen = this.onOpen.bind(this);
47
48
  this.connection.onmessage = this.onMessage.bind(this);
package/js/src/bigone.js CHANGED
@@ -857,7 +857,7 @@ export default class bigone extends Exchange {
857
857
  'close': close,
858
858
  'last': close,
859
859
  'previousClose': undefined,
860
- 'change': this.safeString2(ticker, 'daily_change', 'last24hPriceChange'),
860
+ 'change': this.safeString(ticker, 'daily_change'),
861
861
  'percentage': undefined,
862
862
  'average': undefined,
863
863
  'baseVolume': this.safeString2(ticker, 'volume', 'volume24h'),
@@ -553,7 +553,7 @@ export default class binance extends Exchange {
553
553
  * @param {boolean} [params.trigger] set to true if you would like to fetch portfolio margin account trigger or conditional orders
554
554
  * @returns {object[]} a list of [order structures]{@link https://docs.ccxt.com/?id=order-structure}
555
555
  */
556
- fetchCanceledOrders(symbol?: Str, since?: Int, limit?: Int, params?: {}): Promise<any>;
556
+ fetchCanceledOrders(symbol?: Str, since?: Int, limit?: Int, params?: {}): Promise<Order[]>;
557
557
  /**
558
558
  * @method
559
559
  * @name binance#fetchCanceledAndClosedOrders
package/js/src/binance.js CHANGED
@@ -1004,6 +1004,7 @@ export default class binance extends Exchange {
1004
1004
  'block/order/execute': 5,
1005
1005
  'block/user-trades': 5,
1006
1006
  'blockTrades': 5,
1007
+ 'comission': 5,
1007
1008
  },
1008
1009
  'post': {
1009
1010
  'order': 1,
package/js/src/bingx.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import Exchange from './abstract/bingx.js';
2
- import type { TransferEntry, Int, OrderSide, OHLCV, FundingRateHistory, Order, OrderType, OrderRequest, Str, Trade, Balances, Transaction, Ticker, OrderBook, Tickers, Market, Strings, Currency, Position, Dict, Leverage, MarginMode, Num, MarginModification, Currencies, int, TradingFeeInterface, FundingRate, FundingRates, DepositAddress } from './base/types.js';
2
+ import type { LeverageTier, TransferEntry, Int, OrderSide, OHLCV, FundingRateHistory, Order, OrderType, OrderRequest, Str, Trade, Balances, Transaction, Ticker, OrderBook, Tickers, Market, Strings, Currency, Position, Dict, Leverage, MarginMode, Num, MarginModification, Currencies, int, TradingFeeInterface, FundingRate, FundingRates, DepositAddress } from './base/types.js';
3
3
  /**
4
4
  * @class bingx
5
5
  * @augments Exchange
@@ -766,6 +766,17 @@ export default class bingx extends Exchange {
766
766
  fetchTradingFee(symbol: string, params?: {}): Promise<TradingFeeInterface>;
767
767
  parseTradingFee(fee: Dict, market?: Market): TradingFeeInterface;
768
768
  customEncode(params: any): any;
769
+ /**
770
+ * @method
771
+ * @name bingx#fetchMarketLeverageTiers
772
+ * @description retrieve information on the maximum leverage, for different trade sizes for a single market
773
+ * @see https://bingx-api.github.io/docs-v3/#/en/Swap/Trades%20Endpoints/Position%20and%20Maintenance%20Margin%20Ratio
774
+ * @param {string} symbol unified market symbol
775
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
776
+ * @returns {object} a [leverage tiers structure]{@link https://docs.ccxt.com/?id=leverage-tiers-structure}
777
+ */
778
+ fetchMarketLeverageTiers(symbol: string, params?: {}): Promise<LeverageTier[]>;
779
+ parseMarketLeverageTiers(info: any, market?: Market): LeverageTier[];
769
780
  sign(path: any, section?: string, method?: string, params?: {}, headers?: any, body?: any): {
770
781
  url: string;
771
782
  method: string;
package/js/src/bingx.js CHANGED
@@ -85,6 +85,7 @@ export default class bingx extends Exchange {
85
85
  'fetchLiquidations': false,
86
86
  'fetchMarginAdjustmentHistory': false,
87
87
  'fetchMarginMode': true,
88
+ 'fetchMarketLeverageTiers': true,
88
89
  'fetchMarkets': true,
89
90
  'fetchMarkOHLCV': true,
90
91
  'fetchMarkPrice': true,
@@ -6661,6 +6662,78 @@ export default class bingx extends Exchange {
6661
6662
  }
6662
6663
  return result;
6663
6664
  }
6665
+ /**
6666
+ * @method
6667
+ * @name bingx#fetchMarketLeverageTiers
6668
+ * @description retrieve information on the maximum leverage, for different trade sizes for a single market
6669
+ * @see https://bingx-api.github.io/docs-v3/#/en/Swap/Trades%20Endpoints/Position%20and%20Maintenance%20Margin%20Ratio
6670
+ * @param {string} symbol unified market symbol
6671
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
6672
+ * @returns {object} a [leverage tiers structure]{@link https://docs.ccxt.com/?id=leverage-tiers-structure}
6673
+ */
6674
+ async fetchMarketLeverageTiers(symbol, params = {}) {
6675
+ await this.loadMarkets();
6676
+ const market = this.market(symbol);
6677
+ if (!market['swap']) {
6678
+ throw new BadRequest(this.id + ' fetchMarketLeverageTiers() supports swap markets only');
6679
+ }
6680
+ const request = {
6681
+ 'symbol': market['id'],
6682
+ };
6683
+ const response = await this.swapV1PrivateGetMaintMarginRatio(this.extend(request, params));
6684
+ //
6685
+ // {
6686
+ // "code": 0,
6687
+ // "msg": "",
6688
+ // "timestamp": 1767789967284,
6689
+ // "data": [
6690
+ // {
6691
+ // "tier": "Tier 1",
6692
+ // "symbol": "ETH-USDT",
6693
+ // "minPositionVal": "0",
6694
+ // "maxPositionVal": "900000",
6695
+ // "maintMarginRatio": "0.003300",
6696
+ // "maintAmount": "0.000000"
6697
+ // }
6698
+ // ]
6699
+ // }
6700
+ //
6701
+ const data = this.safeList(response, 'data', []);
6702
+ return this.parseMarketLeverageTiers(data, market);
6703
+ }
6704
+ parseMarketLeverageTiers(info, market = undefined) {
6705
+ //
6706
+ // [
6707
+ // {
6708
+ // "tier": "Tier 1",
6709
+ // "symbol": "ETH-USDT",
6710
+ // "minPositionVal": "0",
6711
+ // "maxPositionVal": "900000",
6712
+ // "maintMarginRatio": "0.003300",
6713
+ // "maintAmount": "0.000000"
6714
+ // }
6715
+ // ]
6716
+ //
6717
+ const tiers = [];
6718
+ for (let i = 0; i < info.length; i++) {
6719
+ const tier = this.safeDict(info, i);
6720
+ const tierString = this.safeString(tier, 'tier');
6721
+ const tierParts = tierString.split(' ');
6722
+ const marketId = this.safeString(tier, 'symbol');
6723
+ market = this.safeMarket(marketId, market, undefined, 'swap');
6724
+ tiers.push({
6725
+ 'tier': this.safeNumber(tierParts, 1),
6726
+ 'symbol': this.safeSymbol(marketId, market),
6727
+ 'currency': this.safeString(market, 'settle'),
6728
+ 'minNotional': this.safeNumber(tier, 'minPositionVal'),
6729
+ 'maxNotional': this.safeNumber(tier, 'maxPositionVal'),
6730
+ 'maintenanceMarginRate': this.safeNumber(tier, 'maintMarginRatio'),
6731
+ 'maxLeverage': undefined,
6732
+ 'info': tier,
6733
+ });
6734
+ }
6735
+ return tiers;
6736
+ }
6664
6737
  sign(path, section = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
6665
6738
  let type = section[0];
6666
6739
  let version = section[1];
@@ -80,7 +80,7 @@ export default class cryptomus extends Exchange {
80
80
  'fetchConvertTradeHistory': false,
81
81
  'fetchCrossBorrowRate': false,
82
82
  'fetchCrossBorrowRates': false,
83
- 'fetchCurrencies': true,
83
+ 'fetchCurrencies': false,
84
84
  'fetchDepositAddress': false,
85
85
  'fetchDeposits': false,
86
86
  'fetchDepositsWithdrawals': false,
package/js/src/exmo.d.ts CHANGED
@@ -308,7 +308,7 @@ export default class exmo extends Exchange {
308
308
  * @param {string} [params.marginMode] set to "isolated" for margin orders
309
309
  * @returns {object} a list of [order structures]{@link https://docs.ccxt.com/?id=order-structure}
310
310
  */
311
- fetchCanceledOrders(symbol?: Str, since?: Int, limit?: Int, params?: {}): Promise<any[]>;
311
+ fetchCanceledOrders(symbol?: Str, since?: Int, limit?: Int, params?: {}): Promise<Order[]>;
312
312
  /**
313
313
  * @method
314
314
  * @name exmo#editOrder
package/js/src/gate.js CHANGED
@@ -4973,6 +4973,24 @@ export default class gate extends Exchange {
4973
4973
  //
4974
4974
  // {"user_id":10406147,"id":"id","succeeded":false,"message":"INVALID_PROTOCOL","label":"INVALID_PROTOCOL"}
4975
4975
  //
4976
+ // cancel trigger order returns timestamps in ms
4977
+ // id: '2007047737421336576',
4978
+ // id_string: '2007047737421336576',
4979
+ // trigger_time: '0',
4980
+ // trade_id: '0',
4981
+ // trade_id_string: '',
4982
+ // status: 'finished',
4983
+ // finish_as: 'cancelled',
4984
+ // reason: '',
4985
+ // create_time: '1767352444402496'
4986
+ // finish_time: '1767352509535790',
4987
+ // is_stop_order: false,
4988
+ // stop_trigger: { rule: '0', trigger_price: '', order_price: '' },
4989
+ // me_order_id: '0',
4990
+ // me_order_id_string: '',
4991
+ // order_type: '',
4992
+ // in_dual_mode: false,
4993
+ // parent_id: '0',
4976
4994
  const succeeded = this.safeBool(order, 'succeeded', true);
4977
4995
  if (!succeeded) {
4978
4996
  // cancelOrders response
@@ -5015,13 +5033,33 @@ export default class gate extends Exchange {
5015
5033
  side = Precise.stringGt(amount, '0') ? 'buy' : 'sell';
5016
5034
  }
5017
5035
  const rawStatus = this.safeStringN(order, ['finish_as', 'status', 'open']);
5018
- let timestamp = this.safeInteger(order, 'create_time_ms');
5019
- if (timestamp === undefined) {
5020
- timestamp = this.safeTimestamp2(order, 'create_time', 'ctime');
5036
+ let timestampStr = this.safeString(order, 'create_time_ms');
5037
+ if (timestampStr === undefined) {
5038
+ timestampStr = this.safeString2(order, 'create_time', 'ctime');
5039
+ if (timestampStr !== undefined) {
5040
+ if (timestampStr.length === 10 || timestampStr.indexOf('.') >= 0) {
5041
+ // ts in seconds, multiply to ms
5042
+ timestampStr = Precise.stringMul(timestampStr, '1000');
5043
+ }
5044
+ else if (timestampStr.length === 16) {
5045
+ // ts in microseconds, divide to ms
5046
+ timestampStr = Precise.stringDiv(timestampStr, '1000');
5047
+ }
5048
+ }
5021
5049
  }
5022
- let lastTradeTimestamp = this.safeInteger(order, 'update_time_ms');
5023
- if (lastTradeTimestamp === undefined) {
5024
- lastTradeTimestamp = this.safeTimestamp2(order, 'update_time', 'finish_time');
5050
+ let lastTradeTimestampStr = this.safeString(order, 'update_time_ms');
5051
+ if (lastTradeTimestampStr === undefined) {
5052
+ lastTradeTimestampStr = this.safeString2(order, 'update_time', 'finish_time');
5053
+ if (lastTradeTimestampStr !== undefined) {
5054
+ if (lastTradeTimestampStr.length === 10 || lastTradeTimestampStr.indexOf('.') >= 0) {
5055
+ // ts in seconds, multiply to ms
5056
+ lastTradeTimestampStr = Precise.stringMul(lastTradeTimestampStr, '1000');
5057
+ }
5058
+ else if (lastTradeTimestampStr.length === 16) {
5059
+ // ts in microseconds, divide to ms
5060
+ lastTradeTimestampStr = Precise.stringDiv(lastTradeTimestampStr, '1000');
5061
+ }
5062
+ }
5025
5063
  }
5026
5064
  let marketType = 'contract';
5027
5065
  if (('currency_pair' in order) || ('market' in order)) {
@@ -5068,6 +5106,14 @@ export default class gate extends Exchange {
5068
5106
  amount = Precise.stringDiv(amount, averageString);
5069
5107
  }
5070
5108
  }
5109
+ let timestamp = undefined;
5110
+ let lastTradeTimestamp = undefined;
5111
+ if (timestampStr !== undefined) {
5112
+ timestamp = this.parseToInt(timestampStr);
5113
+ }
5114
+ if (lastTradeTimestampStr !== undefined) {
5115
+ lastTradeTimestamp = this.parseToInt(lastTradeTimestampStr);
5116
+ }
5071
5117
  return this.safeOrder({
5072
5118
  'id': this.safeString(order, 'id'),
5073
5119
  'clientOrderId': this.safeString(order, 'text'),
@@ -88,6 +88,7 @@ export default class hyperliquid extends Exchange {
88
88
  */
89
89
  fetchSpotMarkets(params?: {}): Promise<Market[]>;
90
90
  parseMarket(market: Dict): Market;
91
+ updateSpotCurrencyCode(code: string): string;
91
92
  /**
92
93
  * @method
93
94
  * @name hyperliquid#fetchBalance
@@ -1063,6 +1063,13 @@ export default class hyperliquid extends Exchange {
1063
1063
  'info': market,
1064
1064
  });
1065
1065
  }
1066
+ updateSpotCurrencyCode(code) {
1067
+ if (code === undefined) {
1068
+ return code;
1069
+ }
1070
+ const spotCurrencyMapping = this.safeDict(this.options, 'spotCurrencyMapping', {});
1071
+ return this.safeString(spotCurrencyMapping, code, code);
1072
+ }
1066
1073
  /**
1067
1074
  * @method
1068
1075
  * @name hyperliquid#fetchBalance
@@ -1130,7 +1137,8 @@ export default class hyperliquid extends Exchange {
1130
1137
  const spotBalances = { 'info': response };
1131
1138
  for (let i = 0; i < balances.length; i++) {
1132
1139
  const balance = balances[i];
1133
- const code = this.safeCurrencyCode(this.safeString(balance, 'coin'));
1140
+ const unifiedCode = this.safeCurrencyCode(this.safeString(balance, 'coin'));
1141
+ const code = isSpot ? this.updateSpotCurrencyCode(unifiedCode) : unifiedCode;
1134
1142
  const account = this.account();
1135
1143
  const total = this.safeString(balance, 'total');
1136
1144
  const used = this.safeString(balance, 'hold');
@@ -569,17 +569,19 @@ export default class kucoin extends Exchange {
569
569
  * @method
570
570
  * @name kucoin#transfer
571
571
  * @description transfer currency internally between wallets on the same account
572
- * @see https://www.kucoin.com/docs/rest/funding/transfer/inner-transfer
573
- * @see https://docs.kucoin.com/futures/#transfer-funds-to-kucoin-main-account-2
574
- * @see https://docs.kucoin.com/spot-hf/#internal-funds-transfers-in-high-frequency-trading-accounts
572
+ * @see https://www.kucoin.com/docs-new/rest/account-info/transfer/flex-transfer?lang=en_US&
575
573
  * @param {string} code unified currency code
576
574
  * @param {float} amount amount to transfer
577
575
  * @param {string} fromAccount account to transfer from
578
576
  * @param {string} toAccount account to transfer to
579
577
  * @param {object} [params] extra parameters specific to the exchange API endpoint
578
+ * @param {string} [params.transferType] INTERNAL, PARENT_TO_SUB, SUB_TO_PARENT (default is INTERNAL)
579
+ * @param {string} [params.fromUserId] required if transferType is SUB_TO_PARENT
580
+ * @param {string} [params.toUserId] required if transferType is PARENT_TO_SUB
580
581
  * @returns {object} a [transfer structure]{@link https://docs.ccxt.com/?id=transfer-structure}
581
582
  */
582
583
  transfer(code: string, amount: number, fromAccount: string, toAccount: string, params?: {}): Promise<TransferEntry>;
584
+ isHfOrMining(fromId: Str, toId: Str): boolean;
583
585
  parseTransfer(transfer: Dict, currency?: Currency): TransferEntry;
584
586
  parseTransferStatus(status: Str): Str;
585
587
  parseLedgerEntryType(type: any): string;
package/js/src/kucoin.js CHANGED
@@ -183,6 +183,7 @@ export default class kucoin extends Exchange {
183
183
  'get': {
184
184
  // account
185
185
  'user-info': 30,
186
+ 'user/api-key': 30,
186
187
  'accounts': 7.5,
187
188
  'accounts/{accountId}': 7.5,
188
189
  'accounts/ledgers': 3,
@@ -267,6 +268,8 @@ export default class kucoin extends Exchange {
267
268
  'convert/limit/orders': 5,
268
269
  // affiliate
269
270
  'affiliate/inviter/statistics': 30,
271
+ // earn
272
+ 'earn/redeem-preview': 5, // 5EW
270
273
  },
271
274
  'post': {
272
275
  // account
@@ -714,6 +717,9 @@ export default class kucoin extends Exchange {
714
717
  'withdraw': {
715
718
  'includeFee': false,
716
719
  },
720
+ 'transfer': {
721
+ 'fillResponseFromRequest': true,
722
+ },
717
723
  // endpoint versions
718
724
  'versions': {
719
725
  'public': {
@@ -4584,96 +4590,89 @@ export default class kucoin extends Exchange {
4584
4590
  * @method
4585
4591
  * @name kucoin#transfer
4586
4592
  * @description transfer currency internally between wallets on the same account
4587
- * @see https://www.kucoin.com/docs/rest/funding/transfer/inner-transfer
4588
- * @see https://docs.kucoin.com/futures/#transfer-funds-to-kucoin-main-account-2
4589
- * @see https://docs.kucoin.com/spot-hf/#internal-funds-transfers-in-high-frequency-trading-accounts
4593
+ * @see https://www.kucoin.com/docs-new/rest/account-info/transfer/flex-transfer?lang=en_US&
4590
4594
  * @param {string} code unified currency code
4591
4595
  * @param {float} amount amount to transfer
4592
4596
  * @param {string} fromAccount account to transfer from
4593
4597
  * @param {string} toAccount account to transfer to
4594
4598
  * @param {object} [params] extra parameters specific to the exchange API endpoint
4599
+ * @param {string} [params.transferType] INTERNAL, PARENT_TO_SUB, SUB_TO_PARENT (default is INTERNAL)
4600
+ * @param {string} [params.fromUserId] required if transferType is SUB_TO_PARENT
4601
+ * @param {string} [params.toUserId] required if transferType is PARENT_TO_SUB
4595
4602
  * @returns {object} a [transfer structure]{@link https://docs.ccxt.com/?id=transfer-structure}
4596
4603
  */
4597
4604
  async transfer(code, amount, fromAccount, toAccount, params = {}) {
4598
4605
  await this.loadMarkets();
4599
4606
  const currency = this.currency(code);
4600
4607
  const requestedAmount = this.currencyToPrecision(code, amount);
4608
+ const request = {
4609
+ 'currency': currency['id'],
4610
+ 'amount': requestedAmount,
4611
+ };
4612
+ let transferType = 'INTERNAL';
4613
+ [transferType, params] = this.handleParamString2(params, 'transferType', 'type', transferType);
4614
+ if (transferType === 'PARENT_TO_SUB') {
4615
+ if (!('toUserId' in params)) {
4616
+ throw new ExchangeError(this.id + ' transfer() requires a toUserId param for PARENT_TO_SUB transfers');
4617
+ }
4618
+ }
4619
+ else if (transferType === 'SUB_TO_PARENT') {
4620
+ if (!('fromUserId' in params)) {
4621
+ throw new ExchangeError(this.id + ' transfer() requires a fromUserId param for SUB_TO_PARENT transfers');
4622
+ }
4623
+ }
4624
+ if (!('clientOid' in params)) {
4625
+ request['clientOid'] = this.uuid();
4626
+ }
4601
4627
  let fromId = this.convertTypeToAccount(fromAccount);
4602
4628
  let toId = this.convertTypeToAccount(toAccount);
4603
4629
  const fromIsolated = this.inArray(fromId, this.ids);
4604
4630
  const toIsolated = this.inArray(toId, this.ids);
4605
- if (fromId === 'contract') {
4606
- if (toId !== 'main') {
4607
- throw new ExchangeError(this.id + ' transfer() only supports transferring from futures account to main account');
4608
- }
4609
- const request = {
4610
- 'currency': currency['id'],
4611
- 'amount': requestedAmount,
4612
- };
4613
- if (!('bizNo' in params)) {
4614
- // it doesn't like more than 24 characters
4615
- request['bizNo'] = this.uuid22();
4616
- }
4617
- const response = await this.futuresPrivatePostTransferOut(this.extend(request, params));
4618
- //
4619
- // {
4620
- // "code": "200000",
4621
- // "data": {
4622
- // "applyId": "605a87217dff1500063d485d",
4623
- // "bizNo": "bcd6e5e1291f4905af84dc",
4624
- // "payAccountType": "CONTRACT",
4625
- // "payTag": "DEFAULT",
4626
- // "remark": '',
4627
- // "recAccountType": "MAIN",
4628
- // "recTag": "DEFAULT",
4629
- // "recRemark": '',
4630
- // "recSystem": "KUCOIN",
4631
- // "status": "PROCESSING",
4632
- // "currency": "XBT",
4633
- // "amount": "0.00001",
4634
- // "fee": "0",
4635
- // "sn": "573688685663948",
4636
- // "reason": '',
4637
- // "createdAt": 1616545569000,
4638
- // "updatedAt": 1616545569000
4639
- // }
4640
- // }
4641
- //
4642
- const data = this.safeDict(response, 'data');
4643
- return this.parseTransfer(data, currency);
4631
+ if (fromIsolated) {
4632
+ request['fromAccountTag'] = fromId;
4633
+ fromId = 'isolated';
4644
4634
  }
4645
- else {
4646
- const request = {
4647
- 'currency': currency['id'],
4648
- 'amount': requestedAmount,
4649
- };
4650
- if (fromIsolated || toIsolated) {
4651
- if (this.inArray(fromId, this.ids)) {
4652
- request['fromTag'] = fromId;
4653
- fromId = 'isolated';
4654
- }
4655
- if (this.inArray(toId, this.ids)) {
4656
- request['toTag'] = toId;
4657
- toId = 'isolated';
4658
- }
4659
- }
4635
+ if (toIsolated) {
4636
+ request['toAccountTag'] = toId;
4637
+ toId = 'isolated';
4638
+ }
4639
+ const hfOrMining = this.isHfOrMining(fromId, toId);
4640
+ let response = undefined;
4641
+ if (hfOrMining) {
4642
+ // new endpoint does not support hf and mining transfers
4643
+ // use old endpoint for hf and mining transfers
4660
4644
  request['from'] = fromId;
4661
4645
  request['to'] = toId;
4662
- if (!('clientOid' in params)) {
4663
- request['clientOid'] = this.uuid();
4664
- }
4665
- const response = await this.privatePostAccountsInnerTransfer(this.extend(request, params));
4646
+ response = await this.privatePostAccountsInnerTransfer(this.extend(request, params));
4647
+ }
4648
+ else {
4649
+ request['type'] = transferType;
4650
+ request['fromAccountType'] = fromId.toUpperCase();
4651
+ request['toAccountType'] = toId.toUpperCase();
4666
4652
  //
4667
4653
  // {
4668
4654
  // "code": "200000",
4669
4655
  // "data": {
4670
- // "orderId": "605a6211e657f00006ad0ad6"
4656
+ // "orderId": "694fcb5b08bb1600015cda75"
4671
4657
  // }
4672
4658
  // }
4673
4659
  //
4674
- const data = this.safeDict(response, 'data');
4675
- return this.parseTransfer(data, currency);
4660
+ response = await this.privatePostAccountsUniversalTransfer(this.extend(request, params));
4676
4661
  }
4662
+ const data = this.safeDict(response, 'data');
4663
+ const transfer = this.parseTransfer(data, currency);
4664
+ const transferOptions = this.safeDict(this.options, 'transfer', {});
4665
+ const fillResponseFromRequest = this.safeBool(transferOptions, 'fillResponseFromRequest', true);
4666
+ if (fillResponseFromRequest) {
4667
+ transfer['amount'] = amount;
4668
+ transfer['fromAccount'] = fromAccount;
4669
+ transfer['toAccount'] = toAccount;
4670
+ transfer['status'] = 'ok';
4671
+ }
4672
+ return transfer;
4673
+ }
4674
+ isHfOrMining(fromId, toId) {
4675
+ return (fromId === 'trade_hf' || toId === 'trade_hf' || fromId === 'pool' || toId === 'pool');
4677
4676
  }
4678
4677
  parseTransfer(transfer, currency = undefined) {
4679
4678
  //