ccxt 4.2.68 → 4.2.69

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.
@@ -88,6 +88,7 @@ export default class bitstamp extends Exchange {
88
88
  'setLeverage': false,
89
89
  'setMarginMode': false,
90
90
  'setPositionMode': false,
91
+ 'transfer': true,
91
92
  'withdraw': true,
92
93
  },
93
94
  'urls': {
@@ -2122,6 +2123,73 @@ export default class bitstamp extends Exchange {
2122
2123
  const response = await this[method](this.extend(request, params));
2123
2124
  return this.parseTransaction(response, currency);
2124
2125
  }
2126
+ async transfer(code, amount, fromAccount, toAccount, params = {}) {
2127
+ /**
2128
+ * @method
2129
+ * @name bitstamp#transfer
2130
+ * @description transfer currency internally between wallets on the same account
2131
+ * @see https://www.bitstamp.net/api/#tag/Sub-account/operation/TransferFromMainToSub
2132
+ * @see https://www.bitstamp.net/api/#tag/Sub-account/operation/TransferFromSubToMain
2133
+ * @param {string} code unified currency code
2134
+ * @param {float} amount amount to transfer
2135
+ * @param {string} fromAccount account to transfer from
2136
+ * @param {string} toAccount account to transfer to
2137
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2138
+ * @returns {object} a [transfer structure]{@link https://docs.ccxt.com/#/?id=transfer-structure}
2139
+ */
2140
+ await this.loadMarkets();
2141
+ const currency = this.currency(code);
2142
+ amount = this.currencyToPrecision(code, amount);
2143
+ amount = this.parseToNumeric(amount);
2144
+ const request = {
2145
+ 'amount': amount,
2146
+ 'currency': currency['id'].toUpperCase(),
2147
+ };
2148
+ let response = undefined;
2149
+ if (fromAccount === 'main') {
2150
+ request['subAccount'] = toAccount;
2151
+ response = await this.privatePostTransferFromMain(this.extend(request, params));
2152
+ }
2153
+ else if (toAccount === 'main') {
2154
+ request['subAccount'] = fromAccount;
2155
+ response = await this.privatePostTransferToMain(this.extend(request, params));
2156
+ }
2157
+ else {
2158
+ throw new BadRequest(this.id + ' transfer() only supports from or to main');
2159
+ }
2160
+ //
2161
+ // { status: 'ok' }
2162
+ //
2163
+ const transfer = this.parseTransfer(response, currency);
2164
+ transfer['amount'] = amount;
2165
+ transfer['fromAccount'] = fromAccount;
2166
+ transfer['toAccount'] = toAccount;
2167
+ return transfer;
2168
+ }
2169
+ parseTransfer(transfer, currency = undefined) {
2170
+ //
2171
+ // { status: 'ok' }
2172
+ //
2173
+ const status = this.safeString(transfer, 'status');
2174
+ return {
2175
+ 'info': transfer,
2176
+ 'id': undefined,
2177
+ 'timestamp': undefined,
2178
+ 'datetime': undefined,
2179
+ 'currency': currency['code'],
2180
+ 'amount': undefined,
2181
+ 'fromAccount': undefined,
2182
+ 'toAccount': undefined,
2183
+ 'status': this.parseTransferStatus(status),
2184
+ };
2185
+ }
2186
+ parseTransferStatus(status) {
2187
+ const statuses = {
2188
+ 'ok': 'ok',
2189
+ 'error': 'failed',
2190
+ };
2191
+ return this.safeString(statuses, status, status);
2192
+ }
2125
2193
  nonce() {
2126
2194
  return this.milliseconds();
2127
2195
  }
package/js/src/gate.js CHANGED
@@ -4483,7 +4483,10 @@ export default class gate extends Exchange {
4483
4483
  if (lastTradeTimestamp === undefined) {
4484
4484
  lastTradeTimestamp = this.safeTimestamp2(order, 'update_time', 'finish_time');
4485
4485
  }
4486
- const marketType = ('currency_pair' in order) ? 'spot' : 'contract';
4486
+ let marketType = 'contract';
4487
+ if (('currency_pair' in order) || ('market' in order)) {
4488
+ marketType = 'spot';
4489
+ }
4487
4490
  const exchangeSymbol = this.safeString2(order, 'currency_pair', 'market', contract);
4488
4491
  const symbol = this.safeSymbol(exchangeSymbol, market, '_', marketType);
4489
4492
  // Everything below this(above return) is related to fees
@@ -12,7 +12,7 @@ export default class gemini extends Exchange {
12
12
  fetchMarketsFromWeb(params?: {}): Promise<any[]>;
13
13
  parseMarketActive(status: any): boolean;
14
14
  fetchUSDTMarkets(params?: {}): Promise<any[]>;
15
- fetchMarketsFromAPI(params?: {}): Promise<unknown[]>;
15
+ fetchMarketsFromAPI(params?: {}): Promise<any[]>;
16
16
  parseMarket(response: any): Market;
17
17
  fetchOrderBook(symbol: string, limit?: Int, params?: {}): Promise<OrderBook>;
18
18
  fetchTickerV1(symbol: string, params?: {}): Promise<Ticker>;
package/js/src/gemini.js CHANGED
@@ -30,7 +30,7 @@ export default class gemini extends Exchange {
30
30
  'CORS': undefined,
31
31
  'spot': true,
32
32
  'margin': false,
33
- 'swap': false,
33
+ 'swap': true,
34
34
  'future': false,
35
35
  'option': false,
36
36
  'addMargin': false,
@@ -255,11 +255,11 @@ export default class gemini extends Exchange {
255
255
  },
256
256
  },
257
257
  'options': {
258
- 'fetchMarketsMethod': 'fetch_markets_from_web',
258
+ 'fetchMarketsMethod': 'fetch_markets_from_api',
259
259
  'fetchMarketFromWebRetries': 10,
260
260
  'fetchMarketsFromAPI': {
261
261
  'fetchDetailsForAllSymbols': false,
262
- 'fetchDetailsForMarketIds': [],
262
+ 'quoteCurrencies': ['USDT', 'GUSD', 'USD', 'DAI', 'EUR', 'GBP', 'SGD', 'BTC', 'ETH', 'LTC', 'BCH'],
263
263
  },
264
264
  'fetchMarkets': {
265
265
  'webApiEnable': true,
@@ -315,10 +315,7 @@ export default class gemini extends Exchange {
315
315
  }
316
316
  //
317
317
  // {
318
- // "tradingPairs": [
319
- // [ "BTCAUD", 2, 8, "0.00001", 10, true ],
320
- // ...
321
- // ],
318
+ // "tradingPairs": [ [ 'BTCUSD', 2, 8, '0.00001', 10, true ], ... ],
322
319
  // "currencies": [
323
320
  // [ "ORCA", "Orca", 204, 6, 0, 6, 8, false, null, "solana" ], // as confirmed, precisions seem to be the 5th index
324
321
  // [ "ATOM", "Cosmos", 44, 6, 0, 6, 8, false, null, "cosmos" ],
@@ -337,6 +334,7 @@ export default class gemini extends Exchange {
337
334
  // }
338
335
  //
339
336
  const result = {};
337
+ this.options['tradingPairs'] = this.safeList(data, 'tradingPairs');
340
338
  const currenciesArray = this.safeValue(data, 'currencies', []);
341
339
  for (let i = 0; i < currenciesArray.length; i++) {
342
340
  const currency = currenciesArray[i];
@@ -546,7 +544,7 @@ export default class gemini extends Exchange {
546
544
  return result;
547
545
  }
548
546
  async fetchMarketsFromAPI(params = {}) {
549
- const response = await this.publicGetV1Symbols(params);
547
+ const marketIdsRaw = await this.publicGetV1Symbols(params);
550
548
  //
551
549
  // [
552
550
  // "btcusd",
@@ -554,93 +552,185 @@ export default class gemini extends Exchange {
554
552
  // ...
555
553
  // ]
556
554
  //
557
- const result = {};
558
- for (let i = 0; i < response.length; i++) {
559
- const marketId = response[i];
560
- const market = {
561
- 'symbol': marketId,
562
- };
563
- result[marketId] = this.parseMarket(market);
555
+ const result = [];
556
+ const options = this.safeDict(this.options, 'fetchMarketsFromAPI', {});
557
+ const bugSymbol = 'efilfil'; // we skip this inexistent test symbol, which bugs other functions
558
+ const marketIds = [];
559
+ for (let i = 0; i < marketIdsRaw.length; i++) {
560
+ if (marketIdsRaw[i] !== bugSymbol) {
561
+ marketIds.push(marketIdsRaw[i]);
562
+ }
564
563
  }
565
- const options = this.safeValue(this.options, 'fetchMarketsFromAPI', {});
566
- const fetchDetailsForAllSymbols = this.safeBool(options, 'fetchDetailsForAllSymbols', false);
567
- const fetchDetailsForMarketIds = this.safeValue(options, 'fetchDetailsForMarketIds', []);
568
- let promises = [];
569
- let marketIds = [];
570
- if (fetchDetailsForAllSymbols) {
571
- marketIds = response;
564
+ if (this.safeBool(options, 'fetchDetailsForAllSymbols', false)) {
565
+ const promises = [];
566
+ for (let i = 0; i < marketIds.length; i++) {
567
+ const marketId = marketIds[i];
568
+ const request = {
569
+ 'symbol': marketId,
570
+ };
571
+ promises.push(this.publicGetV1SymbolsDetailsSymbol(this.extend(request, params)));
572
+ //
573
+ // {
574
+ // "symbol": "BTCUSD",
575
+ // "base_currency": "BTC",
576
+ // "quote_currency": "USD",
577
+ // "tick_size": 1E-8,
578
+ // "quote_increment": 0.01,
579
+ // "min_order_size": "0.00001",
580
+ // "status": "open",
581
+ // "wrap_enabled": false
582
+ // }
583
+ //
584
+ }
585
+ const responses = await Promise.all(promises);
586
+ for (let i = 0; i < responses.length; i++) {
587
+ result.push(this.parseMarket(responses[i]));
588
+ }
572
589
  }
573
590
  else {
574
- marketIds = fetchDetailsForMarketIds;
575
- }
576
- for (let i = 0; i < marketIds.length; i++) {
577
- const marketId = marketIds[i];
578
- const request = {
579
- 'symbol': marketId,
580
- };
581
- promises.push(this.publicGetV1SymbolsDetailsSymbol(this.extend(request, params)));
582
- //
583
- // {
584
- // "symbol": "BTCUSD",
585
- // "base_currency": "BTC",
586
- // "quote_currency": "USD",
587
- // "tick_size": 1E-8,
588
- // "quote_increment": 0.01,
589
- // "min_order_size": "0.00001",
590
- // "status": "open",
591
- // "wrap_enabled": false
592
- // }
593
- //
594
- }
595
- promises = await Promise.all(promises);
596
- for (let i = 0; i < promises.length; i++) {
597
- const responseInner = promises[i];
598
- const marketId = this.safeStringLower(responseInner, 'symbol');
599
- result[marketId] = this.parseMarket(responseInner);
591
+ // use trading-pairs info, if it was fetched
592
+ const tradingPairs = this.safeList(this.options, 'tradingPairs');
593
+ if (tradingPairs !== undefined) {
594
+ const indexedTradingPairs = this.indexBy(tradingPairs, 0);
595
+ for (let i = 0; i < marketIds.length; i++) {
596
+ const marketId = marketIds[i];
597
+ const tradingPair = this.safeList(indexedTradingPairs, marketId.toUpperCase());
598
+ if (tradingPair !== undefined) {
599
+ result.push(this.parseMarket(tradingPair));
600
+ }
601
+ }
602
+ }
603
+ else {
604
+ for (let i = 0; i < marketIds.length; i++) {
605
+ result.push(this.parseMarket(marketIds[i]));
606
+ }
607
+ }
600
608
  }
601
- return this.toArray(result);
609
+ return result;
602
610
  }
603
611
  parseMarket(response) {
604
- const marketId = this.safeStringLower(response, 'symbol');
605
- let baseId = this.safeString(response, 'base_currency');
606
- let quoteId = this.safeString(response, 'quote_currency');
607
- if (baseId === undefined) {
608
- const idLength = marketId.length - 0;
609
- const isUSDT = marketId.indexOf('usdt') >= 0;
610
- const quoteSize = isUSDT ? 4 : 3;
611
- baseId = marketId.slice(0, idLength - quoteSize); // Not true for all markets
612
- quoteId = marketId.slice(idLength - quoteSize, idLength);
612
+ //
613
+ // response might be:
614
+ //
615
+ // btcusd
616
+ //
617
+ // or
618
+ //
619
+ // [
620
+ // 'BTCUSD', // symbol
621
+ // 2, // priceTickDecimalPlaces
622
+ // 8, // quantityTickDecimalPlaces
623
+ // '0.00001', // quantityMinimum
624
+ // 10, // quantityRoundDecimalPlaces
625
+ // true // minimumsAreInclusive
626
+ // ],
627
+ //
628
+ // or
629
+ //
630
+ // {
631
+ // "symbol": "BTCUSD", // perpetuals have 'PERP' suffix, i.e. DOGEUSDPERP
632
+ // "base_currency": "BTC",
633
+ // "quote_currency": "USD",
634
+ // "tick_size": 1E-8,
635
+ // "quote_increment": 0.01,
636
+ // "min_order_size": "0.00001",
637
+ // "status": "open",
638
+ // "wrap_enabled": false
639
+ // "product_type": "swap", // only in perps
640
+ // "contract_type": "linear", // only in perps
641
+ // "contract_price_currency": "GUSD" // only in perps
642
+ // }
643
+ //
644
+ let marketId = undefined;
645
+ let baseId = undefined;
646
+ let quoteId = undefined;
647
+ let settleId = undefined;
648
+ let tickSize = undefined;
649
+ let increment = undefined;
650
+ let minSize = undefined;
651
+ let status = undefined;
652
+ let swap = false;
653
+ let contractSize = undefined;
654
+ let linear = undefined;
655
+ let inverse = undefined;
656
+ const isString = (typeof response === 'string');
657
+ const isArray = (Array.isArray(response));
658
+ if (!isString && !isArray) {
659
+ marketId = this.safeStringLower(response, 'symbol');
660
+ minSize = this.safeNumber(response, 'min_order_size');
661
+ tickSize = this.safeNumber(response, 'tick_size');
662
+ increment = this.safeNumber(response, 'quote_increment');
663
+ status = this.parseMarketActive(this.safeString(response, 'status'));
664
+ baseId = this.safeString(response, 'base_currency');
665
+ quoteId = this.safeString(response, 'quote_currency');
666
+ settleId = this.safeString(response, 'contract_price_currency');
667
+ }
668
+ else {
669
+ // if no detailed API was called, then parse either string or array
670
+ if (isString) {
671
+ marketId = response;
672
+ }
673
+ else {
674
+ marketId = this.safeStringLower(response, 0);
675
+ minSize = this.safeNumber(response, 3);
676
+ tickSize = this.parseNumber(this.parsePrecision(this.safeString(response, 1)));
677
+ increment = this.parseNumber(this.parsePrecision(this.safeString(response, 2)));
678
+ }
679
+ const marketIdUpper = marketId.toUpperCase();
680
+ const isPerp = (marketIdUpper.indexOf('PERP') >= 0);
681
+ const marketIdWithoutPerp = marketIdUpper.replace('PERP', '');
682
+ const quoteQurrencies = this.handleOption('fetchMarketsFromAPI', 'quoteCurrencies', []);
683
+ for (let i = 0; i < quoteQurrencies.length; i++) {
684
+ const quoteCurrency = quoteQurrencies[i];
685
+ if (marketIdWithoutPerp.endsWith(quoteCurrency)) {
686
+ baseId = marketIdWithoutPerp.replace(quoteCurrency, '');
687
+ quoteId = quoteCurrency;
688
+ if (isPerp) {
689
+ settleId = quoteCurrency; // always same
690
+ }
691
+ break;
692
+ }
693
+ }
613
694
  }
614
695
  const base = this.safeCurrencyCode(baseId);
615
696
  const quote = this.safeCurrencyCode(quoteId);
616
- const status = this.safeString(response, 'status');
697
+ const settle = this.safeCurrencyCode(settleId);
698
+ let symbol = base + '/' + quote;
699
+ if (settleId !== undefined) {
700
+ symbol = symbol + ':' + settle;
701
+ swap = true;
702
+ contractSize = tickSize; // always same
703
+ linear = true; // always linear
704
+ inverse = false;
705
+ }
706
+ const type = swap ? 'swap' : 'spot';
617
707
  return {
618
708
  'id': marketId,
619
- 'symbol': base + '/' + quote,
709
+ 'symbol': symbol,
620
710
  'base': base,
621
711
  'quote': quote,
622
- 'settle': undefined,
712
+ 'settle': settle,
623
713
  'baseId': baseId,
624
714
  'quoteId': quoteId,
625
- 'settleId': undefined,
626
- 'type': 'spot',
627
- 'spot': true,
715
+ 'settleId': settleId,
716
+ 'type': type,
717
+ 'spot': !swap,
628
718
  'margin': false,
629
- 'swap': false,
719
+ 'swap': swap,
630
720
  'future': false,
631
721
  'option': false,
632
- 'active': this.parseMarketActive(status),
633
- 'contract': false,
634
- 'linear': undefined,
635
- 'inverse': undefined,
636
- 'contractSize': undefined,
722
+ 'active': status,
723
+ 'contract': swap,
724
+ 'linear': linear,
725
+ 'inverse': inverse,
726
+ 'contractSize': contractSize,
637
727
  'expiry': undefined,
638
728
  'expiryDatetime': undefined,
639
729
  'strike': undefined,
640
730
  'optionType': undefined,
641
731
  'precision': {
642
- 'price': this.safeNumber(response, 'quote_increment'),
643
- 'amount': this.safeNumber(response, 'tick_size'),
732
+ 'price': increment,
733
+ 'amount': tickSize,
644
734
  },
645
735
  'limits': {
646
736
  'leverage': {
@@ -648,7 +738,7 @@ export default class gemini extends Exchange {
648
738
  'max': undefined,
649
739
  },
650
740
  'amount': {
651
- 'min': this.safeNumber(response, 'min_order_size'),
741
+ 'min': minSize,
652
742
  'max': undefined,
653
743
  },
654
744
  'price': {
package/js/src/hitbtc.js CHANGED
@@ -318,6 +318,7 @@ export default class hitbtc extends Exchange {
318
318
  '2012': BadRequest,
319
319
  '2020': BadRequest,
320
320
  '2022': BadRequest,
321
+ '2024': InvalidOrder,
321
322
  '10001': BadRequest,
322
323
  '10021': AccountSuspended,
323
324
  '10022': BadRequest,
@@ -335,6 +336,7 @@ export default class hitbtc extends Exchange {
335
336
  '20012': ExchangeError,
336
337
  '20014': ExchangeError,
337
338
  '20016': ExchangeError,
339
+ '20018': ExchangeError,
338
340
  '20031': ExchangeError,
339
341
  '20032': ExchangeError,
340
342
  '20033': ExchangeError,
@@ -345,10 +347,15 @@ export default class hitbtc extends Exchange {
345
347
  '20043': ExchangeError,
346
348
  '20044': PermissionDenied,
347
349
  '20045': InvalidOrder,
350
+ '20047': InvalidOrder,
351
+ '20048': InvalidOrder,
352
+ '20049': InvalidOrder,
348
353
  '20080': ExchangeError,
349
354
  '21001': ExchangeError,
350
355
  '21003': AccountSuspended,
351
356
  '21004': AccountSuspended,
357
+ '22004': ExchangeError,
358
+ '22008': ExchangeError, // Gateway timeout exceeded.
352
359
  },
353
360
  'broad': {},
354
361
  },
package/js/src/htx.js CHANGED
@@ -470,6 +470,7 @@ export default class htx extends Exchange {
470
470
  'v2/sub-user/api-key-modification': 1,
471
471
  'v2/sub-user/api-key-deletion': 1,
472
472
  'v1/subuser/transfer': 10,
473
+ 'v1/trust/user/active/credit': 10,
473
474
  // Trading
474
475
  'v1/order/orders/place': 0.2,
475
476
  'v1/order/batch-orders': 0.4,
package/js/src/kucoin.js CHANGED
@@ -413,6 +413,7 @@ export default class kucoin extends Exchange {
413
413
  '12h': '12hour',
414
414
  '1d': '1day',
415
415
  '1w': '1week',
416
+ '1M': '1month',
416
417
  },
417
418
  'precisionMode': TICK_SIZE,
418
419
  'exceptions': {
@@ -4462,7 +4463,7 @@ export default class kucoin extends Exchange {
4462
4463
  url = url + endpoint;
4463
4464
  const isFuturePrivate = (api === 'futuresPrivate');
4464
4465
  const isPrivate = (api === 'private');
4465
- const isBroker = (api === 'private');
4466
+ const isBroker = (api === 'broker');
4466
4467
  if (isPrivate || isFuturePrivate || isBroker) {
4467
4468
  this.checkRequiredCredentials();
4468
4469
  const timestamp = this.nonce().toString();
@@ -4494,7 +4495,9 @@ export default class kucoin extends Exchange {
4494
4495
  }
4495
4496
  if (isBroker) {
4496
4497
  const brokerName = this.safeString(partner, 'name');
4497
- headers['KC-BROKER-NAME'] = brokerName;
4498
+ if (brokerName !== undefined) {
4499
+ headers['KC-BROKER-NAME'] = brokerName;
4500
+ }
4498
4501
  }
4499
4502
  }
4500
4503
  return { 'url': url, 'method': method, 'body': body, 'headers': headers };
@@ -429,7 +429,7 @@ export default class lbank extends lbankRest {
429
429
  // "volume":6.3607,
430
430
  // "amount":77148.9303,
431
431
  // "price":12129,
432
- // "direction":"sell",
432
+ // "direction":"sell", // or "sell_market"
433
433
  // "TS":"2019-06-28T19:55:49.460"
434
434
  // },
435
435
  // "type":"trade",
@@ -469,7 +469,7 @@ export default class lbank extends lbankRest {
469
469
  // "volume":6.3607,
470
470
  // "amount":77148.9303,
471
471
  // "price":12129,
472
- // "direction":"sell",
472
+ // "direction":"sell", // or "sell_market"
473
473
  // "TS":"2019-06-28T19:55:49.460"
474
474
  // }
475
475
  //
@@ -478,6 +478,8 @@ export default class lbank extends lbankRest {
478
478
  if (timestamp === undefined) {
479
479
  timestamp = this.parse8601(datetime);
480
480
  }
481
+ let side = this.safeString2(trade, 'direction', 3);
482
+ side = side.replace('_market', '');
481
483
  return this.safeTrade({
482
484
  'timestamp': timestamp,
483
485
  'datetime': datetime,
@@ -486,7 +488,7 @@ export default class lbank extends lbankRest {
486
488
  'order': undefined,
487
489
  'type': undefined,
488
490
  'takerOrMaker': undefined,
489
- 'side': this.safeString2(trade, 'direction', 3),
491
+ 'side': side,
490
492
  'price': this.safeString2(trade, 'price', 1),
491
493
  'amount': this.safeString2(trade, 'volume', 2),
492
494
  'cost': this.safeString(trade, 'amount'),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ccxt",
3
- "version": "4.2.68",
3
+ "version": "4.2.69",
4
4
  "description": "A JavaScript / TypeScript / Python / C# / PHP cryptocurrency trading library with support for 100+ exchanges",
5
5
  "unpkg": "dist/ccxt.browser.js",
6
6
  "type": "module",
package/skip-tests.json CHANGED
@@ -887,6 +887,7 @@
887
887
  }
888
888
  },
889
889
  "gemini": {
890
+ "skipWs": "fixes needed",
890
891
  "skipMethods": {
891
892
  "loadMarkets": {
892
893
  "currencyIdAndCode": "messed codes",