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
@@ -2302,15 +2302,9 @@ class bybit(Exchange, ImplicitAPI):
2302
2302
  # 'baseCoin': '', Base coin. For option only
2303
2303
  # 'expDate': '', Expiry date. e.g., 25DEC22. For option only
2304
2304
  }
2305
- if market['spot']:
2306
- request['category'] = 'spot'
2307
- else:
2308
- if market['option']:
2309
- request['category'] = 'option'
2310
- elif market['linear']:
2311
- request['category'] = 'linear'
2312
- elif market['inverse']:
2313
- request['category'] = 'inverse'
2305
+ category = None
2306
+ category, params = self.get_bybit_type('fetchTicker', market, params)
2307
+ request['category'] = category
2314
2308
  response = await self.publicGetV5MarketTickers(self.extend(request, params))
2315
2309
  #
2316
2310
  # {
@@ -2402,24 +2396,14 @@ class bybit(Exchange, ImplicitAPI):
2402
2396
  # 'baseCoin': '', # Base coin. For option only
2403
2397
  # 'expDate': '', # Expiry date. e.g., 25DEC22. For option only
2404
2398
  }
2405
- type = None
2406
- type, params = self.handle_market_type_and_params('fetchTickers', market, params)
2407
- # Calls like `.fetchTickers(None, {subType:'inverse'})` should be supported for self exchange, so
2408
- # as "options.defaultSubType" is also set in exchange options, we should consider `params.subType`
2409
- # with higher priority and only default to spot, if `subType` is not set in params
2410
- passedSubType = self.safe_string(params, 'subType')
2411
- subType = None
2412
- subType, params = self.handle_sub_type_and_params('fetchTickers', market, params, 'linear')
2413
- # only if passedSubType is None, then use spot
2414
- if type == 'spot' and passedSubType is None:
2415
- request['category'] = 'spot'
2416
- elif type == 'option':
2399
+ category = None
2400
+ category, params = self.get_bybit_type('fetchTickers', market, params)
2401
+ request['category'] = category
2402
+ if category == 'option':
2417
2403
  request['category'] = 'option'
2418
2404
  if code is None:
2419
2405
  code = 'BTC'
2420
2406
  request['baseCoin'] = code
2421
- elif type == 'swap' or type == 'future' or subType is not None:
2422
- request['category'] = subType
2423
2407
  response = await self.publicGetV5MarketTickers(self.extend(request, params))
2424
2408
  #
2425
2409
  # {
@@ -3692,7 +3676,10 @@ class bybit(Exchange, ImplicitAPI):
3692
3676
  market = self.market(symbol)
3693
3677
  if not market['spot']:
3694
3678
  raise NotSupported(self.id + ' createMarketBuyOrderWithCost() supports spot orders only')
3695
- return await self.create_order(symbol, 'market', 'buy', cost, 1, params)
3679
+ req = {
3680
+ 'cost': cost,
3681
+ }
3682
+ return await self.create_order(symbol, 'market', 'buy', -1, None, self.extend(req, params))
3696
3683
 
3697
3684
  async def create_market_sell_order_with_cost(self, symbol: str, cost: float, params={}) -> Order:
3698
3685
  """
@@ -3713,7 +3700,10 @@ class bybit(Exchange, ImplicitAPI):
3713
3700
  market = self.market(symbol)
3714
3701
  if not market['spot']:
3715
3702
  raise NotSupported(self.id + ' createMarketSellOrderWithCost() supports spot orders only')
3716
- return await self.create_order(symbol, 'market', 'sell', cost, 1, params)
3703
+ req = {
3704
+ 'cost': cost,
3705
+ }
3706
+ return await self.create_order(symbol, 'market', 'sell', -1, None, self.extend(req, params))
3717
3707
 
3718
3708
  async def create_order(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}) -> Order:
3719
3709
  """
@@ -3891,14 +3881,9 @@ class bybit(Exchange, ImplicitAPI):
3891
3881
  request['orderLinkId'] = self.uuid16()
3892
3882
  if isLimit:
3893
3883
  request['price'] = priceString
3894
- if market['spot']:
3895
- request['category'] = 'spot'
3896
- elif market['option']:
3897
- request['category'] = 'option'
3898
- elif market['linear']:
3899
- request['category'] = 'linear'
3900
- elif market['inverse']:
3901
- request['category'] = 'inverse'
3884
+ category = None
3885
+ category, params = self.get_bybit_type('createOrderRequest', market, params)
3886
+ request['category'] = category
3902
3887
  cost = self.safe_string(params, 'cost')
3903
3888
  params = self.omit(params, 'cost')
3904
3889
  # if the cost is inferable, let's keep the old logic and ignore marketUnit, to minimize the impact of the changes
@@ -3926,7 +3911,7 @@ class bybit(Exchange, ImplicitAPI):
3926
3911
  if (price is None) and (cost is None):
3927
3912
  raise InvalidOrder(self.id + ' createOrder() requires the price argument for market buy orders to calculate the total cost to spend(amount * price), alternatively set the createMarketBuyOrderRequiresPrice option or param to False and pass the cost to spend in the amount argument')
3928
3913
  else:
3929
- quoteAmount = Precise.string_mul(amountString, priceString)
3914
+ quoteAmount = Precise.string_mul(self.number_to_string(amount), priceString)
3930
3915
  costRequest = cost if (cost is not None) else quoteAmount
3931
3916
  request['qty'] = self.get_cost(symbol, costRequest)
3932
3917
  else:
@@ -4091,14 +4076,9 @@ class bybit(Exchange, ImplicitAPI):
4091
4076
  # Valid for option only.
4092
4077
  # 'orderIv': '0', # Implied volatility; parameters are passed according to the real value; for example, for 10%, 0.1 is passed
4093
4078
  }
4094
- if market['spot']:
4095
- request['category'] = 'spot'
4096
- elif market['linear']:
4097
- request['category'] = 'linear'
4098
- elif market['inverse']:
4099
- request['category'] = 'inverse'
4100
- elif market['option']:
4101
- request['category'] = 'option'
4079
+ category = None
4080
+ category, params = self.get_bybit_type('editOrderRequest', market, params)
4081
+ request['category'] = category
4102
4082
  if amount is not None:
4103
4083
  request['qty'] = self.get_amount(symbol, amount)
4104
4084
  if price is not None:
@@ -4289,14 +4269,9 @@ class bybit(Exchange, ImplicitAPI):
4289
4269
  request['orderFilter'] = 'StopOrder' if isTrigger else 'Order'
4290
4270
  if id is not None: # The user can also use argument params["orderLinkId"]
4291
4271
  request['orderId'] = id
4292
- if market['spot']:
4293
- request['category'] = 'spot'
4294
- elif market['linear']:
4295
- request['category'] = 'linear'
4296
- elif market['inverse']:
4297
- request['category'] = 'inverse'
4298
- elif market['option']:
4299
- request['category'] = 'option'
4272
+ category = None
4273
+ category, params = self.get_bybit_type('cancelOrderRequest', market, params)
4274
+ request['category'] = category
4300
4275
  return self.extend(request, params)
4301
4276
 
4302
4277
  async def cancel_order(self, id: str, symbol: Str = None, params={}) -> Order:
@@ -7189,14 +7164,7 @@ classic accounts only/ spot not supported* fetches information on an order made
7189
7164
  'symbol': market['id'],
7190
7165
  }
7191
7166
  category = None
7192
- if market['linear']:
7193
- category = 'linear'
7194
- elif market['inverse']:
7195
- category = 'inverse'
7196
- elif market['spot']:
7197
- category = 'spot'
7198
- else:
7199
- category = 'option'
7167
+ category, params = self.get_bybit_type('fetchTradingFee', market, params)
7200
7168
  request['category'] = category
7201
7169
  response = await self.privateGetV5AccountFeeRate(self.extend(request, params))
7202
7170
  #
@@ -7435,9 +7403,9 @@ classic accounts only/ spot not supported* fetches information on an order made
7435
7403
  request['symbol'] = market['id']
7436
7404
  type = None
7437
7405
  type, params = self.get_bybit_type('fetchMySettlementHistory', market, params)
7438
- if type == 'spot' or type == 'inverse':
7406
+ if type == 'spot':
7439
7407
  raise NotSupported(self.id + ' fetchMySettlementHistory() is not supported for spot market')
7440
- request['category'] = 'linear'
7408
+ request['category'] = type
7441
7409
  if limit is not None:
7442
7410
  request['limit'] = limit
7443
7411
  response = await self.privateGetV5AssetDeliveryRecord(self.extend(request, params))
@@ -4409,7 +4409,7 @@ class coinbase(Exchange, ImplicitAPI):
4409
4409
  """
4410
4410
  *futures only* closes open positions for a market
4411
4411
 
4412
- https://coinbase-api.github.io/docs/#/en-us/swapV2/trade-api.html#One-Click%20Close%20All%20Positions
4412
+ https://docs.cdp.coinbase.com/coinbase-app/trade/reference/retailbrokerageapi_closeposition
4413
4413
 
4414
4414
  :param str symbol: Unified CCXT market symbol
4415
4415
  :param str [side]: not used by coinbase
@@ -4420,8 +4420,6 @@ class coinbase(Exchange, ImplicitAPI):
4420
4420
  """
4421
4421
  await self.load_markets()
4422
4422
  market = self.market(symbol)
4423
- if not market['future']:
4424
- raise NotSupported(self.id + ' closePosition() only supported for futures markets')
4425
4423
  clientOrderId = self.safe_string_2(params, 'client_order_id', 'clientOrderId')
4426
4424
  params = self.omit(params, 'clientOrderId')
4427
4425
  request: dict = {
@@ -60,6 +60,7 @@ class cryptocom(Exchange, ImplicitAPI):
60
60
  'createOrders': True,
61
61
  'createStopOrder': True,
62
62
  'createTriggerOrder': True,
63
+ 'editOrder': True,
63
64
  'fetchAccounts': True,
64
65
  'fetchBalance': True,
65
66
  'fetchBidsAsks': False,
@@ -152,6 +153,7 @@ class cryptocom(Exchange, ImplicitAPI):
152
153
  'derivatives': 'https://uat-api.3ona.co/v2',
153
154
  },
154
155
  'api': {
156
+ 'base': 'https://api.crypto.com',
155
157
  'v1': 'https://api.crypto.com/exchange/v1',
156
158
  'v2': 'https://api.crypto.com/v2',
157
159
  'derivatives': 'https://deriv-api.crypto.com/v1',
@@ -169,6 +171,13 @@ class cryptocom(Exchange, ImplicitAPI):
169
171
  'fees': 'https://crypto.com/exchange/document/fees-limits',
170
172
  },
171
173
  'api': {
174
+ 'base': {
175
+ 'public': {
176
+ 'get': {
177
+ 'v1/public/get-announcements': 1, # no description of rate limit
178
+ },
179
+ },
180
+ },
172
181
  'v1': {
173
182
  'public': {
174
183
  'get': {
@@ -195,6 +204,7 @@ class cryptocom(Exchange, ImplicitAPI):
195
204
  'private/user-balance-history': 10 / 3,
196
205
  'private/get-positions': 10 / 3,
197
206
  'private/create-order': 2 / 3,
207
+ 'private/amend-order': 4 / 3, # no description of rate limit
198
208
  'private/create-order-list': 10 / 3,
199
209
  'private/cancel-order': 2 / 3,
200
210
  'private/cancel-order-list': 10 / 3,
@@ -1551,6 +1561,45 @@ class cryptocom(Exchange, ImplicitAPI):
1551
1561
  params = self.omit(params, ['postOnly', 'clientOrderId', 'timeInForce', 'stopPrice', 'triggerPrice', 'stopLossPrice', 'takeProfitPrice'])
1552
1562
  return self.extend(request, params)
1553
1563
 
1564
+ async def edit_order(self, id: str, symbol: str, type: OrderType, side: OrderSide, amount: Num = None, price: Num = None, params={}):
1565
+ """
1566
+ edit a trade order
1567
+
1568
+ https://exchange-docs.crypto.com/exchange/v1/rest-ws/index.html#private-amend-order
1569
+
1570
+ :param str id: order id
1571
+ :param str symbol: unified market symbol of the order to edit
1572
+ :param str [type]: not used by cryptocom editOrder
1573
+ :param str [side]: not used by cryptocom editOrder
1574
+ :param float amount:(mandatory) how much of the currency you want to trade in units of the base currency
1575
+ :param float price:(mandatory) the price for the order, in units of the quote currency, ignored in market orders
1576
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1577
+ :param str [params.clientOrderId]: the original client order id of the order to edit, required if id is not provided
1578
+ :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1579
+ """
1580
+ await self.load_markets()
1581
+ request = self.edit_order_request(id, symbol, amount, price, params)
1582
+ response = await self.v1PrivatePostPrivateAmendOrder(request)
1583
+ result = self.safe_dict(response, 'result', {})
1584
+ return self.parse_order(result)
1585
+
1586
+ def edit_order_request(self, id: str, symbol: str, amount: float, price: Num = None, params={}):
1587
+ request: dict = {}
1588
+ if id is not None:
1589
+ request['order_id'] = id
1590
+ else:
1591
+ originalClientOrderId = self.safe_string_2(params, 'orig_client_oid', 'clientOrderId')
1592
+ if originalClientOrderId is None:
1593
+ raise ArgumentsRequired(self.id + ' editOrder() requires an id argument or orig_client_oid parameter')
1594
+ else:
1595
+ request['orig_client_oid'] = originalClientOrderId
1596
+ params = self.omit(params, ['orig_client_oid', 'clientOrderId'])
1597
+ if (amount is None) or (price is None):
1598
+ raise ArgumentsRequired(self.id + ' editOrder() requires both amount and price arguments. If you do not want to change the amount or price, you should pass the original values')
1599
+ request['new_quantity'] = self.amount_to_precision(symbol, amount)
1600
+ request['new_price'] = self.price_to_precision(symbol, price)
1601
+ return self.extend(request, params)
1602
+
1554
1603
  async def cancel_all_orders(self, symbol: Str = None, params={}):
1555
1604
  """
1556
1605
  cancel all open orders
@@ -906,9 +906,9 @@ class delta(Exchange, ImplicitAPI):
906
906
  'inverse': None if spot else not linear,
907
907
  'taker': self.safe_number(market, 'taker_commission_rate'),
908
908
  'maker': self.safe_number(market, 'maker_commission_rate'),
909
- 'contractSize': contractSize,
909
+ 'contractSize': None if spot else contractSize,
910
910
  'expiry': expiry,
911
- 'expiryDatetime': expiryDatetime,
911
+ 'expiryDatetime': self.iso8601(expiry), # do not use raw expiry string
912
912
  'strike': self.parse_number(strike),
913
913
  'optionType': optionType,
914
914
  'precision': {
@@ -467,6 +467,16 @@ class digifinex(Exchange, ImplicitAPI):
467
467
  'TRX': 'TRC20',
468
468
  'VECHAIN': 'Vechain', # VET
469
469
  },
470
+ 'networksById': {
471
+ 'TRC20': 'TRC20',
472
+ 'TRX': 'TRC20',
473
+ 'BEP20': 'BEP20',
474
+ 'BSC': 'BEP20',
475
+ 'ERC20': 'ERC20',
476
+ 'ETH': 'ERC20',
477
+ 'Polygon': 'POLYGON',
478
+ 'Crypto.com': 'CRONOS',
479
+ },
470
480
  },
471
481
  'commonCurrencies': {
472
482
  'BHT': 'Black House Test',
@@ -494,6 +504,7 @@ class digifinex(Exchange, ImplicitAPI):
494
504
  # "min_withdraw_amount":10,
495
505
  # "min_withdraw_fee":5,
496
506
  # "currency":"USDT",
507
+ # "withdraw_fee_currency":"USDT",
497
508
  # "withdraw_status":0,
498
509
  # "chain":"OMNI"
499
510
  # },
@@ -504,6 +515,7 @@ class digifinex(Exchange, ImplicitAPI):
504
515
  # "min_withdraw_amount":10,
505
516
  # "min_withdraw_fee":3,
506
517
  # "currency":"USDT",
518
+ # "withdraw_fee_currency":"USDT",
507
519
  # "withdraw_status":1,
508
520
  # "chain":"ERC20"
509
521
  # },
@@ -514,6 +526,7 @@ class digifinex(Exchange, ImplicitAPI):
514
526
  # "min_withdraw_amount":0,
515
527
  # "min_withdraw_fee":0,
516
528
  # "currency":"DGF13",
529
+ # "withdraw_fee_currency":"DGF13",
517
530
  # "withdraw_status":0,
518
531
  # "chain":""
519
532
  # },
@@ -521,118 +534,45 @@ class digifinex(Exchange, ImplicitAPI):
521
534
  # "code":200
522
535
  # }
523
536
  #
524
- data = self.safe_value(response, 'data', [])
537
+ data = self.safe_list(response, 'data', [])
538
+ groupedById = self.group_by(data, 'currency')
539
+ keys = list(groupedById.keys())
525
540
  result: dict = {}
526
- for i in range(0, len(data)):
527
- currency = data[i]
528
- id = self.safe_string(currency, 'currency')
541
+ for i in range(0, len(keys)):
542
+ id = keys[i]
543
+ networkEntries = groupedById[id]
529
544
  code = self.safe_currency_code(id)
530
- depositStatus = self.safe_integer(currency, 'deposit_status', 1)
531
- withdrawStatus = self.safe_integer(currency, 'withdraw_status', 1)
532
- deposit = depositStatus > 0
533
- withdraw = withdrawStatus > 0
534
- active = deposit and withdraw
535
- feeString = self.safe_string(currency, 'min_withdraw_fee') # withdraw_fee_rate was zero for all currencies, so self was the worst case scenario
536
- minWithdrawString = self.safe_string(currency, 'min_withdraw_amount')
537
- minDepositString = self.safe_string(currency, 'min_deposit_amount')
538
- minDeposit = self.parse_number(minDepositString)
539
- minWithdraw = self.parse_number(minWithdrawString)
540
- fee = self.parse_number(feeString)
541
- # define precision with temporary way
542
- minFoundPrecision = Precise.string_min(feeString, Precise.string_min(minDepositString, minWithdrawString))
543
- precision = self.parse_number(minFoundPrecision)
544
- networkId = self.safe_string(currency, 'chain')
545
- networkCode = None
546
- if networkId is not None:
545
+ networks = {}
546
+ for j in range(0, len(networkEntries)):
547
+ networkEntry = networkEntries[j]
548
+ networkId = self.safe_string(networkEntry, 'chain')
547
549
  networkCode = self.network_id_to_code(networkId)
548
- network: dict = {
549
- 'info': currency,
550
- 'id': networkId,
551
- 'network': networkCode,
552
- 'active': active,
553
- 'fee': fee,
554
- 'precision': precision,
555
- 'deposit': deposit,
556
- 'withdraw': withdraw,
557
- 'limits': {
558
- 'amount': {
559
- 'min': None,
560
- 'max': None,
561
- },
562
- 'withdraw': {
563
- 'min': minWithdraw,
564
- 'max': None,
565
- },
566
- 'deposit': {
567
- 'min': minDeposit,
568
- 'max': None,
569
- },
570
- },
571
- }
572
- if code in result:
573
- resultCodeInfo = result[code]['info']
574
- if isinstance(resultCodeInfo, list):
575
- resultCodeInfo.append(currency)
576
- else:
577
- resultCodeInfo = [resultCodeInfo, currency]
578
- if withdraw:
579
- result[code]['withdraw'] = True
580
- result[code]['limits']['withdraw']['min'] = min(result[code]['limits']['withdraw']['min'], minWithdraw)
581
- if deposit:
582
- result[code]['deposit'] = True
583
- result[code]['limits']['deposit']['min'] = min(result[code]['limits']['deposit']['min'], minDeposit)
584
- if active:
585
- result[code]['active'] = True
586
- else:
587
- result[code] = {
588
- 'id': id,
589
- 'code': code,
590
- 'info': currency,
591
- 'type': None,
592
- 'name': None,
593
- 'active': active,
594
- 'deposit': deposit,
595
- 'withdraw': withdraw,
596
- 'fee': self.parse_number(feeString),
550
+ networks[networkCode] = {
551
+ 'id': networkId,
552
+ 'network': networkCode,
553
+ 'active': None,
554
+ 'deposit': self.safe_integer(networkEntry, 'deposit_status') == 1,
555
+ 'withdraw': self.safe_integer(networkEntry, 'withdraw_status') == 1,
556
+ 'fee': self.safe_number(networkEntry, 'min_withdraw_fee'),
597
557
  'precision': None,
598
558
  'limits': {
599
- 'amount': {
600
- 'min': None,
601
- 'max': None,
602
- },
603
559
  'withdraw': {
604
- 'min': minWithdraw,
560
+ 'min': self.safe_number(networkEntry, 'min_withdraw_amount'),
605
561
  'max': None,
606
562
  },
607
563
  'deposit': {
608
- 'min': minDeposit,
564
+ 'min': self.safe_number(networkEntry, 'min_deposit_amount'),
609
565
  'max': None,
610
566
  },
611
567
  },
612
- 'networks': {},
613
- }
614
- if networkId is not None:
615
- result[code]['networks'][networkId] = network
616
- else:
617
- result[code]['active'] = active
618
- result[code]['fee'] = self.parse_number(feeString)
619
- result[code]['deposit'] = deposit
620
- result[code]['withdraw'] = withdraw
621
- result[code]['limits'] = {
622
- 'amount': {
623
- 'min': None,
624
- 'max': None,
625
- },
626
- 'withdraw': {
627
- 'min': minWithdraw,
628
- 'max': None,
629
- },
630
- 'deposit': {
631
- 'min': minDeposit,
632
- 'max': None,
633
- },
568
+ 'info': networkEntry,
634
569
  }
635
- result[code]['precision'] = precision if (result[code]['precision'] is None) else max(result[code]['precision'], precision)
570
+ result[code] = self.safe_currency_structure({
571
+ 'id': id,
572
+ 'code': code,
573
+ 'info': networkEntries,
574
+ 'networks': networks,
575
+ })
636
576
  return result
637
577
 
638
578
  async def fetch_markets(self, params={}) -> List[Market]:
@@ -1264,17 +1264,21 @@ class gate(Exchange, ImplicitAPI):
1264
1264
  # {
1265
1265
  # "id": "QTUM_ETH",
1266
1266
  # "base": "QTUM",
1267
+ # "base_name": "Quantum",
1267
1268
  # "quote": "ETH",
1269
+ # "quote_name": "Ethereum",
1268
1270
  # "fee": "0.2",
1269
1271
  # "min_base_amount": "0.01",
1270
1272
  # "min_quote_amount": "0.001",
1273
+ # "max_quote_amount": "50000",
1271
1274
  # "amount_precision": 3,
1272
1275
  # "precision": 6,
1273
1276
  # "trade_status": "tradable",
1274
- # "sell_start": 0,
1275
- # "buy_start": 0
1277
+ # "sell_start": 1607313600,
1278
+ # "buy_start": 1700492400,
1279
+ # "type": "normal",
1280
+ # "trade_url": "https://www.gate.io/trade/QTUM_ETH",
1276
1281
  # }
1277
- # ]
1278
1282
  #
1279
1283
  # Margin
1280
1284
  #
@@ -1305,6 +1309,8 @@ class gate(Exchange, ImplicitAPI):
1305
1309
  tradeStatus = self.safe_string(market, 'trade_status')
1306
1310
  leverage = self.safe_number(market, 'leverage')
1307
1311
  margin = leverage is not None
1312
+ buyStart = self.safe_integer_product(spotMarket, 'buy_start', 1000) # buy_start is the trading start time, while sell_start is offline orders start time
1313
+ createdTs = buyStart if (buyStart != 0) else None
1308
1314
  result.append({
1309
1315
  'id': id,
1310
1316
  'symbol': base + '/' + quote,
@@ -1354,7 +1360,7 @@ class gate(Exchange, ImplicitAPI):
1354
1360
  'max': self.safe_number(market, 'max_quote_amount') if margin else None,
1355
1361
  },
1356
1362
  },
1357
- 'created': None,
1363
+ 'created': createdTs,
1358
1364
  'info': market,
1359
1365
  })
1360
1366
  return result
@@ -1419,6 +1425,7 @@ class gate(Exchange, ImplicitAPI):
1419
1425
  # "funding_next_apply": 1610035200,
1420
1426
  # "short_users": 977,
1421
1427
  # "config_change_time": 1609899548,
1428
+ # "create_time": 1609800048,
1422
1429
  # "trade_size": 28530850594,
1423
1430
  # "position_size": 5223816,
1424
1431
  # "long_users": 455,
@@ -1549,7 +1556,7 @@ class gate(Exchange, ImplicitAPI):
1549
1556
  'max': None,
1550
1557
  },
1551
1558
  },
1552
- 'created': None,
1559
+ 'created': self.safe_integer_product(market, 'create_time', 1000),
1553
1560
  'info': market,
1554
1561
  }
1555
1562
 
@@ -1151,47 +1151,43 @@ class hashkey(Exchange, ImplicitAPI):
1151
1151
  currecy = coins[i]
1152
1152
  currencyId = self.safe_string(currecy, 'coinId')
1153
1153
  code = self.safe_currency_code(currencyId)
1154
- allowWithdraw = self.safe_bool(currecy, 'allowWithdraw')
1155
- allowDeposit = self.safe_bool(currecy, 'allowDeposit')
1156
1154
  networks = self.safe_list(currecy, 'chainTypes')
1157
- networksById = self.safe_dict(self.options, 'networksById')
1158
1155
  parsedNetworks: dict = {}
1159
1156
  for j in range(0, len(networks)):
1160
1157
  network = networks[j]
1161
1158
  networkId = self.safe_string(network, 'chainType')
1162
- networkName = self.safe_string(networksById, networkId, networkId)
1163
- maxWithdrawQuantity = self.omit_zero(self.safe_string(network, 'maxWithdrawQuantity'))
1164
- networkDeposit = self.safe_bool(network, 'allowDeposit')
1165
- networkWithdraw = self.safe_bool(network, 'allowWithdraw')
1166
- parsedNetworks[networkName] = {
1159
+ networkCode = self.network_code_to_id(networkId)
1160
+ parsedNetworks[networkCode] = {
1167
1161
  'id': networkId,
1168
- 'network': networkName,
1162
+ 'network': networkCode,
1169
1163
  'limits': {
1170
1164
  'withdraw': {
1171
1165
  'min': self.safe_number(network, 'minWithdrawQuantity'),
1172
- 'max': self.parse_number(maxWithdrawQuantity),
1166
+ 'max': self.parse_number(self.omit_zero(self.safe_string(network, 'maxWithdrawQuantity'))),
1173
1167
  },
1174
1168
  'deposit': {
1175
1169
  'min': self.safe_number(network, 'minDepositQuantity'),
1176
1170
  'max': None,
1177
1171
  },
1178
1172
  },
1179
- 'active': networkDeposit and networkWithdraw,
1180
- 'deposit': networkDeposit,
1181
- 'withdraw': networkWithdraw,
1173
+ 'active': None,
1174
+ 'deposit': self.safe_bool(network, 'allowDeposit'),
1175
+ 'withdraw': self.safe_bool(network, 'allowWithdraw'),
1182
1176
  'fee': self.safe_number(network, 'withdrawFee'),
1183
1177
  'precision': None,
1184
1178
  'info': network,
1185
1179
  }
1186
- result[code] = {
1180
+ rawType = self.safe_string(currecy, 'tokenType')
1181
+ type = 'fiat' if (rawType == 'REAL_MONEY') else 'crypto'
1182
+ result[code] = self.safe_currency_structure({
1187
1183
  'id': currencyId,
1188
1184
  'code': code,
1189
1185
  'precision': None,
1190
- 'type': self.parse_currency_type(self.safe_string(currecy, 'tokenType')),
1186
+ 'type': type,
1191
1187
  'name': self.safe_string(currecy, 'coinFullName'),
1192
- 'active': allowWithdraw and allowDeposit,
1193
- 'deposit': allowDeposit,
1194
- 'withdraw': allowWithdraw,
1188
+ 'active': None,
1189
+ 'deposit': self.safe_bool(currecy, 'allowDeposit'),
1190
+ 'withdraw': self.safe_bool(currecy, 'allowWithdraw'),
1195
1191
  'fee': None,
1196
1192
  'limits': {
1197
1193
  'deposit': {
@@ -1205,18 +1201,9 @@ class hashkey(Exchange, ImplicitAPI):
1205
1201
  },
1206
1202
  'networks': parsedNetworks,
1207
1203
  'info': currecy,
1208
- }
1204
+ })
1209
1205
  return result
1210
1206
 
1211
- def parse_currency_type(self, type):
1212
- types = {
1213
- 'CHAIN_TOKEN': 'crypto',
1214
- 'ERC20_TOKEN': 'crypto',
1215
- 'BSC_TOKEN': 'crypto',
1216
- 'REAL_MONEY': 'fiat',
1217
- }
1218
- return self.safe_string(types, type)
1219
-
1220
1207
  async def fetch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook:
1221
1208
  """
1222
1209
  fetches information on open orders with bid(buy) and ask(sell) prices, volumes and other data