ccxt 4.2.78__py2.py3-none-any.whl → 4.2.80__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 (58) hide show
  1. ccxt/__init__.py +1 -1
  2. ccxt/abstract/bingx.py +1 -0
  3. ccxt/abstract/gate.py +1 -0
  4. ccxt/abstract/gateio.py +1 -0
  5. ccxt/abstract/upbit.py +1 -0
  6. ccxt/async_support/__init__.py +1 -1
  7. ccxt/async_support/base/exchange.py +10 -1
  8. ccxt/async_support/base/ws/functions.py +1 -1
  9. ccxt/async_support/binance.py +3 -3
  10. ccxt/async_support/bingx.py +37 -5
  11. ccxt/async_support/bitstamp.py +20 -26
  12. ccxt/async_support/bybit.py +92 -0
  13. ccxt/async_support/coinbaseinternational.py +2 -2
  14. ccxt/async_support/deribit.py +152 -1
  15. ccxt/async_support/gate.py +11 -4
  16. ccxt/async_support/hyperliquid.py +42 -9
  17. ccxt/async_support/mexc.py +2 -2
  18. ccxt/async_support/upbit.py +2 -0
  19. ccxt/base/exchange.py +38 -9
  20. ccxt/base/types.py +23 -0
  21. ccxt/binance.py +3 -3
  22. ccxt/bingx.py +37 -5
  23. ccxt/bitstamp.py +20 -26
  24. ccxt/bybit.py +92 -0
  25. ccxt/coinbaseinternational.py +2 -2
  26. ccxt/deribit.py +152 -1
  27. ccxt/gate.py +11 -4
  28. ccxt/hyperliquid.py +42 -9
  29. ccxt/mexc.py +2 -2
  30. ccxt/pro/__init__.py +1 -1
  31. ccxt/pro/alpaca.py +1 -1
  32. ccxt/pro/binance.py +5 -5
  33. ccxt/pro/bitfinex2.py +1 -1
  34. ccxt/pro/bitget.py +1 -1
  35. ccxt/pro/bitmart.py +1 -1
  36. ccxt/pro/bitmex.py +1 -1
  37. ccxt/pro/bitopro.py +2 -1
  38. ccxt/pro/blockchaincom.py +1 -1
  39. ccxt/pro/bybit.py +14 -1
  40. ccxt/pro/cex.py +9 -5
  41. ccxt/pro/cryptocom.py +1 -1
  42. ccxt/pro/gemini.py +4 -3
  43. ccxt/pro/hitbtc.py +1 -1
  44. ccxt/pro/htx.py +1 -1
  45. ccxt/pro/okcoin.py +1 -1
  46. ccxt/pro/onetrading.py +1 -1
  47. ccxt/pro/phemex.py +6 -1
  48. ccxt/pro/woo.py +30 -0
  49. ccxt/test/base/test_ohlcv.py +3 -2
  50. ccxt/test/base/test_shared_methods.py +8 -0
  51. ccxt/test/base/test_ticker.py +7 -1
  52. ccxt/test/test_async.py +26 -25
  53. ccxt/test/test_sync.py +26 -25
  54. ccxt/upbit.py +2 -0
  55. {ccxt-4.2.78.dist-info → ccxt-4.2.80.dist-info}/METADATA +6 -6
  56. {ccxt-4.2.78.dist-info → ccxt-4.2.80.dist-info}/RECORD +58 -58
  57. {ccxt-4.2.78.dist-info → ccxt-4.2.80.dist-info}/WHEEL +0 -0
  58. {ccxt-4.2.78.dist-info → ccxt-4.2.80.dist-info}/top_level.txt +0 -0
ccxt/deribit.py CHANGED
@@ -6,7 +6,7 @@
6
6
  from ccxt.base.exchange import Exchange
7
7
  from ccxt.abstract.deribit import ImplicitAPI
8
8
  import hashlib
9
- from ccxt.base.types import Account, Balances, Currency, Greeks, Int, Market, MarketInterface, Num, Order, OrderBook, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, Transaction, TransferEntry
9
+ from ccxt.base.types import Account, Balances, Currency, Greeks, Int, Market, MarketInterface, Num, Option, OptionChain, Order, OrderBook, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, Transaction, TransferEntry
10
10
  from typing import List
11
11
  from ccxt.base.errors import ExchangeError
12
12
  from ccxt.base.errors import PermissionDenied
@@ -83,6 +83,8 @@ class deribit(Exchange, ImplicitAPI):
83
83
  'fetchMyTrades': True,
84
84
  'fetchOHLCV': True,
85
85
  'fetchOpenOrders': True,
86
+ 'fetchOption': True,
87
+ 'fetchOptionChain': True,
86
88
  'fetchOrder': True,
87
89
  'fetchOrderBook': True,
88
90
  'fetchOrders': False,
@@ -3270,6 +3272,155 @@ class deribit(Exchange, ImplicitAPI):
3270
3272
  'info': greeks,
3271
3273
  }
3272
3274
 
3275
+ def fetch_option(self, symbol: str, params={}) -> Option:
3276
+ """
3277
+ fetches option data that is commonly found in an option chain
3278
+ :see: https://docs.deribit.com/#public-get_book_summary_by_instrument
3279
+ :param str symbol: unified market symbol
3280
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3281
+ :returns dict: an `option chain structure <https://docs.ccxt.com/#/?id=option-chain-structure>`
3282
+ """
3283
+ self.load_markets()
3284
+ market = self.market(symbol)
3285
+ request = {
3286
+ 'instrument_name': market['id'],
3287
+ }
3288
+ response = self.publicGetGetBookSummaryByInstrument(self.extend(request, params))
3289
+ #
3290
+ # {
3291
+ # "jsonrpc": "2.0",
3292
+ # "result": [
3293
+ # {
3294
+ # "mid_price": 0.04025,
3295
+ # "volume_usd": 11045.12,
3296
+ # "quote_currency": "BTC",
3297
+ # "estimated_delivery_price": 65444.72,
3298
+ # "creation_timestamp": 1711100949273,
3299
+ # "base_currency": "BTC",
3300
+ # "underlying_index": "BTC-27DEC24",
3301
+ # "underlying_price": 73742.14,
3302
+ # "volume": 4.0,
3303
+ # "interest_rate": 0.0,
3304
+ # "price_change": -6.9767,
3305
+ # "open_interest": 274.2,
3306
+ # "ask_price": 0.042,
3307
+ # "bid_price": 0.0385,
3308
+ # "instrument_name": "BTC-27DEC24-240000-C",
3309
+ # "mark_price": 0.04007735,
3310
+ # "last": 0.04,
3311
+ # "low": 0.04,
3312
+ # "high": 0.043
3313
+ # }
3314
+ # ],
3315
+ # "usIn": 1711100949273223,
3316
+ # "usOut": 1711100949273580,
3317
+ # "usDiff": 357,
3318
+ # "testnet": False
3319
+ # }
3320
+ #
3321
+ result = self.safe_list(response, 'result', [])
3322
+ chain = self.safe_dict(result, 0, {})
3323
+ return self.parse_option(chain, None, market)
3324
+
3325
+ def fetch_option_chain(self, code: str, params={}) -> OptionChain:
3326
+ """
3327
+ fetches data for an underlying asset that is commonly found in an option chain
3328
+ :see: https://docs.deribit.com/#public-get_book_summary_by_currency
3329
+ :param str currency: base currency to fetch an option chain for
3330
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3331
+ :returns dict: a list of `option chain structures <https://docs.ccxt.com/#/?id=option-chain-structure>`
3332
+ """
3333
+ self.load_markets()
3334
+ currency = self.currency(code)
3335
+ request = {
3336
+ 'currency': currency['id'],
3337
+ 'kind': 'option',
3338
+ }
3339
+ response = self.publicGetGetBookSummaryByCurrency(self.extend(request, params))
3340
+ #
3341
+ # {
3342
+ # "jsonrpc": "2.0",
3343
+ # "result": [
3344
+ # {
3345
+ # "mid_price": 0.4075,
3346
+ # "volume_usd": 2836.83,
3347
+ # "quote_currency": "BTC",
3348
+ # "estimated_delivery_price": 65479.26,
3349
+ # "creation_timestamp": 1711101594477,
3350
+ # "base_currency": "BTC",
3351
+ # "underlying_index": "BTC-28JUN24",
3352
+ # "underlying_price": 68827.27,
3353
+ # "volume": 0.1,
3354
+ # "interest_rate": 0.0,
3355
+ # "price_change": 0.0,
3356
+ # "open_interest": 364.1,
3357
+ # "ask_price": 0.411,
3358
+ # "bid_price": 0.404,
3359
+ # "instrument_name": "BTC-28JUN24-42000-C",
3360
+ # "mark_price": 0.40752052,
3361
+ # "last": 0.423,
3362
+ # "low": 0.423,
3363
+ # "high": 0.423
3364
+ # }
3365
+ # ],
3366
+ # "usIn": 1711101594456388,
3367
+ # "usOut": 1711101594484065,
3368
+ # "usDiff": 27677,
3369
+ # "testnet": False
3370
+ # }
3371
+ #
3372
+ result = self.safe_list(response, 'result', [])
3373
+ return self.parse_option_chain(result, 'base_currency', 'instrument_name')
3374
+
3375
+ def parse_option(self, chain, currency: Currency = None, market: Market = None):
3376
+ #
3377
+ # {
3378
+ # "mid_price": 0.04025,
3379
+ # "volume_usd": 11045.12,
3380
+ # "quote_currency": "BTC",
3381
+ # "estimated_delivery_price": 65444.72,
3382
+ # "creation_timestamp": 1711100949273,
3383
+ # "base_currency": "BTC",
3384
+ # "underlying_index": "BTC-27DEC24",
3385
+ # "underlying_price": 73742.14,
3386
+ # "volume": 4.0,
3387
+ # "interest_rate": 0.0,
3388
+ # "price_change": -6.9767,
3389
+ # "open_interest": 274.2,
3390
+ # "ask_price": 0.042,
3391
+ # "bid_price": 0.0385,
3392
+ # "instrument_name": "BTC-27DEC24-240000-C",
3393
+ # "mark_price": 0.04007735,
3394
+ # "last": 0.04,
3395
+ # "low": 0.04,
3396
+ # "high": 0.043
3397
+ # }
3398
+ #
3399
+ marketId = self.safe_string(chain, 'instrument_name')
3400
+ market = self.safe_market(marketId, market)
3401
+ currencyId = self.safe_string(chain, 'base_currency')
3402
+ code = self.safe_currency_code(currencyId, currency)
3403
+ timestamp = self.safe_integer(chain, 'timestamp')
3404
+ return {
3405
+ 'info': chain,
3406
+ 'currency': code['code'],
3407
+ 'symbol': market['symbol'],
3408
+ 'timestamp': timestamp,
3409
+ 'datetime': self.iso8601(timestamp),
3410
+ 'impliedVolatility': None,
3411
+ 'openInterest': self.safe_number(chain, 'open_interest'),
3412
+ 'bidPrice': self.safe_number(chain, 'bid_price'),
3413
+ 'askPrice': self.safe_number(chain, 'ask_price'),
3414
+ 'midPrice': self.safe_number(chain, 'mid_price'),
3415
+ 'markPrice': self.safe_number(chain, 'mark_price'),
3416
+ 'lastPrice': self.safe_number(chain, 'last'),
3417
+ 'underlyingPrice': self.safe_number(chain, 'underlying_price'),
3418
+ 'change': None,
3419
+ 'percentage': self.safe_number(chain, 'price_change'),
3420
+ 'baseVolume': self.safe_number(chain, 'volume'),
3421
+ 'quoteVolume': self.safe_number(chain, 'volume_usd'),
3422
+ }
3423
+
3273
3424
  def nonce(self):
3274
3425
  return self.milliseconds()
3275
3426
 
ccxt/gate.py CHANGED
@@ -328,6 +328,7 @@ class gate(Exchange, ImplicitAPI):
328
328
  'loan_records': 20 / 15,
329
329
  'interest_records': 20 / 15,
330
330
  'estimate_rate': 20 / 15,
331
+ 'currency_discount_tiers': 20 / 15,
331
332
  },
332
333
  'post': {
333
334
  'account_mode': 20 / 15,
@@ -3958,7 +3959,13 @@ class gate(Exchange, ImplicitAPI):
3958
3959
  'account': account,
3959
3960
  }
3960
3961
  if amount is not None:
3961
- request['amount'] = self.amount_to_precision(symbol, amount)
3962
+ if market['spot']:
3963
+ request['amount'] = self.amount_to_precision(symbol, amount)
3964
+ else:
3965
+ if side == 'sell':
3966
+ request['size'] = Precise.string_neg(self.amount_to_precision(symbol, amount))
3967
+ else:
3968
+ request['size'] = self.amount_to_precision(symbol, amount)
3962
3969
  if price is not None:
3963
3970
  request['price'] = self.price_to_precision(symbol, price)
3964
3971
  response = None
@@ -4688,8 +4695,8 @@ class gate(Exchange, ImplicitAPI):
4688
4695
  """
4689
4696
  self.load_markets()
4690
4697
  market = None if (symbol is None) else self.market(symbol)
4691
- stop = self.safe_value(params, 'stop')
4692
- params = self.omit(params, 'stop')
4698
+ stop = self.safe_bool_2(params, 'stop', 'trigger')
4699
+ params = self.omit(params, ['stop', 'trigger'])
4693
4700
  type, query = self.handle_market_type_and_params('cancelAllOrders', market, params)
4694
4701
  request, requestParams = self.multi_order_spot_prepare_request(market, stop, query) if (type == 'spot') else self.prepare_request(market, type, query)
4695
4702
  response = None
@@ -4983,7 +4990,7 @@ class gate(Exchange, ImplicitAPI):
4983
4990
  'unrealizedPnl': self.parse_number(unrealisedPnl),
4984
4991
  'realizedPnl': self.safe_number(position, 'realised_pnl'),
4985
4992
  'contracts': self.parse_number(Precise.string_abs(size)),
4986
- 'contractSize': self.safe_value(market, 'contractSize'),
4993
+ 'contractSize': self.safe_number(market, 'contractSize'),
4987
4994
  # 'realisedPnl': position['realised_pnl'],
4988
4995
  'marginRatio': None,
4989
4996
  'liquidationPrice': self.safe_number(position, 'liq_price'),
ccxt/hyperliquid.py CHANGED
@@ -754,6 +754,8 @@ class hyperliquid(Exchange, ImplicitAPI):
754
754
  """
755
755
  self.load_markets()
756
756
  market = self.market(symbol)
757
+ vaultAddress = self.safe_string(params, 'vaultAddress')
758
+ params = self.omit(params, 'vaultAddress')
757
759
  symbol = market['symbol']
758
760
  order = {
759
761
  'symbol': symbol,
@@ -763,7 +765,10 @@ class hyperliquid(Exchange, ImplicitAPI):
763
765
  'price': price,
764
766
  'params': params,
765
767
  }
766
- response = self.create_orders([order], params)
768
+ globalParams = {}
769
+ if vaultAddress is not None:
770
+ globalParams['vaultAddress'] = vaultAddress
771
+ response = self.create_orders([order], globalParams)
767
772
  first = self.safe_dict(response, 0)
768
773
  return first
769
774
 
@@ -807,7 +812,6 @@ class hyperliquid(Exchange, ImplicitAPI):
807
812
  amount = self.safe_string(rawOrder, 'amount')
808
813
  price = self.safe_string(rawOrder, 'price')
809
814
  orderParams = self.safe_dict(rawOrder, 'params', {})
810
- orderParams = self.extend(params, orderParams)
811
815
  clientOrderId = self.safe_string_2(orderParams, 'clientOrderId', 'client_id')
812
816
  slippage = self.safe_string(orderParams, 'slippage', defaultSlippage)
813
817
  defaultTimeInForce = 'ioc' if (isMarket) else 'gtc'
@@ -847,6 +851,7 @@ class hyperliquid(Exchange, ImplicitAPI):
847
851
  orderType['limit'] = {
848
852
  'tif': timeInForce,
849
853
  }
854
+ orderParams = self.omit(orderParams, ['clientOrderId', 'slippage', 'triggerPrice', 'stopPrice', 'stopLossPrice', 'takeProfitPrice', 'timeInForce', 'client_id'])
850
855
  orderObj = {
851
856
  'a': self.parse_to_int(market['baseId']),
852
857
  'b': isBuy,
@@ -858,8 +863,8 @@ class hyperliquid(Exchange, ImplicitAPI):
858
863
  }
859
864
  if clientOrderId is not None:
860
865
  orderObj['c'] = clientOrderId
861
- orderReq.append(orderObj)
862
- vaultAddress = self.safe_string(params, 'vaultAddress')
866
+ orderReq.append(self.extend(orderObj, orderParams))
867
+ vaultAddress = self.format_vault_address(self.safe_string(params, 'vaultAddress'))
863
868
  orderAction = {
864
869
  'type': 'order',
865
870
  'orders': orderReq,
@@ -875,6 +880,9 @@ class hyperliquid(Exchange, ImplicitAPI):
875
880
  'signature': signature,
876
881
  # 'vaultAddress': vaultAddress,
877
882
  }
883
+ if vaultAddress is not None:
884
+ params = self.omit(params, 'vaultAddress')
885
+ request['vaultAddress'] = vaultAddress
878
886
  response = self.privatePostExchange(self.extend(request, params))
879
887
  #
880
888
  # {
@@ -957,10 +965,13 @@ class hyperliquid(Exchange, ImplicitAPI):
957
965
  'o': self.parse_to_numeric(ids[i]),
958
966
  })
959
967
  cancelAction['cancels'] = cancelReq
960
- vaultAddress = self.safe_string(params, 'vaultAddress')
968
+ vaultAddress = self.format_vault_address(self.safe_string(params, 'vaultAddress'))
961
969
  signature = self.sign_l1_action(cancelAction, nonce, vaultAddress)
962
970
  request['action'] = cancelAction
963
971
  request['signature'] = signature
972
+ if vaultAddress is not None:
973
+ params = self.omit(params, 'vaultAddress')
974
+ request['vaultAddress'] = vaultAddress
964
975
  response = self.privatePostExchange(self.extend(request, params))
965
976
  #
966
977
  # {
@@ -1066,7 +1077,7 @@ class hyperliquid(Exchange, ImplicitAPI):
1066
1077
  'type': 'batchModify',
1067
1078
  'modifies': [modifyReq],
1068
1079
  }
1069
- vaultAddress = self.safe_string(params, 'vaultAddress')
1080
+ vaultAddress = self.format_vault_address(self.safe_string(params, 'vaultAddress'))
1070
1081
  signature = self.sign_l1_action(modifyAction, nonce, vaultAddress)
1071
1082
  request = {
1072
1083
  'action': modifyAction,
@@ -1074,6 +1085,9 @@ class hyperliquid(Exchange, ImplicitAPI):
1074
1085
  'signature': signature,
1075
1086
  # 'vaultAddress': vaultAddress,
1076
1087
  }
1088
+ if vaultAddress is not None:
1089
+ params = self.omit(params, 'vaultAddress')
1090
+ request['vaultAddress'] = vaultAddress
1077
1091
  response = self.privatePostExchange(self.extend(request, params))
1078
1092
  #
1079
1093
  # {
@@ -1643,7 +1657,7 @@ class hyperliquid(Exchange, ImplicitAPI):
1643
1657
  'isolated': isIsolated,
1644
1658
  'hedged': None,
1645
1659
  'side': side,
1646
- 'contracts': self.parse_number(quantity),
1660
+ 'contracts': self.safe_number(entry, 'szi'),
1647
1661
  'contractSize': None,
1648
1662
  'entryPrice': self.safe_number(entry, 'entryPx'),
1649
1663
  'markPrice': None,
@@ -1687,6 +1701,10 @@ class hyperliquid(Exchange, ImplicitAPI):
1687
1701
  'leverage': leverage,
1688
1702
  }
1689
1703
  vaultAddress = self.safe_string(params, 'vaultAddress')
1704
+ if vaultAddress is not None:
1705
+ params = self.omit(params, 'vaultAddress')
1706
+ if vaultAddress.startswith('0x'):
1707
+ vaultAddress = vaultAddress.replace('0x', '')
1690
1708
  signature = self.sign_l1_action(updateAction, nonce, vaultAddress)
1691
1709
  request = {
1692
1710
  'action': updateAction,
@@ -1694,6 +1712,8 @@ class hyperliquid(Exchange, ImplicitAPI):
1694
1712
  'signature': signature,
1695
1713
  # 'vaultAddress': vaultAddress,
1696
1714
  }
1715
+ if vaultAddress is not None:
1716
+ request['vaultAddress'] = vaultAddress
1697
1717
  response = self.privatePostExchange(self.extend(request, params))
1698
1718
  #
1699
1719
  # {
@@ -1729,7 +1749,7 @@ class hyperliquid(Exchange, ImplicitAPI):
1729
1749
  'isCross': isCross,
1730
1750
  'leverage': leverage,
1731
1751
  }
1732
- vaultAddress = self.safe_string(params, 'vaultAddress')
1752
+ vaultAddress = self.format_vault_address(self.safe_string(params, 'vaultAddress'))
1733
1753
  signature = self.sign_l1_action(updateAction, nonce, vaultAddress)
1734
1754
  request = {
1735
1755
  'action': updateAction,
@@ -1737,6 +1757,9 @@ class hyperliquid(Exchange, ImplicitAPI):
1737
1757
  'signature': signature,
1738
1758
  # 'vaultAddress': vaultAddress,
1739
1759
  }
1760
+ if vaultAddress is not None:
1761
+ params = self.omit(params, 'vaultAddress')
1762
+ request['vaultAddress'] = vaultAddress
1740
1763
  response = self.privatePostExchange(self.extend(request, params))
1741
1764
  #
1742
1765
  # {
@@ -1784,7 +1807,7 @@ class hyperliquid(Exchange, ImplicitAPI):
1784
1807
  'isBuy': True,
1785
1808
  'ntli': sz,
1786
1809
  }
1787
- vaultAddress = self.safe_string(params, 'vaultAddress')
1810
+ vaultAddress = self.format_vault_address(self.safe_string(params, 'vaultAddress'))
1788
1811
  signature = self.sign_l1_action(updateAction, nonce, vaultAddress)
1789
1812
  request = {
1790
1813
  'action': updateAction,
@@ -1792,6 +1815,9 @@ class hyperliquid(Exchange, ImplicitAPI):
1792
1815
  'signature': signature,
1793
1816
  # 'vaultAddress': vaultAddress,
1794
1817
  }
1818
+ if vaultAddress is not None:
1819
+ params = self.omit(params, 'vaultAddress')
1820
+ request['vaultAddress'] = vaultAddress
1795
1821
  response = self.privatePostExchange(self.extend(request, params))
1796
1822
  #
1797
1823
  # {
@@ -1882,6 +1908,13 @@ class hyperliquid(Exchange, ImplicitAPI):
1882
1908
  response = self.privatePostExchange(self.extend(request, params))
1883
1909
  return response
1884
1910
 
1911
+ def format_vault_address(self, address: Str = None):
1912
+ if address is None:
1913
+ return None
1914
+ if address.startswith('0x'):
1915
+ return address.replace('0x', '')
1916
+ return address
1917
+
1885
1918
  def handle_public_address(self, methodName: str, params: dict):
1886
1919
  userAux = None
1887
1920
  userAux, params = self.handle_option_and_params(params, methodName, 'user')
ccxt/mexc.py CHANGED
@@ -899,8 +899,8 @@ class mexc(Exchange, ImplicitAPI):
899
899
  '30032': InvalidOrder, # Cannot exceed the maximum position
900
900
  '30041': InvalidOrder, # current order type can not place order
901
901
  '60005': ExchangeError, # your account is abnormal
902
- '700001': AuthenticationError, # API-key format invalid
903
- '700002': AuthenticationError, # Signature for self request is not valid
902
+ '700001': AuthenticationError, # {"code":700002,"msg":"Signature for self request is not valid."} # same message for expired API keys
903
+ '700002': AuthenticationError, # Signature for self request is not valid # or the API secret is incorrect
904
904
  '700004': BadRequest, # Param 'origClientOrderId' or 'orderId' must be sent, but both were empty/null
905
905
  '700005': InvalidNonce, # recvWindow must less than 60000
906
906
  '700006': BadRequest, # IP non white list
ccxt/pro/__init__.py CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  # ----------------------------------------------------------------------------
6
6
 
7
- __version__ = '4.2.78'
7
+ __version__ = '4.2.80'
8
8
 
9
9
  # ----------------------------------------------------------------------------
10
10
 
ccxt/pro/alpaca.py CHANGED
@@ -562,7 +562,7 @@ class alpaca(ccxt.async_support.alpaca):
562
562
  },
563
563
  }
564
564
  self.watch(url, messageHash, request, messageHash, future)
565
- return future
565
+ return await future
566
566
 
567
567
  def handle_error_message(self, client: Client, message):
568
568
  #
ccxt/pro/binance.py CHANGED
@@ -89,7 +89,7 @@ class binance(ccxt.async_support.binance):
89
89
  'future': 200,
90
90
  'delivery': 200,
91
91
  },
92
- 'streamBySubscriptionsHash': {},
92
+ 'streamBySubscriptionsHash': self.create_safe_dictionary(),
93
93
  'streamIndex': -1,
94
94
  # get updates every 1000ms or 100ms
95
95
  # or every 0ms in real-time for futures
@@ -97,7 +97,7 @@ class binance(ccxt.async_support.binance):
97
97
  'tradesLimit': 1000,
98
98
  'ordersLimit': 1000,
99
99
  'OHLCVLimit': 1000,
100
- 'requestId': {},
100
+ 'requestId': self.create_safe_dictionary(),
101
101
  'watchOrderBookLimit': 1000, # default limit
102
102
  'watchTrades': {
103
103
  'name': 'trade', # 'trade' or 'aggTrade'
@@ -131,14 +131,14 @@ class binance(ccxt.async_support.binance):
131
131
  })
132
132
 
133
133
  def request_id(self, url):
134
- options = self.safe_value(self.options, 'requestId', {})
134
+ options = self.safe_dict(self.options, 'requestId', self.create_safe_dictionary())
135
135
  previousValue = self.safe_integer(options, url, 0)
136
136
  newValue = self.sum(previousValue, 1)
137
137
  self.options['requestId'][url] = newValue
138
138
  return newValue
139
139
 
140
140
  def stream(self, type, subscriptionHash, numSubscriptions=1):
141
- streamBySubscriptionsHash = self.safe_value(self.options, 'streamBySubscriptionsHash', {})
141
+ streamBySubscriptionsHash = self.safe_dict(self.options, 'streamBySubscriptionsHash', self.create_safe_dictionary())
142
142
  stream = self.safe_string(streamBySubscriptionsHash, subscriptionHash)
143
143
  if stream is None:
144
144
  streamIndex = self.safe_integer(self.options, 'streamIndex', -1)
@@ -151,7 +151,7 @@ class binance(ccxt.async_support.binance):
151
151
  self.options['streamBySubscriptionsHash'][subscriptionHash] = stream
152
152
  subscriptionsByStreams = self.safe_value(self.options, 'numSubscriptionsByStream')
153
153
  if subscriptionsByStreams is None:
154
- self.options['numSubscriptionsByStream'] = {}
154
+ self.options['numSubscriptionsByStream'] = self.create_safe_dictionary()
155
155
  subscriptionsByStream = self.safe_integer(self.options['numSubscriptionsByStream'], stream, 0)
156
156
  newNumSubscriptions = subscriptionsByStream + numSubscriptions
157
157
  subscriptionLimitByStream = self.safe_integer(self.options['subscriptionLimitByStream'], type, 200)
ccxt/pro/bitfinex2.py CHANGED
@@ -812,7 +812,7 @@ class bitfinex2(ccxt.async_support.bitfinex2):
812
812
  }
813
813
  message = self.extend(request, params)
814
814
  self.watch(url, messageHash, message, messageHash)
815
- return future
815
+ return await future
816
816
 
817
817
  def handle_authentication_message(self, client: Client, message):
818
818
  messageHash = 'authenticated'
ccxt/pro/bitget.py CHANGED
@@ -1523,7 +1523,7 @@ class bitget(ccxt.async_support.bitget):
1523
1523
  }
1524
1524
  message = self.extend(request, params)
1525
1525
  self.watch(url, messageHash, message, messageHash)
1526
- return future
1526
+ return await future
1527
1527
 
1528
1528
  async def watch_private(self, messageHash, subscriptionHash, args, params={}):
1529
1529
  await self.authenticate()
ccxt/pro/bitmart.py CHANGED
@@ -1312,7 +1312,7 @@ class bitmart(ccxt.async_support.bitmart):
1312
1312
  }
1313
1313
  message = self.extend(request, params)
1314
1314
  self.watch(url, messageHash, message, messageHash)
1315
- return future
1315
+ return await future
1316
1316
 
1317
1317
  def handle_subscription_status(self, client: Client, message):
1318
1318
  #
ccxt/pro/bitmex.py CHANGED
@@ -599,7 +599,7 @@ class bitmex(ccxt.async_support.bitmex):
599
599
  }
600
600
  message = self.extend(request, params)
601
601
  self.watch(url, messageHash, message, messageHash)
602
- return future
602
+ return await future
603
603
 
604
604
  def handle_authentication_message(self, client: Client, message):
605
605
  authenticated = self.safe_bool(message, 'success', False)
ccxt/pro/bitopro.py CHANGED
@@ -364,7 +364,8 @@ class bitopro(ccxt.async_support.bitopro):
364
364
  },
365
365
  },
366
366
  }
367
- self.options = self.extend(defaultOptions, self.options)
367
+ # self.options = self.extend(defaultOptions, self.options)
368
+ self.extend_exchange_options(defaultOptions)
368
369
  originalHeaders = self.options['ws']['options']['headers']
369
370
  headers = {
370
371
  'X-BITOPRO-API': 'ccxt',
ccxt/pro/blockchaincom.py CHANGED
@@ -735,4 +735,4 @@ class blockchaincom(ccxt.async_support.blockchaincom):
735
735
  'token': self.secret,
736
736
  }
737
737
  return self.watch(url, messageHash, self.extend(request, params), messageHash)
738
- return future
738
+ return await future
ccxt/pro/bybit.py CHANGED
@@ -974,8 +974,21 @@ class bybit(ccxt.async_support.bybit):
974
974
  for i in range(0, len(rawPositions)):
975
975
  rawPosition = rawPositions[i]
976
976
  position = self.parse_position(rawPosition)
977
+ side = self.safe_string(position, 'side')
978
+ # hacky solution to handle closing positions
979
+ # without crashing, we should handle self properly later
977
980
  newPositions.append(position)
978
- cache.append(position)
981
+ if side is None or side == '':
982
+ # closing update, adding both sides to "reset" both sides
983
+ # since we don't know which side is being closed
984
+ position['side'] = 'long'
985
+ cache.append(position)
986
+ position['side'] = 'short'
987
+ cache.append(position)
988
+ position['side'] = None
989
+ else:
990
+ # regular update
991
+ cache.append(position)
979
992
  messageHashes = self.find_message_hashes(client, 'positions::')
980
993
  for i in range(0, len(messageHashes)):
981
994
  messageHash = messageHashes[i]
ccxt/pro/cex.py CHANGED
@@ -157,16 +157,20 @@ class cex(ccxt.async_support.cex):
157
157
  # {
158
158
  # "e": "history",
159
159
  # "data": [
160
- # "sell:1665467367741:3888551:19058.8:14541219",
161
- # "buy:1665467367741:1059339:19071.5:14541218",
160
+ # 'buy:1710255706095:444444:71222.2:14892622'
161
+ # 'sell:1710255658251:42530:71300:14892621'
162
+ # 'buy:1710252424241:87913:72800:14892620'
163
+ # ... timestamp descending
162
164
  # ]
163
165
  # }
164
166
  #
165
- data = self.safe_value(message, 'data', [])
167
+ data = self.safe_list(message, 'data', [])
166
168
  limit = self.safe_integer(self.options, 'tradesLimit', 1000)
167
169
  stored = ArrayCache(limit)
168
- for i in range(0, len(data)):
169
- rawTrade = data[i]
170
+ dataLength = len(data)
171
+ for i in range(0, dataLength):
172
+ index = dataLength - 1 - i
173
+ rawTrade = data[index]
170
174
  parsed = self.parse_ws_old_trade(rawTrade)
171
175
  stored.append(parsed)
172
176
  messageHash = 'trades'
ccxt/pro/cryptocom.py CHANGED
@@ -931,7 +931,7 @@ class cryptocom(ccxt.async_support.cryptocom):
931
931
  }
932
932
  message = self.extend(request, params)
933
933
  self.watch(url, messageHash, message, messageHash)
934
- return future
934
+ return await future
935
935
 
936
936
  def handle_ping(self, client: Client, message):
937
937
  self.spawn(self.pong, client, message)
ccxt/pro/gemini.py CHANGED
@@ -6,7 +6,7 @@
6
6
  import ccxt.async_support
7
7
  from ccxt.async_support.base.ws.cache import ArrayCache, ArrayCacheBySymbolById, ArrayCacheByTimestamp
8
8
  import hashlib
9
- from ccxt.base.types import Int, Order, OrderBook, Str, Tickers, Trade
9
+ from ccxt.base.types import Int, Order, OrderBook, Str, Strings, Tickers, Trade
10
10
  from ccxt.async_support.base.ws.client import Client
11
11
  from typing import List
12
12
  from ccxt.base.errors import ExchangeError
@@ -393,7 +393,7 @@ class gemini(ccxt.async_support.gemini):
393
393
  orderbook = await self.helper_for_watch_multiple_construct('orderbook', symbols, params)
394
394
  return orderbook.limit()
395
395
 
396
- async def watch_bids_asks(self, symbols: List[str], limit: Int = None, params={}) -> Tickers:
396
+ async def watch_bids_asks(self, symbols: Strings = None, params={}) -> Tickers:
397
397
  """
398
398
  watches best bid & ask for symbols
399
399
  :see: https://docs.gemini.com/websocket-api/#multi-market-data
@@ -851,7 +851,8 @@ class gemini(ccxt.async_support.gemini):
851
851
  },
852
852
  },
853
853
  }
854
- self.options = self.extend(defaultOptions, self.options)
854
+ # self.options = self.extend(defaultOptions, self.options)
855
+ self.extend_exchange_options(defaultOptions)
855
856
  originalHeaders = self.options['ws']['options']['headers']
856
857
  headers = {
857
858
  'X-GEMINI-APIKEY': self.apiKey,
ccxt/pro/hitbtc.py CHANGED
@@ -119,7 +119,7 @@ class hitbtc(ccxt.async_support.hitbtc):
119
119
  # }
120
120
  # }
121
121
  #
122
- return future
122
+ return await future
123
123
 
124
124
  async def subscribe_public(self, name: str, messageHashPrefix: str, symbols: Strings = None, params={}):
125
125
  """
ccxt/pro/htx.py CHANGED
@@ -2205,4 +2205,4 @@ class htx(ccxt.async_support.htx):
2205
2205
  'params': params,
2206
2206
  }
2207
2207
  self.watch(url, messageHash, request, messageHash, subscription)
2208
- return future
2208
+ return await future
ccxt/pro/okcoin.py CHANGED
@@ -452,7 +452,7 @@ class okcoin(ccxt.async_support.okcoin):
452
452
  ],
453
453
  }
454
454
  self.spawn(self.watch, url, messageHash, request, messageHash, future)
455
- return future
455
+ return await future
456
456
 
457
457
  async def watch_balance(self, params={}) -> Balances:
458
458
  """
ccxt/pro/onetrading.py CHANGED
@@ -1272,4 +1272,4 @@ class onetrading(ccxt.async_support.onetrading):
1272
1272
  'api_token': self.apiKey,
1273
1273
  }
1274
1274
  self.watch(url, messageHash, self.extend(request, params), messageHash)
1275
- return future
1275
+ return await future