ccxt 4.4.78__py2.py3-none-any.whl → 4.4.82__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 (87) hide show
  1. ccxt/__init__.py +1 -1
  2. ccxt/abstract/bitmart.py +1 -0
  3. ccxt/apex.py +21 -31
  4. ccxt/ascendex.py +23 -6
  5. ccxt/async_support/__init__.py +1 -1
  6. ccxt/async_support/apex.py +21 -31
  7. ccxt/async_support/ascendex.py +23 -6
  8. ccxt/async_support/base/exchange.py +5 -1
  9. ccxt/async_support/bigone.py +17 -14
  10. ccxt/async_support/binance.py +6 -0
  11. ccxt/async_support/bingx.py +16 -35
  12. ccxt/async_support/bitfinex.py +120 -82
  13. ccxt/async_support/bitget.py +58 -66
  14. ccxt/async_support/bitmart.py +7 -2
  15. ccxt/async_support/bitmex.py +8 -1
  16. ccxt/async_support/bitopro.py +5 -1
  17. ccxt/async_support/bitrue.py +2 -1
  18. ccxt/async_support/bitso.py +1 -1
  19. ccxt/async_support/bitteam.py +2 -0
  20. ccxt/async_support/bitvavo.py +25 -10
  21. ccxt/async_support/btcalpha.py +1 -1
  22. ccxt/async_support/btcmarkets.py +1 -1
  23. ccxt/async_support/btcturk.py +1 -1
  24. ccxt/async_support/bybit.py +29 -15
  25. ccxt/async_support/coinbase.py +3 -15
  26. ccxt/async_support/coinex.py +1 -0
  27. ccxt/async_support/coinlist.py +1 -0
  28. ccxt/async_support/coinone.py +1 -0
  29. ccxt/async_support/delta.py +3 -0
  30. ccxt/async_support/deribit.py +1 -0
  31. ccxt/async_support/hollaex.py +1 -0
  32. ccxt/async_support/htx.py +9 -5
  33. ccxt/async_support/huobijp.py +1 -0
  34. ccxt/async_support/hyperliquid.py +14 -0
  35. ccxt/async_support/kraken.py +2 -0
  36. ccxt/async_support/okx.py +2 -3
  37. ccxt/async_support/oxfun.py +21 -1
  38. ccxt/async_support/poloniex.py +1 -0
  39. ccxt/async_support/timex.py +2 -2
  40. ccxt/async_support/upbit.py +43 -21
  41. ccxt/async_support/whitebit.py +65 -12
  42. ccxt/base/exchange.py +20 -2
  43. ccxt/bigone.py +17 -14
  44. ccxt/binance.py +6 -0
  45. ccxt/bingx.py +16 -35
  46. ccxt/bitfinex.py +120 -82
  47. ccxt/bitget.py +58 -66
  48. ccxt/bitmart.py +7 -2
  49. ccxt/bitmex.py +8 -1
  50. ccxt/bitopro.py +5 -1
  51. ccxt/bitrue.py +2 -1
  52. ccxt/bitso.py +1 -1
  53. ccxt/bitteam.py +2 -0
  54. ccxt/bitvavo.py +25 -10
  55. ccxt/btcalpha.py +1 -1
  56. ccxt/btcmarkets.py +1 -1
  57. ccxt/btcturk.py +1 -1
  58. ccxt/bybit.py +29 -15
  59. ccxt/coinbase.py +3 -15
  60. ccxt/coinex.py +1 -0
  61. ccxt/coinlist.py +1 -0
  62. ccxt/coinone.py +1 -0
  63. ccxt/delta.py +3 -0
  64. ccxt/deribit.py +1 -0
  65. ccxt/hollaex.py +1 -0
  66. ccxt/htx.py +9 -5
  67. ccxt/huobijp.py +1 -0
  68. ccxt/hyperliquid.py +14 -0
  69. ccxt/kraken.py +2 -0
  70. ccxt/okx.py +2 -3
  71. ccxt/oxfun.py +21 -1
  72. ccxt/poloniex.py +1 -0
  73. ccxt/pro/__init__.py +1 -1
  74. ccxt/pro/binance.py +3 -3
  75. ccxt/pro/coinbase.py +41 -53
  76. ccxt/pro/hyperliquid.py +10 -2
  77. ccxt/pro/upbit.py +42 -0
  78. ccxt/test/tests_async.py +0 -1
  79. ccxt/test/tests_sync.py +0 -1
  80. ccxt/timex.py +2 -2
  81. ccxt/upbit.py +43 -21
  82. ccxt/whitebit.py +65 -12
  83. {ccxt-4.4.78.dist-info → ccxt-4.4.82.dist-info}/METADATA +9 -13
  84. {ccxt-4.4.78.dist-info → ccxt-4.4.82.dist-info}/RECORD +87 -87
  85. {ccxt-4.4.78.dist-info → ccxt-4.4.82.dist-info}/LICENSE.txt +0 -0
  86. {ccxt-4.4.78.dist-info → ccxt-4.4.82.dist-info}/WHEEL +0 -0
  87. {ccxt-4.4.78.dist-info → ccxt-4.4.82.dist-info}/top_level.txt +0 -0
@@ -742,7 +742,7 @@ class bitso(Exchange, ImplicitAPI):
742
742
  # {
743
743
  # "bucket_start_time":1648219140000,
744
744
  # "first_trade_time":1648219154990,
745
- # "last_trade_time":1648219189441,
745
+ # "last_trade_time":1648219189442,
746
746
  # "first_rate":"44958.60",
747
747
  # "last_rate":"44979.88",
748
748
  # "min_rate":"44957.33",
@@ -650,6 +650,7 @@ class bitteam(Exchange, ImplicitAPI):
650
650
  networkIds = list(feesByNetworkId.keys())
651
651
  networks: dict = {}
652
652
  networkPrecision = self.parse_number(self.parse_precision(self.safe_string(currency, 'decimals')))
653
+ typeRaw = self.safe_string(currency, 'type')
653
654
  for j in range(0, len(networkIds)):
654
655
  networkId = networkIds[j]
655
656
  networkCode = self.network_id_to_code(networkId, code)
@@ -703,6 +704,7 @@ class bitteam(Exchange, ImplicitAPI):
703
704
  'max': None,
704
705
  },
705
706
  },
707
+ 'type': typeRaw, # 'crypto' or 'fiat'
706
708
  'networks': networks,
707
709
  }
708
710
  return result
@@ -361,6 +361,8 @@ class bitvavo(Exchange, ImplicitAPI):
361
361
  'ERC20': 'ETH',
362
362
  'TRC20': 'TRX',
363
363
  },
364
+ 'operatorId': None, # self will be required soon for order-related endpoints
365
+ 'fiatCurrencies': ['EUR'], # only fiat atm
364
366
  },
365
367
  'precisionMode': SIGNIFICANT_DIGITS,
366
368
  'commonCurrencies': {
@@ -567,24 +569,24 @@ class bitvavo(Exchange, ImplicitAPI):
567
569
  # },
568
570
  # ]
569
571
  #
572
+ fiatCurrencies = self.safe_list(self.options, 'fiatCurrencies', [])
570
573
  result: dict = {}
571
574
  for i in range(0, len(currencies)):
572
575
  currency = currencies[i]
573
576
  id = self.safe_string(currency, 'symbol')
574
577
  code = self.safe_currency_code(id)
578
+ isFiat = self.in_array(code, fiatCurrencies)
575
579
  networks: dict = {}
576
- networksArray = self.safe_value(currency, 'networks', [])
577
- networksLength = len(networksArray)
578
- isOneNetwork = (networksLength == 1)
579
- deposit = (self.safe_value(currency, 'depositStatus') == 'OK')
580
- withdrawal = (self.safe_value(currency, 'withdrawalStatus') == 'OK')
580
+ networksArray = self.safe_list(currency, 'networks', [])
581
+ deposit = self.safe_string(currency, 'depositStatus') == 'OK'
582
+ withdrawal = self.safe_string(currency, 'withdrawalStatus') == 'OK'
581
583
  active = deposit and withdrawal
582
584
  withdrawFee = self.safe_number(currency, 'withdrawalFee')
583
585
  precision = self.safe_integer(currency, 'decimals', 8)
584
586
  minWithdraw = self.safe_number(currency, 'withdrawalMinAmount')
585
- # absolutely all of them have 1 network atm - ETH. So, we can reliably assign that inside networks
586
- if isOneNetwork:
587
- networkId = networksArray[0]
587
+ # btw, absolutely all of them have 1 network atm
588
+ for j in range(0, len(networksArray)):
589
+ networkId = networksArray[j]
588
590
  networkCode = self.network_id_to_code(networkId)
589
591
  networks[networkCode] = {
590
592
  'info': currency,
@@ -602,7 +604,7 @@ class bitvavo(Exchange, ImplicitAPI):
602
604
  },
603
605
  },
604
606
  }
605
- result[code] = {
607
+ result[code] = self.safe_currency_structure({
606
608
  'info': currency,
607
609
  'id': id,
608
610
  'code': code,
@@ -613,6 +615,7 @@ class bitvavo(Exchange, ImplicitAPI):
613
615
  'networks': networks,
614
616
  'fee': withdrawFee,
615
617
  'precision': precision,
618
+ 'type': 'fiat' if isFiat else 'crypto',
616
619
  'limits': {
617
620
  'amount': {
618
621
  'min': None,
@@ -627,7 +630,7 @@ class bitvavo(Exchange, ImplicitAPI):
627
630
  'max': None,
628
631
  },
629
632
  },
630
- }
633
+ })
631
634
  # set currencies here to avoid calling publicGetAssets twice
632
635
  self.currencies = self.deep_extend(self.currencies, result)
633
636
  return result
@@ -1166,6 +1169,10 @@ class bitvavo(Exchange, ImplicitAPI):
1166
1169
  request['timeInForce'] = timeInForce
1167
1170
  if postOnly:
1168
1171
  request['postOnly'] = True
1172
+ operatorId = None
1173
+ operatorId, params = self.handle_option_and_params(params, 'createOrder', 'operatorId')
1174
+ if operatorId is not None:
1175
+ request['operatorId'] = self.parse_to_int(operatorId)
1169
1176
  return self.extend(request, params)
1170
1177
 
1171
1178
  async def create_order(self, symbol: Str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
@@ -1259,6 +1266,10 @@ class bitvavo(Exchange, ImplicitAPI):
1259
1266
  clientOrderId = self.safe_string(params, 'clientOrderId')
1260
1267
  if clientOrderId is None:
1261
1268
  request['orderId'] = id
1269
+ operatorId = None
1270
+ operatorId, params = self.handle_option_and_params(params, 'editOrder', 'operatorId')
1271
+ if operatorId is not None:
1272
+ request['operatorId'] = self.parse_to_int(operatorId)
1262
1273
  request['market'] = market['id']
1263
1274
  return request
1264
1275
 
@@ -1293,6 +1304,10 @@ class bitvavo(Exchange, ImplicitAPI):
1293
1304
  clientOrderId = self.safe_string(params, 'clientOrderId')
1294
1305
  if clientOrderId is None:
1295
1306
  request['orderId'] = id
1307
+ operatorId = None
1308
+ operatorId, params = self.handle_option_and_params(params, 'cancelOrder', 'operatorId')
1309
+ if operatorId is not None:
1310
+ request['operatorId'] = self.parse_to_int(operatorId)
1296
1311
  return self.extend(request, params)
1297
1312
 
1298
1313
  async def cancel_order(self, id: str, symbol: Str = None, params={}):
@@ -216,7 +216,7 @@ class btcalpha(Exchange, ImplicitAPI):
216
216
  'symbolRequired': False,
217
217
  },
218
218
  'fetchOHLCV': {
219
- 'max': 720,
219
+ 'limit': 720,
220
220
  },
221
221
  },
222
222
  'swap': {
@@ -455,7 +455,7 @@ class btcmarkets(Exchange, ImplicitAPI):
455
455
  # "marketId":"COMP-AUD",
456
456
  # "baseAssetName":"COMP",
457
457
  # "quoteAssetName":"AUD",
458
- # "minOrderAmount":"0.00007",
458
+ # "minOrderAmount":"0.00006",
459
459
  # "maxOrderAmount":"1000000",
460
460
  # "amountDecimals":"8",
461
461
  # "priceDecimals":"2",
@@ -248,7 +248,7 @@ class btcturk(Exchange, ImplicitAPI):
248
248
  # "minPrice": "0.0000000000001",
249
249
  # "maxPrice": "10000000",
250
250
  # "tickSize": "10",
251
- # "minExchangeValue": "99.91",
251
+ # "minExchangeValue": "99.92",
252
252
  # "minAmount": null,
253
253
  # "maxAmount": null
254
254
  # }
@@ -1041,9 +1041,6 @@ class bybit(Exchange, ImplicitAPI):
1041
1041
  'usePrivateInstrumentsInfo': False,
1042
1042
  'enableDemoTrading': False,
1043
1043
  'fetchMarkets': ['spot', 'linear', 'inverse', 'option'],
1044
- 'createOrder': {
1045
- 'method': 'privatePostV5OrderCreate', # 'privatePostV5PositionTradingStop'
1046
- },
1047
1044
  'enableUnifiedMargin': None,
1048
1045
  'enableUnifiedAccount': None,
1049
1046
  'unifiedMarginStatus': None,
@@ -1708,6 +1705,7 @@ class bybit(Exchange, ImplicitAPI):
1708
1705
  },
1709
1706
  },
1710
1707
  'networks': networks,
1708
+ 'type': 'crypto', # atm exchange api provides only cryptos
1711
1709
  }
1712
1710
  return result
1713
1711
 
@@ -2131,6 +2129,7 @@ class bybit(Exchange, ImplicitAPI):
2131
2129
  strike = self.safe_string(splitId, 2)
2132
2130
  optionLetter = self.safe_string(splitId, 3)
2133
2131
  isActive = (status == 'Trading')
2132
+ isInverse = base == settle
2134
2133
  if isActive or (self.options['loadAllOptions']) or (self.options['loadExpiredOptions']):
2135
2134
  result.append(self.safe_market_structure({
2136
2135
  'id': id,
@@ -2142,7 +2141,7 @@ class bybit(Exchange, ImplicitAPI):
2142
2141
  'quoteId': quoteId,
2143
2142
  'settleId': settleId,
2144
2143
  'type': 'option',
2145
- 'subType': 'linear',
2144
+ 'subType': None,
2146
2145
  'spot': False,
2147
2146
  'margin': False,
2148
2147
  'swap': False,
@@ -2150,8 +2149,8 @@ class bybit(Exchange, ImplicitAPI):
2150
2149
  'option': True,
2151
2150
  'active': isActive,
2152
2151
  'contract': True,
2153
- 'linear': True,
2154
- 'inverse': False,
2152
+ 'linear': not isInverse,
2153
+ 'inverse': isInverse,
2155
2154
  'taker': self.safe_number(market, 'takerFee', self.parse_number('0.0006')),
2156
2155
  'maker': self.safe_number(market, 'makerFee', self.parse_number('0.0001')),
2157
2156
  'contractSize': self.parse_number('1'),
@@ -3775,12 +3774,21 @@ class bybit(Exchange, ImplicitAPI):
3775
3774
  parts = await self.is_unified_enabled()
3776
3775
  enableUnifiedAccount = parts[1]
3777
3776
  trailingAmount = self.safe_string_2(params, 'trailingAmount', 'trailingStop')
3777
+ stopLossPrice = self.safe_string(params, 'stopLossPrice')
3778
+ takeProfitPrice = self.safe_string(params, 'takeProfitPrice')
3778
3779
  isTrailingAmountOrder = trailingAmount is not None
3780
+ isStopLoss = stopLossPrice is not None
3781
+ isTakeProfit = takeProfitPrice is not None
3779
3782
  orderRequest = self.create_order_request(symbol, type, side, amount, price, params, enableUnifiedAccount)
3780
- options = self.safe_dict(self.options, 'createOrder', {})
3781
- defaultMethod = self.safe_string(options, 'method', 'privatePostV5OrderCreate')
3783
+ defaultMethod = None
3784
+ if isTrailingAmountOrder or isStopLoss or isTakeProfit:
3785
+ defaultMethod = 'privatePostV5PositionTradingStop'
3786
+ else:
3787
+ defaultMethod = 'privatePostV5OrderCreate'
3788
+ method = None
3789
+ method, params = self.handle_option_and_params(params, 'createOrder', 'method', defaultMethod)
3782
3790
  response = None
3783
- if isTrailingAmountOrder or (defaultMethod == 'privatePostV5PositionTradingStop'):
3791
+ if method == 'privatePostV5PositionTradingStop':
3784
3792
  response = await self.privatePostV5PositionTradingStop(orderRequest)
3785
3793
  else:
3786
3794
  response = await self.privatePostV5OrderCreate(orderRequest) # already extended inside createOrderRequest
@@ -3805,8 +3813,6 @@ class bybit(Exchange, ImplicitAPI):
3805
3813
  lowerCaseType = type.lower()
3806
3814
  if (price is None) and (lowerCaseType == 'limit'):
3807
3815
  raise ArgumentsRequired(self.id + ' createOrder requires a price argument for limit orders')
3808
- defaultMethod = None
3809
- defaultMethod, params = self.handle_option_and_params(params, 'createOrder', 'method', 'privatePostV5OrderCreate')
3810
3816
  request: dict = {
3811
3817
  'symbol': market['id'],
3812
3818
  # 'side': self.capitalize(side),
@@ -3850,7 +3856,14 @@ class bybit(Exchange, ImplicitAPI):
3850
3856
  isMarket = lowerCaseType == 'market'
3851
3857
  isLimit = lowerCaseType == 'limit'
3852
3858
  isBuy = side == 'buy'
3853
- isAlternativeEndpoint = defaultMethod == 'privatePostV5PositionTradingStop'
3859
+ defaultMethod = None
3860
+ if isTrailingAmountOrder or isStopLossTriggerOrder or isTakeProfitTriggerOrder:
3861
+ defaultMethod = 'privatePostV5PositionTradingStop'
3862
+ else:
3863
+ defaultMethod = 'privatePostV5OrderCreate'
3864
+ method = None
3865
+ method, params = self.handle_option_and_params(params, 'createOrder', 'method', defaultMethod)
3866
+ isAlternativeEndpoint = method == 'privatePostV5PositionTradingStop'
3854
3867
  amountString = self.get_amount(symbol, amount)
3855
3868
  priceString = self.get_price(symbol, self.number_to_string(price)) if (price is not None) else None
3856
3869
  if isTrailingAmountOrder or isAlternativeEndpoint:
@@ -3901,12 +3914,12 @@ class bybit(Exchange, ImplicitAPI):
3901
3914
  request['price'] = priceString
3902
3915
  if market['spot']:
3903
3916
  request['category'] = 'spot'
3917
+ elif market['option']:
3918
+ request['category'] = 'option'
3904
3919
  elif market['linear']:
3905
3920
  request['category'] = 'linear'
3906
3921
  elif market['inverse']:
3907
3922
  request['category'] = 'inverse'
3908
- elif market['option']:
3909
- request['category'] = 'option'
3910
3923
  cost = self.safe_string(params, 'cost')
3911
3924
  params = self.omit(params, 'cost')
3912
3925
  # if the cost is inferable, let's keep the old logic and ignore marketUnit, to minimize the impact of the changes
@@ -5651,7 +5664,8 @@ classic accounts only/ spot not supported* fetches information on an order made
5651
5664
  subType, params = self.handle_sub_type_and_params('fetchLedger', None, params)
5652
5665
  response = None
5653
5666
  if enableUnified[1]:
5654
- if subType == 'inverse':
5667
+ unifiedMarginStatus = self.safe_integer(self.options, 'unifiedMarginStatus', 5) # 3/4 uta 1.0, 5/6 uta 2.0
5668
+ if subType == 'inverse' and (unifiedMarginStatus < 5):
5655
5669
  response = await self.privateGetV5AccountContractTransactionLog(self.extend(request, params))
5656
5670
  else:
5657
5671
  response = await self.privateGetV5AccountTransactionLog(self.extend(request, params))
@@ -387,7 +387,6 @@ class coinbase(Exchange, ImplicitAPI):
387
387
  'fetchBalance': 'v2PrivateGetAccounts', # 'v2PrivateGetAccounts' or 'v3PrivateGetBrokerageAccounts'
388
388
  'fetchTime': 'v2PublicGetTime', # 'v2PublicGetTime' or 'v3PublicGetBrokerageTime'
389
389
  'user_native_currency': 'USD', # needed to get fees for v3
390
- 'aliasCbMarketIds': {},
391
390
  },
392
391
  'features': {
393
392
  'default': {
@@ -1475,8 +1474,6 @@ class coinbase(Exchange, ImplicitAPI):
1475
1474
  perpetualData = self.safe_list(perpetualFutures, 'products', [])
1476
1475
  for i in range(0, len(perpetualData)):
1477
1476
  result.append(self.parse_contract_market(perpetualData[i], perpetualFeeTier))
1478
- # remove aliases
1479
- self.options['aliasCbMarketIds'] = {}
1480
1477
  newMarkets = []
1481
1478
  for i in range(0, len(result)):
1482
1479
  market = result[i]
@@ -1484,21 +1481,12 @@ class coinbase(Exchange, ImplicitAPI):
1484
1481
  realMarketIds = self.safe_list(info, 'alias_to', [])
1485
1482
  length = len(realMarketIds)
1486
1483
  if length > 0:
1487
- self.options['aliasCbMarketIds'][market['id']] = realMarketIds[0]
1488
- self.options['aliasCbMarketIds'][market['symbol']] = realMarketIds[0]
1484
+ market['alias'] = realMarketIds[0]
1489
1485
  else:
1490
- newMarkets.append(market)
1486
+ market['alias'] = None
1487
+ newMarkets.append(market)
1491
1488
  return newMarkets
1492
1489
 
1493
- def market(self, symbol: str) -> MarketInterface:
1494
- finalSymbol = self.safe_string(self.options['aliasCbMarketIds'], symbol, symbol)
1495
- return super(coinbase, self).market(finalSymbol)
1496
-
1497
- def safe_market(self, marketId: Str = None, market: Market = None, delimiter: Str = None, marketType: Str = None) -> MarketInterface:
1498
- if marketId in self.options['aliasCbMarketIds']:
1499
- return self.market(marketId)
1500
- return super(coinbase, self).safe_market(marketId, market, delimiter, marketType)
1501
-
1502
1490
  def parse_spot_market(self, market, feeTier) -> MarketInterface:
1503
1491
  #
1504
1492
  # {
@@ -758,6 +758,7 @@ class coinex(Exchange, ImplicitAPI):
758
758
  },
759
759
  },
760
760
  'networks': {},
761
+ 'type': 'crypto',
761
762
  'info': coin,
762
763
  }
763
764
  for j in range(0, len(chains)):
@@ -489,6 +489,7 @@ class coinlist(Exchange, ImplicitAPI):
489
489
  'withdraw': {'min': minWithdrawal, 'max': None},
490
490
  },
491
491
  'networks': {},
492
+ 'type': 'crypto',
492
493
  }
493
494
  return result
494
495
 
@@ -330,6 +330,7 @@ class coinone(Exchange, ImplicitAPI):
330
330
  },
331
331
  },
332
332
  'networks': {},
333
+ 'type': 'crypto',
333
334
  }
334
335
  return result
335
336
 
@@ -357,6 +357,8 @@ class delta(Exchange, ImplicitAPI):
357
357
  base = self.safe_string(optionParts, 1)
358
358
  expiry = self.safe_string(optionParts, 3)
359
359
  optionType = self.safe_string(optionParts, 0)
360
+ if expiry is not None:
361
+ expiry = expiry[4:] + expiry[2:4] + expiry[0:2]
360
362
  settle = quote
361
363
  strike = self.safe_string(optionParts, 2)
362
364
  datetime = self.convert_expire_date(expiry)
@@ -567,6 +569,7 @@ class delta(Exchange, ImplicitAPI):
567
569
  },
568
570
  },
569
571
  'networks': {},
572
+ 'type': 'crypto',
570
573
  }
571
574
  return result
572
575
 
@@ -655,6 +655,7 @@ class deribit(Exchange, ImplicitAPI):
655
655
  'active': None,
656
656
  'deposit': None,
657
657
  'withdraw': None,
658
+ 'type': 'crypto',
658
659
  'fee': self.safe_number(currency, 'withdrawal_fee'),
659
660
  'precision': self.parse_number(self.parse_precision(self.safe_string(currency, 'fee_precision'))),
660
661
  'limits': {
@@ -493,6 +493,7 @@ class hollaex(Exchange, ImplicitAPI):
493
493
  },
494
494
  },
495
495
  'networks': {},
496
+ 'type': 'crypto',
496
497
  }
497
498
  return result
498
499
 
ccxt/async_support/htx.py CHANGED
@@ -963,6 +963,7 @@ class htx(Exchange, ImplicitAPI):
963
963
  },
964
964
  'precisionMode': TICK_SIZE,
965
965
  'options': {
966
+ 'include_OS_certificates': False, # temporarily leave self, remove in future
966
967
  'fetchMarkets': {
967
968
  'types': {
968
969
  'spot': True,
@@ -2173,14 +2174,14 @@ class htx(Exchange, ImplicitAPI):
2173
2174
  ask = None
2174
2175
  askVolume = None
2175
2176
  if 'bid' in ticker:
2176
- if isinstance(ticker['bid'], list):
2177
+ if ticker['bid'] is not None and isinstance(ticker['bid'], list):
2177
2178
  bid = self.safe_string(ticker['bid'], 0)
2178
2179
  bidVolume = self.safe_string(ticker['bid'], 1)
2179
2180
  else:
2180
2181
  bid = self.safe_string(ticker, 'bid')
2181
2182
  bidVolume = self.safe_string(ticker, 'bidSize')
2182
2183
  if 'ask' in ticker:
2183
- if isinstance(ticker['ask'], list):
2184
+ if ticker['ask'] is not None and isinstance(ticker['ask'], list):
2184
2185
  ask = self.safe_string(ticker['ask'], 0)
2185
2186
  askVolume = self.safe_string(ticker['ask'], 1)
2186
2187
  else:
@@ -3271,7 +3272,7 @@ class htx(Exchange, ImplicitAPI):
3271
3272
  # "withdrawQuotaPerYear": null,
3272
3273
  # "withdrawQuotaTotal": null,
3273
3274
  # "withdrawFeeType": "fixed",
3274
- # "transactFeeWithdraw": "11.1653",
3275
+ # "transactFeeWithdraw": "11.1654",
3275
3276
  # "addrWithTag": False,
3276
3277
  # "addrDepositTag": False
3277
3278
  # }
@@ -3294,6 +3295,8 @@ class htx(Exchange, ImplicitAPI):
3294
3295
  chains = self.safe_value(entry, 'chains', [])
3295
3296
  networks: dict = {}
3296
3297
  instStatus = self.safe_string(entry, 'instStatus')
3298
+ assetType = self.safe_string(entry, 'assetType')
3299
+ type = assetType == 'crypto' if '1' else 'fiat'
3297
3300
  currencyActive = instStatus == 'normal'
3298
3301
  minPrecision = None
3299
3302
  minDeposit = None
@@ -3351,6 +3354,7 @@ class htx(Exchange, ImplicitAPI):
3351
3354
  'withdraw': withdraw,
3352
3355
  'fee': None,
3353
3356
  'name': None,
3357
+ 'type': type,
3354
3358
  'limits': {
3355
3359
  'amount': {
3356
3360
  'min': None,
@@ -6942,7 +6946,7 @@ class htx(Exchange, ImplicitAPI):
6942
6946
  if method != 'POST':
6943
6947
  request = self.extend(request, query)
6944
6948
  sortedRequest = self.keysort(request)
6945
- auth = self.urlencode(sortedRequest)
6949
+ auth = self.urlencode(sortedRequest, True) # True is a go only requirment
6946
6950
  # unfortunately, PHP demands double quotes for the escaped newline symbol
6947
6951
  payload = "\n".join([method, self.hostname, url, auth]) # eslint-disable-line quotes
6948
6952
  signature = self.hmac(self.encode(payload), self.encode(self.secret), hashlib.sha256, 'base64')
@@ -7008,7 +7012,7 @@ class htx(Exchange, ImplicitAPI):
7008
7012
  if method != 'POST':
7009
7013
  sortedQuery = self.keysort(query)
7010
7014
  request = self.extend(request, sortedQuery)
7011
- auth = self.urlencode(request).replace('%2c', '%2C') # in c# it manually needs to be uppercased
7015
+ auth = self.urlencode(request, True).replace('%2c', '%2C') # in c# it manually needs to be uppercased
7012
7016
  # unfortunately, PHP demands double quotes for the escaped newline symbol
7013
7017
  payload = "\n".join([method, hostname, url, auth]) # eslint-disable-line quotes
7014
7018
  signature = self.hmac(self.encode(payload), self.encode(self.secret), hashlib.sha256, 'base64')
@@ -1110,6 +1110,7 @@ class huobijp(Exchange, ImplicitAPI):
1110
1110
  'withdraw': withdrawEnabled,
1111
1111
  'fee': None, # todo need to fetch from fee endpoint
1112
1112
  'precision': precision,
1113
+ 'networks': None,
1113
1114
  'limits': {
1114
1115
  'amount': {
1115
1116
  'min': precision,
@@ -380,6 +380,7 @@ class hyperliquid(Exchange, ImplicitAPI):
380
380
  'withdraw': None,
381
381
  'networks': None,
382
382
  'fee': None,
383
+ 'type': 'crypto',
383
384
  'limits': {
384
385
  'amount': {
385
386
  'min': None,
@@ -2178,6 +2179,10 @@ class hyperliquid(Exchange, ImplicitAPI):
2178
2179
  return self.parse_order(data, market)
2179
2180
 
2180
2181
  def parse_order(self, order: dict, market: Market = None) -> Order:
2182
+ #
2183
+ # createOrdersWs error
2184
+ #
2185
+ # {error: 'Insufficient margin to place order. asset=159'}
2181
2186
  #
2182
2187
  # fetchOpenOrders
2183
2188
  #
@@ -2269,6 +2274,12 @@ class hyperliquid(Exchange, ImplicitAPI):
2269
2274
  # "triggerPx": "0.6"
2270
2275
  # }
2271
2276
  #
2277
+ error = self.safe_string(order, 'error')
2278
+ if error is not None:
2279
+ return self.safe_order({
2280
+ 'info': order,
2281
+ 'status': 'rejected',
2282
+ })
2272
2283
  entry = self.safe_dict_n(order, ['order', 'resting', 'filled'])
2273
2284
  if entry is None:
2274
2285
  entry = order
@@ -3444,9 +3455,12 @@ class hyperliquid(Exchange, ImplicitAPI):
3444
3455
  # {"status":"ok","response":{"type":"order","data":{"statuses":[{"error":"Insufficient margin to place order. asset=84"}]}}}
3445
3456
  #
3446
3457
  status = self.safe_string(response, 'status', '')
3458
+ error = self.safe_string(response, 'error')
3447
3459
  message = None
3448
3460
  if status == 'err':
3449
3461
  message = self.safe_string(response, 'response')
3462
+ elif error is not None:
3463
+ message = error
3450
3464
  else:
3451
3465
  responsePayload = self.safe_dict(response, 'response', {})
3452
3466
  data = self.safe_dict(responsePayload, 'data', {})
@@ -864,12 +864,14 @@ class kraken(Exchange, ImplicitAPI):
864
864
  precision = self.parse_number(self.parse_precision(self.safe_string(currency, 'decimals')))
865
865
  # assumes all currencies are active except those listed above
866
866
  active = self.safe_string(currency, 'status') == 'enabled'
867
+ isFiat = code.find('.HOLD') >= 0
867
868
  result[code] = {
868
869
  'id': id,
869
870
  'code': code,
870
871
  'info': currency,
871
872
  'name': self.safe_string(currency, 'altname'),
872
873
  'active': active,
874
+ 'type': 'fiat' if isFiat else 'crypto',
873
875
  'deposit': None,
874
876
  'withdraw': None,
875
877
  'fee': None,
ccxt/async_support/okx.py CHANGED
@@ -1648,7 +1648,6 @@ class okx(Exchange, ImplicitAPI):
1648
1648
  ymd = self.yymmdd(expiry)
1649
1649
  symbol = symbol + '-' + ymd + '-' + strikePrice + '-' + optionType
1650
1650
  optionType = 'put' if (optionType == 'P') else 'call'
1651
- tickSize = self.safe_string(market, 'tickSz')
1652
1651
  fees = self.safe_dict_2(self.fees, type, 'trading', {})
1653
1652
  maxLeverage = self.safe_string(market, 'lever', '1')
1654
1653
  maxLeverage = Precise.string_max(maxLeverage, '1')
@@ -1680,7 +1679,7 @@ class okx(Exchange, ImplicitAPI):
1680
1679
  'created': self.safe_integer(market, 'listTime'),
1681
1680
  'precision': {
1682
1681
  'amount': self.safe_number(market, 'lotSz'),
1683
- 'price': self.parse_number(tickSize),
1682
+ 'price': self.safe_number(market, 'tickSz'),
1684
1683
  },
1685
1684
  'limits': {
1686
1685
  'leverage': {
@@ -4832,7 +4831,7 @@ class okx(Exchange, ImplicitAPI):
4832
4831
  :returns dict: an `address structure <https://docs.ccxt.com/#/?id=address-structure>`
4833
4832
  """
4834
4833
  await self.load_markets()
4835
- rawNetwork = self.safe_string_upper(params, 'network')
4834
+ rawNetwork = self.safe_string(params, 'network') # some networks are like "Dora Vota Mainnet"
4836
4835
  params = self.omit(params, 'network')
4837
4836
  code = self.safe_currency_code(code)
4838
4837
  network = self.network_id_to_code(rawNetwork, code)
@@ -84,7 +84,7 @@ class oxfun(Exchange, ImplicitAPI):
84
84
  'fetchDepositWithdrawFee': False,
85
85
  'fetchDepositWithdrawFees': False,
86
86
  'fetchFundingHistory': True,
87
- 'fetchFundingRate': 'emulated',
87
+ 'fetchFundingRate': True,
88
88
  'fetchFundingRateHistory': True,
89
89
  'fetchFundingRates': True,
90
90
  'fetchIndexOHLCV': False,
@@ -1104,6 +1104,26 @@ class oxfun(Exchange, ImplicitAPI):
1104
1104
  data = self.safe_list(response, 'data', [])
1105
1105
  return self.parse_funding_rates(data, symbols)
1106
1106
 
1107
+ async def fetch_funding_rate(self, symbol: str, params={}) -> FundingRate:
1108
+ """
1109
+ fetch the current funding rates for a symbol
1110
+
1111
+ https://docs.ox.fun/?json#get-v3-funding-estimates
1112
+
1113
+ :param str symbol: unified market symbols
1114
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1115
+ :returns Order[]: an array of `funding rate structures <https://docs.ccxt.com/#/?id=funding-rate-structure>`
1116
+ """
1117
+ await self.load_markets()
1118
+ request: dict = {
1119
+ 'marketCode': self.market_id(symbol),
1120
+ }
1121
+ response = await self.publicGetV3FundingEstimates(self.extend(request, params))
1122
+ #
1123
+ data = self.safe_list(response, 'data', [])
1124
+ first = self.safe_dict(data, 0, {})
1125
+ return self.parse_funding_rate(first, self.market(symbol))
1126
+
1107
1127
  def parse_funding_rate(self, fundingRate, market: Market = None) -> FundingRate:
1108
1128
  #
1109
1129
  # {
@@ -1204,6 +1204,7 @@ class poloniex(Exchange, ImplicitAPI):
1204
1204
  'withdraw': withdrawEnabled,
1205
1205
  'fee': self.parse_number(feeString),
1206
1206
  'precision': None,
1207
+ 'type': 'crypto',
1207
1208
  'limits': {
1208
1209
  'amount': {
1209
1210
  'min': None,
@@ -1526,7 +1526,7 @@ class timex(Exchange, ImplicitAPI):
1526
1526
  'cost': feeCost,
1527
1527
  'currency': feeCurrency,
1528
1528
  }
1529
- return {
1529
+ return self.safe_trade({
1530
1530
  'info': trade,
1531
1531
  'id': id,
1532
1532
  'timestamp': timestamp,
@@ -1540,7 +1540,7 @@ class timex(Exchange, ImplicitAPI):
1540
1540
  'cost': cost,
1541
1541
  'takerOrMaker': takerOrMaker,
1542
1542
  'fee': fee,
1543
- }
1543
+ })
1544
1544
 
1545
1545
  def parse_ohlcv(self, ohlcv, market: Market = None) -> list:
1546
1546
  #