ccxt 4.4.88__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 (63) 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 +1 -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 +9 -3
  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/okx.py +2 -1
  28. ccxt/async_support/phemex.py +16 -8
  29. ccxt/async_support/tradeogre.py +3 -3
  30. ccxt/async_support/xt.py +1 -1
  31. ccxt/base/exchange.py +13 -4
  32. ccxt/binance.py +1 -1
  33. ccxt/bingx.py +55 -29
  34. ccxt/bitget.py +469 -147
  35. ccxt/bitrue.py +72 -66
  36. ccxt/bitvavo.py +34 -0
  37. ccxt/btcalpha.py +35 -0
  38. ccxt/btcbox.py +35 -0
  39. ccxt/btcmarkets.py +35 -0
  40. ccxt/btcturk.py +35 -0
  41. ccxt/bybit.py +9 -3
  42. ccxt/coinbase.py +1 -3
  43. ccxt/cryptocom.py +49 -0
  44. ccxt/delta.py +2 -2
  45. ccxt/digifinex.py +39 -99
  46. ccxt/gate.py +12 -5
  47. ccxt/hashkey.py +15 -28
  48. ccxt/hollaex.py +27 -22
  49. ccxt/kraken.py +27 -49
  50. ccxt/luno.py +87 -1
  51. ccxt/okx.py +2 -1
  52. ccxt/phemex.py +16 -8
  53. ccxt/pro/__init__.py +1 -127
  54. ccxt/pro/coinbase.py +2 -0
  55. ccxt/pro/cryptocom.py +27 -0
  56. ccxt/pro/kraken.py +3 -9
  57. ccxt/tradeogre.py +3 -3
  58. ccxt/xt.py +1 -1
  59. {ccxt-4.4.88.dist-info → ccxt-4.4.90.dist-info}/METADATA +62 -20
  60. {ccxt-4.4.88.dist-info → ccxt-4.4.90.dist-info}/RECORD +63 -63
  61. {ccxt-4.4.88.dist-info → ccxt-4.4.90.dist-info}/LICENSE.txt +0 -0
  62. {ccxt-4.4.88.dist-info → ccxt-4.4.90.dist-info}/WHEEL +0 -0
  63. {ccxt-4.4.88.dist-info → ccxt-4.4.90.dist-info}/top_level.txt +0 -0
ccxt/bybit.py CHANGED
@@ -3675,7 +3675,10 @@ class bybit(Exchange, ImplicitAPI):
3675
3675
  market = self.market(symbol)
3676
3676
  if not market['spot']:
3677
3677
  raise NotSupported(self.id + ' createMarketBuyOrderWithCost() supports spot orders only')
3678
- return self.create_order(symbol, 'market', 'buy', cost, 1, params)
3678
+ req = {
3679
+ 'cost': cost,
3680
+ }
3681
+ return self.create_order(symbol, 'market', 'buy', -1, None, self.extend(req, params))
3679
3682
 
3680
3683
  def create_market_sell_order_with_cost(self, symbol: str, cost: float, params={}) -> Order:
3681
3684
  """
@@ -3696,7 +3699,10 @@ class bybit(Exchange, ImplicitAPI):
3696
3699
  market = self.market(symbol)
3697
3700
  if not market['spot']:
3698
3701
  raise NotSupported(self.id + ' createMarketSellOrderWithCost() supports spot orders only')
3699
- return self.create_order(symbol, 'market', 'sell', cost, 1, params)
3702
+ req = {
3703
+ 'cost': cost,
3704
+ }
3705
+ return self.create_order(symbol, 'market', 'sell', -1, None, self.extend(req, params))
3700
3706
 
3701
3707
  def create_order(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}) -> Order:
3702
3708
  """
@@ -3904,7 +3910,7 @@ class bybit(Exchange, ImplicitAPI):
3904
3910
  if (price is None) and (cost is None):
3905
3911
  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')
3906
3912
  else:
3907
- quoteAmount = Precise.string_mul(amountString, priceString)
3913
+ quoteAmount = Precise.string_mul(self.number_to_string(amount), priceString)
3908
3914
  costRequest = cost if (cost is not None) else quoteAmount
3909
3915
  request['qty'] = self.get_cost(symbol, costRequest)
3910
3916
  else:
ccxt/coinbase.py CHANGED
@@ -4408,7 +4408,7 @@ class coinbase(Exchange, ImplicitAPI):
4408
4408
  """
4409
4409
  *futures only* closes open positions for a market
4410
4410
 
4411
- https://coinbase-api.github.io/docs/#/en-us/swapV2/trade-api.html#One-Click%20Close%20All%20Positions
4411
+ https://docs.cdp.coinbase.com/coinbase-app/trade/reference/retailbrokerageapi_closeposition
4412
4412
 
4413
4413
  :param str symbol: Unified CCXT market symbol
4414
4414
  :param str [side]: not used by coinbase
@@ -4419,8 +4419,6 @@ class coinbase(Exchange, ImplicitAPI):
4419
4419
  """
4420
4420
  self.load_markets()
4421
4421
  market = self.market(symbol)
4422
- if not market['future']:
4423
- raise NotSupported(self.id + ' closePosition() only supported for futures markets')
4424
4422
  clientOrderId = self.safe_string_2(params, 'client_order_id', 'clientOrderId')
4425
4423
  params = self.omit(params, 'clientOrderId')
4426
4424
  request: dict = {
ccxt/cryptocom.py CHANGED
@@ -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
+ 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
+ self.load_markets()
1581
+ request = self.edit_order_request(id, symbol, amount, price, params)
1582
+ response = 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
  def cancel_all_orders(self, symbol: Str = None, params={}):
1555
1604
  """
1556
1605
  cancel all open orders
ccxt/delta.py CHANGED
@@ -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': {
ccxt/digifinex.py CHANGED
@@ -466,6 +466,16 @@ class digifinex(Exchange, ImplicitAPI):
466
466
  'TRX': 'TRC20',
467
467
  'VECHAIN': 'Vechain', # VET
468
468
  },
469
+ 'networksById': {
470
+ 'TRC20': 'TRC20',
471
+ 'TRX': 'TRC20',
472
+ 'BEP20': 'BEP20',
473
+ 'BSC': 'BEP20',
474
+ 'ERC20': 'ERC20',
475
+ 'ETH': 'ERC20',
476
+ 'Polygon': 'POLYGON',
477
+ 'Crypto.com': 'CRONOS',
478
+ },
469
479
  },
470
480
  'commonCurrencies': {
471
481
  'BHT': 'Black House Test',
@@ -493,6 +503,7 @@ class digifinex(Exchange, ImplicitAPI):
493
503
  # "min_withdraw_amount":10,
494
504
  # "min_withdraw_fee":5,
495
505
  # "currency":"USDT",
506
+ # "withdraw_fee_currency":"USDT",
496
507
  # "withdraw_status":0,
497
508
  # "chain":"OMNI"
498
509
  # },
@@ -503,6 +514,7 @@ class digifinex(Exchange, ImplicitAPI):
503
514
  # "min_withdraw_amount":10,
504
515
  # "min_withdraw_fee":3,
505
516
  # "currency":"USDT",
517
+ # "withdraw_fee_currency":"USDT",
506
518
  # "withdraw_status":1,
507
519
  # "chain":"ERC20"
508
520
  # },
@@ -513,6 +525,7 @@ class digifinex(Exchange, ImplicitAPI):
513
525
  # "min_withdraw_amount":0,
514
526
  # "min_withdraw_fee":0,
515
527
  # "currency":"DGF13",
528
+ # "withdraw_fee_currency":"DGF13",
516
529
  # "withdraw_status":0,
517
530
  # "chain":""
518
531
  # },
@@ -520,118 +533,45 @@ class digifinex(Exchange, ImplicitAPI):
520
533
  # "code":200
521
534
  # }
522
535
  #
523
- data = self.safe_value(response, 'data', [])
536
+ data = self.safe_list(response, 'data', [])
537
+ groupedById = self.group_by(data, 'currency')
538
+ keys = list(groupedById.keys())
524
539
  result: dict = {}
525
- for i in range(0, len(data)):
526
- currency = data[i]
527
- id = self.safe_string(currency, 'currency')
540
+ for i in range(0, len(keys)):
541
+ id = keys[i]
542
+ networkEntries = groupedById[id]
528
543
  code = self.safe_currency_code(id)
529
- depositStatus = self.safe_integer(currency, 'deposit_status', 1)
530
- withdrawStatus = self.safe_integer(currency, 'withdraw_status', 1)
531
- deposit = depositStatus > 0
532
- withdraw = withdrawStatus > 0
533
- active = deposit and withdraw
534
- feeString = self.safe_string(currency, 'min_withdraw_fee') # withdraw_fee_rate was zero for all currencies, so self was the worst case scenario
535
- minWithdrawString = self.safe_string(currency, 'min_withdraw_amount')
536
- minDepositString = self.safe_string(currency, 'min_deposit_amount')
537
- minDeposit = self.parse_number(minDepositString)
538
- minWithdraw = self.parse_number(minWithdrawString)
539
- fee = self.parse_number(feeString)
540
- # define precision with temporary way
541
- minFoundPrecision = Precise.string_min(feeString, Precise.string_min(minDepositString, minWithdrawString))
542
- precision = self.parse_number(minFoundPrecision)
543
- networkId = self.safe_string(currency, 'chain')
544
- networkCode = None
545
- if networkId is not None:
544
+ networks = {}
545
+ for j in range(0, len(networkEntries)):
546
+ networkEntry = networkEntries[j]
547
+ networkId = self.safe_string(networkEntry, 'chain')
546
548
  networkCode = self.network_id_to_code(networkId)
547
- network: dict = {
548
- 'info': currency,
549
- 'id': networkId,
550
- 'network': networkCode,
551
- 'active': active,
552
- 'fee': fee,
553
- 'precision': precision,
554
- 'deposit': deposit,
555
- 'withdraw': withdraw,
556
- 'limits': {
557
- 'amount': {
558
- 'min': None,
559
- 'max': None,
560
- },
561
- 'withdraw': {
562
- 'min': minWithdraw,
563
- 'max': None,
564
- },
565
- 'deposit': {
566
- 'min': minDeposit,
567
- 'max': None,
568
- },
569
- },
570
- }
571
- if code in result:
572
- resultCodeInfo = result[code]['info']
573
- if isinstance(resultCodeInfo, list):
574
- resultCodeInfo.append(currency)
575
- else:
576
- resultCodeInfo = [resultCodeInfo, currency]
577
- if withdraw:
578
- result[code]['withdraw'] = True
579
- result[code]['limits']['withdraw']['min'] = min(result[code]['limits']['withdraw']['min'], minWithdraw)
580
- if deposit:
581
- result[code]['deposit'] = True
582
- result[code]['limits']['deposit']['min'] = min(result[code]['limits']['deposit']['min'], minDeposit)
583
- if active:
584
- result[code]['active'] = True
585
- else:
586
- result[code] = {
587
- 'id': id,
588
- 'code': code,
589
- 'info': currency,
590
- 'type': None,
591
- 'name': None,
592
- 'active': active,
593
- 'deposit': deposit,
594
- 'withdraw': withdraw,
595
- 'fee': self.parse_number(feeString),
549
+ networks[networkCode] = {
550
+ 'id': networkId,
551
+ 'network': networkCode,
552
+ 'active': None,
553
+ 'deposit': self.safe_integer(networkEntry, 'deposit_status') == 1,
554
+ 'withdraw': self.safe_integer(networkEntry, 'withdraw_status') == 1,
555
+ 'fee': self.safe_number(networkEntry, 'min_withdraw_fee'),
596
556
  'precision': None,
597
557
  'limits': {
598
- 'amount': {
599
- 'min': None,
600
- 'max': None,
601
- },
602
558
  'withdraw': {
603
- 'min': minWithdraw,
559
+ 'min': self.safe_number(networkEntry, 'min_withdraw_amount'),
604
560
  'max': None,
605
561
  },
606
562
  'deposit': {
607
- 'min': minDeposit,
563
+ 'min': self.safe_number(networkEntry, 'min_deposit_amount'),
608
564
  'max': None,
609
565
  },
610
566
  },
611
- 'networks': {},
612
- }
613
- if networkId is not None:
614
- result[code]['networks'][networkId] = network
615
- else:
616
- result[code]['active'] = active
617
- result[code]['fee'] = self.parse_number(feeString)
618
- result[code]['deposit'] = deposit
619
- result[code]['withdraw'] = withdraw
620
- result[code]['limits'] = {
621
- 'amount': {
622
- 'min': None,
623
- 'max': None,
624
- },
625
- 'withdraw': {
626
- 'min': minWithdraw,
627
- 'max': None,
628
- },
629
- 'deposit': {
630
- 'min': minDeposit,
631
- 'max': None,
632
- },
567
+ 'info': networkEntry,
633
568
  }
634
- result[code]['precision'] = precision if (result[code]['precision'] is None) else max(result[code]['precision'], precision)
569
+ result[code] = self.safe_currency_structure({
570
+ 'id': id,
571
+ 'code': code,
572
+ 'info': networkEntries,
573
+ 'networks': networks,
574
+ })
635
575
  return result
636
576
 
637
577
  def fetch_markets(self, params={}) -> List[Market]:
ccxt/gate.py CHANGED
@@ -1263,17 +1263,21 @@ class gate(Exchange, ImplicitAPI):
1263
1263
  # {
1264
1264
  # "id": "QTUM_ETH",
1265
1265
  # "base": "QTUM",
1266
+ # "base_name": "Quantum",
1266
1267
  # "quote": "ETH",
1268
+ # "quote_name": "Ethereum",
1267
1269
  # "fee": "0.2",
1268
1270
  # "min_base_amount": "0.01",
1269
1271
  # "min_quote_amount": "0.001",
1272
+ # "max_quote_amount": "50000",
1270
1273
  # "amount_precision": 3,
1271
1274
  # "precision": 6,
1272
1275
  # "trade_status": "tradable",
1273
- # "sell_start": 0,
1274
- # "buy_start": 0
1276
+ # "sell_start": 1607313600,
1277
+ # "buy_start": 1700492400,
1278
+ # "type": "normal",
1279
+ # "trade_url": "https://www.gate.io/trade/QTUM_ETH",
1275
1280
  # }
1276
- # ]
1277
1281
  #
1278
1282
  # Margin
1279
1283
  #
@@ -1304,6 +1308,8 @@ class gate(Exchange, ImplicitAPI):
1304
1308
  tradeStatus = self.safe_string(market, 'trade_status')
1305
1309
  leverage = self.safe_number(market, 'leverage')
1306
1310
  margin = leverage is not None
1311
+ buyStart = self.safe_integer_product(spotMarket, 'buy_start', 1000) # buy_start is the trading start time, while sell_start is offline orders start time
1312
+ createdTs = buyStart if (buyStart != 0) else None
1307
1313
  result.append({
1308
1314
  'id': id,
1309
1315
  'symbol': base + '/' + quote,
@@ -1353,7 +1359,7 @@ class gate(Exchange, ImplicitAPI):
1353
1359
  'max': self.safe_number(market, 'max_quote_amount') if margin else None,
1354
1360
  },
1355
1361
  },
1356
- 'created': None,
1362
+ 'created': createdTs,
1357
1363
  'info': market,
1358
1364
  })
1359
1365
  return result
@@ -1418,6 +1424,7 @@ class gate(Exchange, ImplicitAPI):
1418
1424
  # "funding_next_apply": 1610035200,
1419
1425
  # "short_users": 977,
1420
1426
  # "config_change_time": 1609899548,
1427
+ # "create_time": 1609800048,
1421
1428
  # "trade_size": 28530850594,
1422
1429
  # "position_size": 5223816,
1423
1430
  # "long_users": 455,
@@ -1548,7 +1555,7 @@ class gate(Exchange, ImplicitAPI):
1548
1555
  'max': None,
1549
1556
  },
1550
1557
  },
1551
- 'created': None,
1558
+ 'created': self.safe_integer_product(market, 'create_time', 1000),
1552
1559
  'info': market,
1553
1560
  }
1554
1561
 
ccxt/hashkey.py CHANGED
@@ -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
  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
ccxt/hollaex.py CHANGED
@@ -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 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 = self.publicGetChart(self.extend(request, params))
925
937
  #
@@ -1277,11 +1289,10 @@ class hollaex(Exchange, ImplicitAPI):
1277
1289
  """
1278
1290
  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)