ccxt 4.4.87__py2.py3-none-any.whl → 4.4.90__py2.py3-none-any.whl

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 (67) hide show
  1. ccxt/__init__.py +1 -1
  2. ccxt/abstract/bitget.py +58 -0
  3. ccxt/abstract/bitrue.py +65 -65
  4. ccxt/abstract/cryptocom.py +2 -0
  5. ccxt/abstract/luno.py +1 -0
  6. ccxt/async_support/__init__.py +1 -1
  7. ccxt/async_support/base/exchange.py +4 -1
  8. ccxt/async_support/binance.py +1 -1
  9. ccxt/async_support/bingx.py +55 -29
  10. ccxt/async_support/bitget.py +469 -147
  11. ccxt/async_support/bitrue.py +72 -66
  12. ccxt/async_support/bitvavo.py +34 -0
  13. ccxt/async_support/btcalpha.py +35 -0
  14. ccxt/async_support/btcbox.py +35 -0
  15. ccxt/async_support/btcmarkets.py +35 -0
  16. ccxt/async_support/btcturk.py +35 -0
  17. ccxt/async_support/bybit.py +28 -60
  18. ccxt/async_support/coinbase.py +1 -3
  19. ccxt/async_support/cryptocom.py +49 -0
  20. ccxt/async_support/delta.py +2 -2
  21. ccxt/async_support/digifinex.py +39 -99
  22. ccxt/async_support/gate.py +12 -5
  23. ccxt/async_support/hashkey.py +15 -28
  24. ccxt/async_support/hollaex.py +27 -22
  25. ccxt/async_support/kraken.py +28 -49
  26. ccxt/async_support/luno.py +87 -1
  27. ccxt/async_support/modetrade.py +7 -7
  28. ccxt/async_support/okx.py +2 -1
  29. ccxt/async_support/phemex.py +16 -8
  30. ccxt/async_support/tradeogre.py +3 -3
  31. ccxt/async_support/xt.py +1 -1
  32. ccxt/base/exchange.py +15 -5
  33. ccxt/binance.py +1 -1
  34. ccxt/bingx.py +55 -29
  35. ccxt/bitget.py +469 -147
  36. ccxt/bitrue.py +72 -66
  37. ccxt/bitvavo.py +34 -0
  38. ccxt/btcalpha.py +35 -0
  39. ccxt/btcbox.py +35 -0
  40. ccxt/btcmarkets.py +35 -0
  41. ccxt/btcturk.py +35 -0
  42. ccxt/bybit.py +28 -60
  43. ccxt/coinbase.py +1 -3
  44. ccxt/cryptocom.py +49 -0
  45. ccxt/delta.py +2 -2
  46. ccxt/digifinex.py +39 -99
  47. ccxt/gate.py +12 -5
  48. ccxt/hashkey.py +15 -28
  49. ccxt/hollaex.py +27 -22
  50. ccxt/kraken.py +27 -49
  51. ccxt/luno.py +87 -1
  52. ccxt/modetrade.py +7 -7
  53. ccxt/okx.py +2 -1
  54. ccxt/phemex.py +16 -8
  55. ccxt/pro/__init__.py +1 -119
  56. ccxt/pro/coinbase.py +2 -0
  57. ccxt/pro/cryptocom.py +27 -0
  58. ccxt/pro/kraken.py +3 -9
  59. ccxt/test/tests_async.py +1 -1
  60. ccxt/test/tests_sync.py +1 -1
  61. ccxt/tradeogre.py +3 -3
  62. ccxt/xt.py +1 -1
  63. {ccxt-4.4.87.dist-info → ccxt-4.4.90.dist-info}/METADATA +62 -20
  64. {ccxt-4.4.87.dist-info → ccxt-4.4.90.dist-info}/RECORD +67 -67
  65. {ccxt-4.4.87.dist-info → ccxt-4.4.90.dist-info}/LICENSE.txt +0 -0
  66. {ccxt-4.4.87.dist-info → ccxt-4.4.90.dist-info}/WHEEL +0 -0
  67. {ccxt-4.4.87.dist-info → ccxt-4.4.90.dist-info}/top_level.txt +0 -0
@@ -15,6 +15,7 @@ from ccxt.base.errors import InsufficientFunds
15
15
  from ccxt.base.errors import OrderNotFound
16
16
  from ccxt.base.errors import OrderImmediatelyFillable
17
17
  from ccxt.base.errors import NetworkError
18
+ from ccxt.base.errors import InvalidNonce
18
19
  from ccxt.base.decimal_to_precision import TICK_SIZE
19
20
  from ccxt.base.precise import Precise
20
21
 
@@ -262,6 +263,7 @@ class hollaex(Exchange, ImplicitAPI):
262
263
  },
263
264
  'exceptions': {
264
265
  'broad': {
266
+ 'API request is expired': InvalidNonce,
265
267
  'Invalid token': AuthenticationError,
266
268
  'Order not found': OrderNotFound,
267
269
  'Insufficient balance': InsufficientFunds,
@@ -796,7 +798,8 @@ class hollaex(Exchange, ImplicitAPI):
796
798
  # "price":0.147411,
797
799
  # "timestamp":"2022-01-26T17:53:34.650Z",
798
800
  # "order_id":"cba78ecb-4187-4da2-9d2f-c259aa693b5a",
799
- # "fee":0.01031877,"fee_coin":"usdt"
801
+ # "fee":0.01031877,
802
+ # "fee_coin":"usdt"
800
803
  # }
801
804
  #
802
805
  marketId = self.safe_string(trade, 'symbol')
@@ -809,11 +812,12 @@ class hollaex(Exchange, ImplicitAPI):
809
812
  priceString = self.safe_string(trade, 'price')
810
813
  amountString = self.safe_string(trade, 'size')
811
814
  feeCostString = self.safe_string(trade, 'fee')
815
+ feeCoin = self.safe_string(trade, 'fee_coin')
812
816
  fee = None
813
817
  if feeCostString is not None:
814
818
  fee = {
815
819
  'cost': feeCostString,
816
- 'currency': market['quote'],
820
+ 'currency': self.safe_currency_code(feeCoin),
817
821
  }
818
822
  return self.safe_trade({
819
823
  'info': trade,
@@ -899,7 +903,7 @@ class hollaex(Exchange, ImplicitAPI):
899
903
  :param str symbol: unified symbol of the market to fetch OHLCV data for
900
904
  :param str timeframe: the length of time each candle represents
901
905
  :param int [since]: timestamp in ms of the earliest candle to fetch
902
- :param int [limit]: the maximum amount of candles to fetch
906
+ :param int [limit]: the maximum amount of candles to fetch(max 500)
903
907
  :param dict [params]: extra parameters specific to the exchange API endpoint
904
908
  :param int [params.until]: timestamp in ms of the latest candle to fetch
905
909
  :returns int[][]: A list of candles ordered, open, high, low, close, volume
@@ -910,16 +914,24 @@ class hollaex(Exchange, ImplicitAPI):
910
914
  'symbol': market['id'],
911
915
  'resolution': self.safe_string(self.timeframes, timeframe, timeframe),
912
916
  }
917
+ paginate = False
918
+ maxLimit = 500
919
+ paginate, params = self.handle_option_and_params(params, 'fetchOHLCV', 'paginate', paginate)
920
+ if paginate:
921
+ return await self.fetch_paginated_call_deterministic('fetchOHLCV', symbol, since, limit, timeframe, params, maxLimit)
913
922
  until = self.safe_integer(params, 'until')
914
- end = self.seconds()
915
- if until is not None:
916
- end = self.parse_to_int(until / 1000)
917
- defaultSpan = 2592000 # 30 days
918
- if since is not None:
919
- request['from'] = self.parse_to_int(since / 1000)
920
- else:
921
- request['from'] = end - defaultSpan
922
- request['to'] = end
923
+ timeDelta = self.parse_timeframe(timeframe) * maxLimit * 1000
924
+ start = since
925
+ now = self.milliseconds()
926
+ if until is None and start is None:
927
+ until = now
928
+ start = until - timeDelta
929
+ elif until is None:
930
+ until = now # the exchange has not a lot of trades, so if we count until by limit and limit is small, it may return empty result
931
+ elif start is None:
932
+ start = until - timeDelta
933
+ request['from'] = self.parse_to_int(start / 1000) # convert to seconds
934
+ request['to'] = self.parse_to_int(until / 1000) # convert to seconds
923
935
  params = self.omit(params, 'until')
924
936
  response = await self.publicGetChart(self.extend(request, params))
925
937
  #
@@ -1277,11 +1289,10 @@ class hollaex(Exchange, ImplicitAPI):
1277
1289
  """
1278
1290
  await self.load_markets()
1279
1291
  market = self.market(symbol)
1280
- convertedAmount = float(self.amount_to_precision(symbol, amount))
1281
1292
  request: dict = {
1282
1293
  'symbol': market['id'],
1283
1294
  'side': side,
1284
- 'size': self.normalize_number_if_needed(convertedAmount),
1295
+ 'size': self.amount_to_precision(symbol, amount),
1285
1296
  'type': type,
1286
1297
  # 'stop': float(self.price_to_precision(symbol, stopPrice)),
1287
1298
  # 'meta': {}, # other options such
@@ -1292,10 +1303,9 @@ class hollaex(Exchange, ImplicitAPI):
1292
1303
  isMarketOrder = type == 'market'
1293
1304
  postOnly = self.is_post_only(isMarketOrder, exchangeSpecificParam, params)
1294
1305
  if not isMarketOrder:
1295
- convertedPrice = float(self.price_to_precision(symbol, price))
1296
- request['price'] = self.normalize_number_if_needed(convertedPrice)
1306
+ request['price'] = self.price_to_precision(symbol, price)
1297
1307
  if triggerPrice is not None:
1298
- request['stop'] = self.normalize_number_if_needed(float(self.price_to_precision(symbol, triggerPrice)))
1308
+ request['stop'] = self.price_to_precision(symbol, triggerPrice)
1299
1309
  if postOnly:
1300
1310
  request['meta'] = {'post_only': True}
1301
1311
  params = self.omit(params, ['postOnly', 'timeInForce', 'stopPrice', 'triggerPrice', 'stop'])
@@ -1943,11 +1953,6 @@ class hollaex(Exchange, ImplicitAPI):
1943
1953
  coins = self.safe_dict(response, 'coins', {})
1944
1954
  return self.parse_deposit_withdraw_fees(coins, codes, 'symbol')
1945
1955
 
1946
- def normalize_number_if_needed(self, number):
1947
- if self.is_round_number(number):
1948
- number = int(number)
1949
- return number
1950
-
1951
1956
  def sign(self, path, api='public', method='GET', params={}, headers=None, body=None):
1952
1957
  query = self.omit(params, self.extract_params(path))
1953
1958
  path = '/' + self.version + '/' + self.implode_params(path, params)
@@ -5,6 +5,7 @@
5
5
 
6
6
  from ccxt.async_support.base.exchange import Exchange
7
7
  from ccxt.abstract.kraken import ImplicitAPI
8
+ import asyncio
8
9
  import hashlib
9
10
  from ccxt.base.types import Any, Balances, Currencies, Currency, DepositAddress, IndexType, Int, LedgerEntry, Market, Num, Order, OrderBook, OrderSide, OrderType, Position, Str, Strings, Ticker, Tickers, Trade, TradingFeeInterface, Transaction, TransferEntry
10
11
  from typing import List
@@ -569,9 +570,12 @@ class kraken(Exchange, ImplicitAPI):
569
570
  :param dict [params]: extra parameters specific to the exchange API endpoint
570
571
  :returns dict[]: an array of objects representing market data
571
572
  """
573
+ promises = []
574
+ promises.append(self.publicGetAssetPairs(params))
572
575
  if self.options['adjustForTimeDifference']:
573
- await self.load_time_difference()
574
- response = await self.publicGetAssetPairs(params)
576
+ promises.append(self.load_time_difference())
577
+ responses = await asyncio.gather(*promises)
578
+ assetsResponse = responses[0]
575
579
  #
576
580
  # {
577
581
  # "error": [],
@@ -619,7 +623,8 @@ class kraken(Exchange, ImplicitAPI):
619
623
  # }
620
624
  # }
621
625
  #
622
- markets = self.safe_value(response, 'result', {})
626
+ markets = self.safe_dict(assetsResponse, 'result', {})
627
+ cachedCurrencies = self.safe_dict(self.options, 'cachedCurrencies', {})
623
628
  keys = list(markets.keys())
624
629
  result = []
625
630
  for i in range(0, len(keys)):
@@ -629,39 +634,45 @@ class kraken(Exchange, ImplicitAPI):
629
634
  quoteId = self.safe_string(market, 'quote')
630
635
  base = self.safe_currency_code(baseId)
631
636
  quote = self.safe_currency_code(quoteId)
632
- darkpool = id.find('.d') >= 0
633
- altname = self.safe_string(market, 'altname')
634
- makerFees = self.safe_value(market, 'fees_maker', [])
635
- firstMakerFee = self.safe_value(makerFees, 0, [])
637
+ makerFees = self.safe_list(market, 'fees_maker', [])
638
+ firstMakerFee = self.safe_list(makerFees, 0, [])
636
639
  firstMakerFeeRate = self.safe_string(firstMakerFee, 1)
637
640
  maker = None
638
641
  if firstMakerFeeRate is not None:
639
642
  maker = self.parse_number(Precise.string_div(firstMakerFeeRate, '100'))
640
- takerFees = self.safe_value(market, 'fees', [])
641
- firstTakerFee = self.safe_value(takerFees, 0, [])
643
+ takerFees = self.safe_list(market, 'fees', [])
644
+ firstTakerFee = self.safe_list(takerFees, 0, [])
642
645
  firstTakerFeeRate = self.safe_string(firstTakerFee, 1)
643
646
  taker = None
644
647
  if firstTakerFeeRate is not None:
645
648
  taker = self.parse_number(Precise.string_div(firstTakerFeeRate, '100'))
646
- leverageBuy = self.safe_value(market, 'leverage_buy', [])
649
+ leverageBuy = self.safe_list(market, 'leverage_buy', [])
647
650
  leverageBuyLength = len(leverageBuy)
648
651
  precisionPrice = self.parse_number(self.parse_precision(self.safe_string(market, 'pair_decimals')))
652
+ precisionAmount = self.parse_number(self.parse_precision(self.safe_string(market, 'lot_decimals')))
653
+ spot = True
654
+ # fix https://github.com/freqtrade/freqtrade/issues/11765#issuecomment-2894224103
655
+ if spot and (base in cachedCurrencies):
656
+ currency = cachedCurrencies[base]
657
+ currencyPrecision = self.safe_number(currency, 'precision')
658
+ # if currency precision is greater(e.g. 0.01) than market precision(e.g. 0.001)
659
+ if currencyPrecision > precisionAmount:
660
+ precisionAmount = currencyPrecision
649
661
  status = self.safe_string(market, 'status')
650
662
  isActive = status == 'online'
651
663
  result.append({
652
664
  'id': id,
653
665
  'wsId': self.safe_string(market, 'wsname'),
654
- 'symbol': altname if darkpool else (base + '/' + quote),
666
+ 'symbol': base + '/' + quote,
655
667
  'base': base,
656
668
  'quote': quote,
657
669
  'settle': None,
658
670
  'baseId': baseId,
659
671
  'quoteId': quoteId,
660
672
  'settleId': None,
661
- 'darkpool': darkpool,
662
673
  'altname': market['altname'],
663
674
  'type': 'spot',
664
- 'spot': True,
675
+ 'spot': spot,
665
676
  'margin': (leverageBuyLength > 0),
666
677
  'swap': False,
667
678
  'future': False,
@@ -678,7 +689,7 @@ class kraken(Exchange, ImplicitAPI):
678
689
  'strike': None,
679
690
  'optionType': None,
680
691
  'precision': {
681
- 'amount': self.parse_number(self.parse_precision(self.safe_string(market, 'lot_decimals'))),
692
+ 'amount': precisionAmount,
682
693
  'price': precisionPrice,
683
694
  },
684
695
  'limits': {
@@ -691,7 +702,7 @@ class kraken(Exchange, ImplicitAPI):
691
702
  'max': None,
692
703
  },
693
704
  'price': {
694
- 'min': precisionPrice,
705
+ 'min': None,
695
706
  'max': None,
696
707
  },
697
708
  'cost': {
@@ -702,7 +713,6 @@ class kraken(Exchange, ImplicitAPI):
702
713
  'created': None,
703
714
  'info': market,
704
715
  })
705
- result = self.append_inactive_markets(result)
706
716
  self.options['marketsByAltname'] = self.index_by(result, 'altname')
707
717
  return result
708
718
 
@@ -714,32 +724,6 @@ class kraken(Exchange, ImplicitAPI):
714
724
  currencyId = currencyId[1:]
715
725
  return super(kraken, self).safe_currency(currencyId, currency)
716
726
 
717
- def append_inactive_markets(self, result):
718
- # result should be an array to append to
719
- precision: dict = {
720
- 'amount': self.parse_number('1e-8'),
721
- 'price': self.parse_number('1e-8'),
722
- }
723
- costLimits: dict = {'min': None, 'max': None}
724
- priceLimits: dict = {'min': precision['price'], 'max': None}
725
- amountLimits: dict = {'min': precision['amount'], 'max': None}
726
- limits: dict = {'amount': amountLimits, 'price': priceLimits, 'cost': costLimits}
727
- defaults: dict = {
728
- 'darkpool': False,
729
- 'info': None,
730
- 'maker': None,
731
- 'taker': None,
732
- 'active': False,
733
- 'precision': precision,
734
- 'limits': limits,
735
- }
736
- markets = [
737
- # {'id': 'XXLMZEUR', 'symbol': 'XLM/EUR', 'base': 'XLM', 'quote': 'EUR', 'altname': 'XLMEUR'},
738
- ]
739
- for i in range(0, len(markets)):
740
- result.append(self.extend(defaults, markets[i]))
741
- return result
742
-
743
727
  async def fetch_status(self, params={}):
744
728
  """
745
729
  the latest known information on the availability of the exchange API
@@ -980,8 +964,6 @@ class kraken(Exchange, ImplicitAPI):
980
964
  """
981
965
  await self.load_markets()
982
966
  market = self.market(symbol)
983
- if market['darkpool']:
984
- raise ExchangeError(self.id + ' fetchOrderBook() does not provide an order book for darkpool symbol ' + symbol)
985
967
  request: dict = {
986
968
  'pair': market['id'],
987
969
  }
@@ -1084,7 +1066,7 @@ class kraken(Exchange, ImplicitAPI):
1084
1066
  for i in range(0, len(symbols)):
1085
1067
  symbol = symbols[i]
1086
1068
  market = self.markets[symbol]
1087
- if market['active'] and not market['darkpool']:
1069
+ if market['active']:
1088
1070
  marketIds.append(market['id'])
1089
1071
  request['pair'] = ','.join(marketIds)
1090
1072
  response = await self.publicGetTicker(self.extend(request, params))
@@ -1110,9 +1092,6 @@ class kraken(Exchange, ImplicitAPI):
1110
1092
  :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
1111
1093
  """
1112
1094
  await self.load_markets()
1113
- darkpool = symbol.find('.d') >= 0
1114
- if darkpool:
1115
- raise ExchangeError(self.id + ' fetchTicker() does not provide a ticker for darkpool symbol ' + symbol)
1116
1095
  market = self.market(symbol)
1117
1096
  request: dict = {
1118
1097
  'pair': market['id'],
@@ -3329,6 +3308,6 @@ class kraken(Exchange, ImplicitAPI):
3329
3308
  for i in range(0, len(response['error'])):
3330
3309
  error = response['error'][i]
3331
3310
  self.throw_exactly_matched_exception(self.exceptions['exact'], error, message)
3332
- self.throw_exactly_matched_exception(self.exceptions['broad'], error, message)
3311
+ self.throw_broadly_matched_exception(self.exceptions['broad'], error, message)
3333
3312
  raise ExchangeError(message)
3334
3313
  return None
@@ -5,7 +5,7 @@
5
5
 
6
6
  from ccxt.async_support.base.exchange import Exchange
7
7
  from ccxt.abstract.luno import ImplicitAPI
8
- from ccxt.base.types import Account, Any, Balances, Currency, DepositAddress, Int, LedgerEntry, Market, Num, Order, OrderBook, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, TradingFeeInterface
8
+ from ccxt.base.types import Account, Any, Balances, Currencies, Currency, DepositAddress, Int, LedgerEntry, Market, Num, Order, OrderBook, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, TradingFeeInterface
9
9
  from typing import List
10
10
  from ccxt.base.errors import ExchangeError
11
11
  from ccxt.base.errors import ArgumentsRequired
@@ -44,6 +44,7 @@ class luno(Exchange, ImplicitAPI):
44
44
  'fetchClosedOrders': True,
45
45
  'fetchCrossBorrowRate': False,
46
46
  'fetchCrossBorrowRates': False,
47
+ 'fetchCurrencies': True,
47
48
  'fetchDepositAddress': True,
48
49
  'fetchFundingHistory': False,
49
50
  'fetchFundingRate': False,
@@ -125,6 +126,7 @@ class luno(Exchange, ImplicitAPI):
125
126
  'accounts/{id}/transactions': 1,
126
127
  'balance': 1,
127
128
  'beneficiaries': 1,
129
+ 'send/networks': 1,
128
130
  'fee_info': 1,
129
131
  'funding_address': 1,
130
132
  'listorders': 1,
@@ -265,6 +267,90 @@ class luno(Exchange, ImplicitAPI):
265
267
  },
266
268
  })
267
269
 
270
+ async def fetch_currencies(self, params={}) -> Currencies:
271
+ """
272
+ fetches all available currencies on an exchange
273
+ :param dict [params]: extra parameters specific to the exchange API endpoint
274
+ :returns dict: an associative dictionary of currencies
275
+ """
276
+ if not self.check_required_credentials(False):
277
+ return None
278
+ response = await self.privateGetSendNetworks(params)
279
+ #
280
+ # {
281
+ # "networks": [
282
+ # {
283
+ # "id": 0,
284
+ # "name": "Ethereum",
285
+ # "native_currency": "ETH"
286
+ # },
287
+ # ...
288
+ # ]
289
+ # }
290
+ #
291
+ currenciesData = self.safe_list(response, 'data', [])
292
+ result: dict = {}
293
+ for i in range(0, len(currenciesData)):
294
+ networkEntry = currenciesData[i]
295
+ id = self.safe_string(networkEntry, 'native_currency')
296
+ code = self.safe_currency_code(id)
297
+ if not (code in result):
298
+ result[code] = {
299
+ 'id': id,
300
+ 'code': code,
301
+ 'precision': None,
302
+ 'type': None,
303
+ 'name': None,
304
+ 'active': None,
305
+ 'deposit': None,
306
+ 'withdraw': None,
307
+ 'fee': None,
308
+ 'limits': {
309
+ 'withdraw': {
310
+ 'min': None,
311
+ 'max': None,
312
+ },
313
+ 'deposit': {
314
+ 'min': None,
315
+ 'max': None,
316
+ },
317
+ },
318
+ 'networks': {},
319
+ 'info': {},
320
+ }
321
+ networkId = self.safe_string(networkEntry, 'name')
322
+ networkCode = self.network_id_to_code(networkId)
323
+ result[code]['networks'][networkCode] = {
324
+ 'id': networkId,
325
+ 'network': networkCode,
326
+ 'limits': {
327
+ 'withdraw': {
328
+ 'min': None,
329
+ 'max': None,
330
+ },
331
+ 'deposit': {
332
+ 'min': None,
333
+ 'max': None,
334
+ },
335
+ },
336
+ 'active': None,
337
+ 'deposit': None,
338
+ 'withdraw': None,
339
+ 'fee': None,
340
+ 'precision': None,
341
+ 'info': networkEntry,
342
+ }
343
+ # add entry in info
344
+ info = self.safe_list(result[code], 'info', [])
345
+ info.append(networkEntry)
346
+ result[code]['info'] = info
347
+ # only after all entries are formed in currencies, restructure each entry
348
+ allKeys = list(result.keys())
349
+ for i in range(0, len(allKeys)):
350
+ code = allKeys[i]
351
+ result[code] = self.safe_currency_structure(result[code]) # self is needed after adding network entry
352
+ return result
353
+
268
354
  async def fetch_markets(self, params={}) -> List[Market]:
269
355
  """
270
356
  retrieves data on all markets for luno
@@ -50,16 +50,16 @@ class modetrade(Exchange, ImplicitAPI):
50
50
  'createConvertTrade': False,
51
51
  'createDepositAddress': False,
52
52
  'createMarketBuyOrderWithCost': False,
53
- 'createMarketOrder': False,
53
+ 'createMarketOrder': True,
54
54
  'createMarketOrderWithCost': False,
55
55
  'createMarketSellOrderWithCost': False,
56
56
  'createOrder': True,
57
57
  'createOrderWithTakeProfitAndStopLoss': True,
58
58
  'createReduceOnlyOrder': True,
59
- 'createStopLimitOrder': False,
59
+ 'createStopLimitOrder': True,
60
60
  'createStopLossOrder': True,
61
- 'createStopMarketOrder': False,
62
- 'createStopOrder': False,
61
+ 'createStopMarketOrder': True,
62
+ 'createStopOrder': True,
63
63
  'createTakeProfitOrder': True,
64
64
  'createTrailingAmountOrder': False,
65
65
  'createTrailingPercentOrder': False,
@@ -298,7 +298,7 @@ class modetrade(Exchange, ImplicitAPI):
298
298
  },
299
299
  'options': {
300
300
  'sandboxMode': False,
301
- 'brokerId': 'CCXT',
301
+ 'brokerId': 'CCXTMODE',
302
302
  'verifyingContractAddress': '0x6F7a338F2aA472838dEFD3283eB360d4Dff5D203',
303
303
  },
304
304
  'features': {
@@ -2069,7 +2069,7 @@ class modetrade(Exchange, ImplicitAPI):
2069
2069
  code = self.safe_currency_code(self.safe_string(balance, 'token'))
2070
2070
  account = self.account()
2071
2071
  account['total'] = self.safe_string(balance, 'holding')
2072
- account['frozen'] = self.safe_string(balance, 'frozen')
2072
+ account['used'] = self.safe_string(balance, 'frozen')
2073
2073
  result[code] = account
2074
2074
  return self.safe_balance(result)
2075
2075
 
@@ -2671,7 +2671,7 @@ class modetrade(Exchange, ImplicitAPI):
2671
2671
  if isPostOrPut and isOrder:
2672
2672
  isSandboxMode = self.safe_bool(self.options, 'sandboxMode', False)
2673
2673
  if not isSandboxMode:
2674
- brokerId = self.safe_string(self.options, 'brokerId', 'CCXT')
2674
+ brokerId = self.safe_string(self.options, 'brokerId', 'CCXTMODE')
2675
2675
  if path == 'batch-order':
2676
2676
  ordersList = self.safe_list(params, 'orders', [])
2677
2677
  for i in range(0, len(ordersList)):
ccxt/async_support/okx.py CHANGED
@@ -1607,6 +1607,7 @@ class okx(Exchange, ImplicitAPI):
1607
1607
  # "instType": "OPTION",
1608
1608
  # "lever": "",
1609
1609
  # "listTime": "1631262612280",
1610
+ # "contTdSwTime": "1631262812280",
1610
1611
  # "lotSz": "1",
1611
1612
  # "minSz": "1",
1612
1613
  # "optType": "P",
@@ -1686,7 +1687,7 @@ class okx(Exchange, ImplicitAPI):
1686
1687
  'expiryDatetime': self.iso8601(expiry),
1687
1688
  'strike': self.parse_number(strikePrice),
1688
1689
  'optionType': optionType,
1689
- 'created': self.safe_integer(market, 'listTime'),
1690
+ 'created': self.safe_integer_2(market, 'contTdSwTime', 'listTime'), # contTdSwTime is public trading start time, while listTime considers pre-trading too
1690
1691
  'precision': {
1691
1692
  'amount': self.safe_number(market, 'lotSz'),
1692
1693
  'price': self.safe_number(market, 'tickSz'),
@@ -598,6 +598,7 @@ class phemex(Exchange, ImplicitAPI):
598
598
  },
599
599
  'defaultNetworks': {
600
600
  'USDT': 'ETH',
601
+ 'MKR': 'ETH',
601
602
  },
602
603
  'defaultSubType': 'linear',
603
604
  'accountsByType': {
@@ -3322,6 +3323,7 @@ class phemex(Exchange, ImplicitAPI):
3322
3323
  fetch the deposit address for a currency associated with self account
3323
3324
  :param str code: unified currency code
3324
3325
  :param dict [params]: extra parameters specific to the exchange API endpoint
3326
+ :param str [params.network]: the chain name to fetch the deposit address e.g. ETH, TRX, EOS, SOL, etc.
3325
3327
  :returns dict: an `address structure <https://docs.ccxt.com/#/?id=address-structure>`
3326
3328
  """
3327
3329
  await self.load_markets()
@@ -3332,20 +3334,26 @@ class phemex(Exchange, ImplicitAPI):
3332
3334
  defaultNetworks = self.safe_dict(self.options, 'defaultNetworks')
3333
3335
  defaultNetwork = self.safe_string_upper(defaultNetworks, code)
3334
3336
  networks = self.safe_dict(self.options, 'networks', {})
3335
- network = self.safe_string_upper(params, 'network', defaultNetwork)
3337
+ network = self.safe_string_upper_2(params, 'network', 'chainName', defaultNetwork)
3336
3338
  network = self.safe_string(networks, network, network)
3337
3339
  if network is None:
3338
- request['chainName'] = currency['id']
3340
+ raise ArgumentsRequired(self.id + ' fetchDepositAddress() requires a network parameter')
3339
3341
  else:
3340
3342
  request['chainName'] = network
3341
3343
  params = self.omit(params, 'network')
3342
- response = await self.privateGetPhemexUserWalletsV2DepositAddress(self.extend(request, params))
3344
+ response = await self.privateGetExchangeWalletsV2DepositAddress(self.extend(request, params))
3345
+ #
3343
3346
  # {
3344
- # "code":0,
3345
- # "msg":"OK",
3346
- # "data":{
3347
- # "address":"0x5bfbf60e0fa7f63598e6cfd8a7fd3ffac4ccc6ad",
3348
- # "tag":null
3347
+ # "code": 0,
3348
+ # "msg": "OK",
3349
+ # "data": {
3350
+ # "address": "tb1qxel5wq5gumt",
3351
+ # "tag": "",
3352
+ # "notice": False,
3353
+ # "accountType": 1,
3354
+ # "contractName": null,
3355
+ # "chainTokenUrl": null,
3356
+ # "sign": null
3349
3357
  # }
3350
3358
  # }
3351
3359
  #
@@ -425,13 +425,13 @@ class tradeogre(Exchange, ImplicitAPI):
425
425
  'vwap': None,
426
426
  'open': self.safe_string(ticker, 'initialprice'),
427
427
  'close': self.safe_string(ticker, 'price'),
428
- 'last': None,
428
+ 'last': self.safe_string(ticker, 'price'),
429
429
  'previousClose': None,
430
430
  'change': None,
431
431
  'percentage': None,
432
432
  'average': None,
433
- 'baseVolume': None,
434
- 'quoteVolume': self.safe_string(ticker, 'volume'),
433
+ 'baseVolume': self.safe_string(ticker, 'volume'),
434
+ 'quoteVolume': None,
435
435
  'info': ticker,
436
436
  }, market)
437
437
 
ccxt/async_support/xt.py CHANGED
@@ -2847,7 +2847,7 @@ class xt(Exchange, ImplicitAPI):
2847
2847
  if trigger or stopLossTakeProfit:
2848
2848
  request['state'] = 'NOT_TRIGGERED'
2849
2849
  elif type == 'swap':
2850
- request['state'] = 'NEW'
2850
+ request['state'] = 'UNFINISHED' # NEW & PARTIALLY_FILLED
2851
2851
  elif status == 'closed':
2852
2852
  if trigger or stopLossTakeProfit:
2853
2853
  request['state'] = 'TRIGGERED'
ccxt/base/exchange.py CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  # -----------------------------------------------------------------------------
6
6
 
7
- __version__ = '4.4.87'
7
+ __version__ = '4.4.90'
8
8
 
9
9
  # -----------------------------------------------------------------------------
10
10
 
@@ -906,6 +906,10 @@ class Exchange(object):
906
906
  def keysort(dictionary):
907
907
  return collections.OrderedDict(sorted(dictionary.items(), key=lambda t: t[0]))
908
908
 
909
+ @staticmethod
910
+ def sort(array):
911
+ return sorted(array)
912
+
909
913
  @staticmethod
910
914
  def extend(*args):
911
915
  if args is not None:
@@ -956,6 +960,11 @@ class Exchange(object):
956
960
  def groupBy(array, key):
957
961
  return Exchange.group_by(array, key)
958
962
 
963
+
964
+ @staticmethod
965
+ def index_by_safe(array, key):
966
+ return Exchange.index_by(array, key) # wrapper for go
967
+
959
968
  @staticmethod
960
969
  def index_by(array, key):
961
970
  result = {}
@@ -1037,7 +1046,7 @@ class Exchange(object):
1037
1046
  return _urlencode.urlencode(result, quote_via=_urlencode.quote)
1038
1047
 
1039
1048
  @staticmethod
1040
- def rawencode(params={}):
1049
+ def rawencode(params={}, sort=False):
1041
1050
  return _urlencode.unquote(Exchange.urlencode(params))
1042
1051
 
1043
1052
  @staticmethod
@@ -1536,7 +1545,8 @@ class Exchange(object):
1536
1545
  currencies = self.fetch_currencies()
1537
1546
  self.options['cachedCurrencies'] = currencies
1538
1547
  markets = self.fetch_markets(params)
1539
- del self.options['cachedCurrencies']
1548
+ if 'cachedCurrencies' in self.options:
1549
+ del self.options['cachedCurrencies']
1540
1550
  return self.set_markets(markets, currencies)
1541
1551
 
1542
1552
  def fetch_markets(self, params={}):
@@ -3186,7 +3196,7 @@ class Exchange(object):
3186
3196
 
3187
3197
  def set_markets(self, markets, currencies=None):
3188
3198
  values = []
3189
- self.markets_by_id = {}
3199
+ self.markets_by_id = self.create_safe_dictionary()
3190
3200
  # handle marketId conflicts
3191
3201
  # we insert spot markets first
3192
3202
  marketValues = self.sort_by(self.to_array(markets), 'spot', True, True)
@@ -3261,7 +3271,7 @@ class Exchange(object):
3261
3271
  resultingCurrencies.append(highestPrecisionCurrency)
3262
3272
  sortedCurrencies = self.sort_by(resultingCurrencies, 'code')
3263
3273
  self.currencies = self.deep_extend(self.currencies, self.index_by(sortedCurrencies, 'code'))
3264
- self.currencies_by_id = self.index_by(self.currencies, 'id')
3274
+ self.currencies_by_id = self.index_by_safe(self.currencies, 'id')
3265
3275
  currenciesSortedByCode = self.keysort(self.currencies)
3266
3276
  self.codes = list(currenciesSortedByCode.keys())
3267
3277
  return self.markets
ccxt/binance.py CHANGED
@@ -9833,7 +9833,7 @@ class binance(Exchange, ImplicitAPI):
9833
9833
  response = self.dapiPrivateV2GetLeverageBracket(query)
9834
9834
  else:
9835
9835
  raise NotSupported(self.id + ' loadLeverageBrackets() supports linear and inverse contracts only')
9836
- self.options['leverageBrackets'] = {}
9836
+ self.options['leverageBrackets'] = self.create_safe_dictionary()
9837
9837
  for i in range(0, len(response)):
9838
9838
  entry = response[i]
9839
9839
  marketId = self.safe_string(entry, 'symbol')