ccxt 4.4.12__py2.py3-none-any.whl → 4.4.14__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 (84) hide show
  1. ccxt/__init__.py +1 -1
  2. ccxt/abstract/binance.py +1 -0
  3. ccxt/abstract/binancecoinm.py +1 -0
  4. ccxt/abstract/binanceus.py +1 -0
  5. ccxt/abstract/binanceusdm.py +1 -0
  6. ccxt/abstract/cryptocom.py +1 -0
  7. ccxt/async_support/__init__.py +1 -1
  8. ccxt/async_support/base/exchange.py +37 -1
  9. ccxt/async_support/bigone.py +2 -0
  10. ccxt/async_support/binance.py +113 -12
  11. ccxt/async_support/bingx.py +69 -3
  12. ccxt/async_support/bitget.py +102 -3
  13. ccxt/async_support/bitmex.py +1 -0
  14. ccxt/async_support/bitrue.py +1 -7
  15. ccxt/async_support/bitvavo.py +1 -3
  16. ccxt/async_support/bybit.py +2 -0
  17. ccxt/async_support/coinbaseinternational.py +2 -0
  18. ccxt/async_support/coinex.py +15 -1
  19. ccxt/async_support/cryptocom.py +1 -0
  20. ccxt/async_support/delta.py +2 -0
  21. ccxt/async_support/deribit.py +2 -0
  22. ccxt/async_support/digifinex.py +15 -1
  23. ccxt/async_support/gate.py +2 -0
  24. ccxt/async_support/htx.py +2 -2
  25. ccxt/async_support/huobijp.py +1 -3
  26. ccxt/async_support/krakenfutures.py +2 -0
  27. ccxt/async_support/kucoin.py +36 -1
  28. ccxt/async_support/kucoinfutures.py +56 -3
  29. ccxt/async_support/mexc.py +52 -8
  30. ccxt/async_support/okx.py +48 -0
  31. ccxt/async_support/oxfun.py +1 -0
  32. ccxt/async_support/paradex.py +1 -0
  33. ccxt/async_support/poloniex.py +1 -0
  34. ccxt/async_support/poloniexfutures.py +35 -11
  35. ccxt/async_support/woo.py +12 -0
  36. ccxt/async_support/woofipro.py +12 -0
  37. ccxt/async_support/xt.py +12 -0
  38. ccxt/base/exchange.py +44 -2
  39. ccxt/base/types.py +2 -0
  40. ccxt/bigone.py +2 -0
  41. ccxt/binance.py +113 -12
  42. ccxt/bingx.py +69 -3
  43. ccxt/bitget.py +102 -3
  44. ccxt/bitmex.py +1 -0
  45. ccxt/bitrue.py +1 -7
  46. ccxt/bitvavo.py +1 -3
  47. ccxt/bybit.py +2 -0
  48. ccxt/coinbaseinternational.py +2 -0
  49. ccxt/coinex.py +15 -1
  50. ccxt/cryptocom.py +1 -0
  51. ccxt/delta.py +2 -0
  52. ccxt/deribit.py +2 -0
  53. ccxt/digifinex.py +15 -1
  54. ccxt/gate.py +2 -0
  55. ccxt/htx.py +2 -2
  56. ccxt/huobijp.py +1 -3
  57. ccxt/krakenfutures.py +2 -0
  58. ccxt/kucoin.py +36 -1
  59. ccxt/kucoinfutures.py +56 -3
  60. ccxt/mexc.py +52 -8
  61. ccxt/okx.py +48 -0
  62. ccxt/oxfun.py +1 -0
  63. ccxt/paradex.py +1 -0
  64. ccxt/poloniex.py +1 -0
  65. ccxt/poloniexfutures.py +35 -11
  66. ccxt/pro/__init__.py +1 -1
  67. ccxt/pro/binance.py +72 -5
  68. ccxt/pro/bitfinex.py +8 -8
  69. ccxt/pro/krakenfutures.py +2 -0
  70. ccxt/pro/okx.py +38 -0
  71. ccxt/pro/phemex.py +2 -0
  72. ccxt/pro/woo.py +69 -0
  73. ccxt/test/tests_async.py +76 -48
  74. ccxt/test/tests_helpers.py +27 -36
  75. ccxt/test/tests_init.py +6 -2
  76. ccxt/test/tests_sync.py +76 -48
  77. ccxt/woo.py +12 -0
  78. ccxt/woofipro.py +12 -0
  79. ccxt/xt.py +12 -0
  80. {ccxt-4.4.12.dist-info → ccxt-4.4.14.dist-info}/METADATA +4 -5
  81. {ccxt-4.4.12.dist-info → ccxt-4.4.14.dist-info}/RECORD +84 -84
  82. {ccxt-4.4.12.dist-info → ccxt-4.4.14.dist-info}/LICENSE.txt +0 -0
  83. {ccxt-4.4.12.dist-info → ccxt-4.4.14.dist-info}/WHEEL +0 -0
  84. {ccxt-4.4.12.dist-info → ccxt-4.4.14.dist-info}/top_level.txt +0 -0
ccxt/mexc.py CHANGED
@@ -89,6 +89,8 @@ class mexc(Exchange, ImplicitAPI):
89
89
  'fetchDepositWithdrawFee': 'emulated',
90
90
  'fetchDepositWithdrawFees': True,
91
91
  'fetchFundingHistory': True,
92
+ 'fetchFundingInterval': True,
93
+ 'fetchFundingIntervals': False,
92
94
  'fetchFundingRate': True,
93
95
  'fetchFundingRateHistory': True,
94
96
  'fetchFundingRates': None,
@@ -2468,6 +2470,7 @@ class mexc(Exchange, ImplicitAPI):
2468
2470
  :param int [since]: the earliest time in ms to fetch orders for
2469
2471
  :param int [limit]: the maximum number of order structures to retrieve
2470
2472
  :param dict [params]: extra parameters specific to the exchange API endpoint
2473
+ :param int [params.until]: the latest time in ms to fetch orders for
2471
2474
  :param str [params.marginMode]: only 'isolated' is supported, for spot-margin trading
2472
2475
  :returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
2473
2476
  """
@@ -2477,6 +2480,8 @@ class mexc(Exchange, ImplicitAPI):
2477
2480
  if symbol is not None:
2478
2481
  market = self.market(symbol)
2479
2482
  request['symbol'] = market['id']
2483
+ until = self.safe_integer(params, 'until')
2484
+ params = self.omit(params, 'until')
2480
2485
  marketType, query = self.handle_market_type_and_params('fetchOrders', market, params)
2481
2486
  if marketType == 'spot':
2482
2487
  if symbol is None:
@@ -2484,6 +2489,8 @@ class mexc(Exchange, ImplicitAPI):
2484
2489
  marginMode, queryInner = self.handle_margin_mode_and_params('fetchOrders', params)
2485
2490
  if since is not None:
2486
2491
  request['startTime'] = since
2492
+ if until is not None:
2493
+ request['endTime'] = until
2487
2494
  if limit is not None:
2488
2495
  request['limit'] = limit
2489
2496
  response = None
@@ -2545,9 +2552,17 @@ class mexc(Exchange, ImplicitAPI):
2545
2552
  else:
2546
2553
  if since is not None:
2547
2554
  request['start_time'] = since
2548
- end = self.safe_integer(params, 'end_time')
2555
+ end = self.safe_integer(params, 'end_time', until)
2549
2556
  if end is None:
2550
2557
  request['end_time'] = self.sum(since, self.options['maxTimeTillEnd'])
2558
+ else:
2559
+ if (end - since) > self.options['maxTimeTillEnd']:
2560
+ raise BadRequest(self.id + ' end is invalid, i.e. exceeds allowed 90 days.')
2561
+ else:
2562
+ request['end_time'] = until
2563
+ elif until is not None:
2564
+ request['start_time'] = self.sum(until, self.options['maxTimeTillEnd'] * -1)
2565
+ request['end_time'] = until
2551
2566
  if limit is not None:
2552
2567
  request['page_size'] = limit
2553
2568
  method = self.safe_string(self.options, 'fetchOrders', 'contractPrivateGetOrderListHistoryOrders')
@@ -3937,9 +3952,12 @@ class mexc(Exchange, ImplicitAPI):
3937
3952
  nextFundingRate = self.safe_number(contract, 'fundingRate')
3938
3953
  nextFundingTimestamp = self.safe_integer(contract, 'nextSettleTime')
3939
3954
  marketId = self.safe_string(contract, 'symbol')
3940
- symbol = self.safe_symbol(marketId, market)
3955
+ symbol = self.safe_symbol(marketId, market, None, 'contract')
3941
3956
  timestamp = self.safe_integer(contract, 'timestamp')
3942
- datetime = self.iso8601(timestamp)
3957
+ interval = self.safe_string(contract, 'collectCycle')
3958
+ intervalString = None
3959
+ if interval is not None:
3960
+ intervalString = interval + 'h'
3943
3961
  return {
3944
3962
  'info': contract,
3945
3963
  'symbol': symbol,
@@ -3948,7 +3966,7 @@ class mexc(Exchange, ImplicitAPI):
3948
3966
  'interestRate': None,
3949
3967
  'estimatedSettlePrice': None,
3950
3968
  'timestamp': timestamp,
3951
- 'datetime': datetime,
3969
+ 'datetime': self.iso8601(timestamp),
3952
3970
  'fundingRate': nextFundingRate,
3953
3971
  'fundingTimestamp': nextFundingTimestamp,
3954
3972
  'fundingDatetime': self.iso8601(nextFundingTimestamp),
@@ -3958,9 +3976,19 @@ class mexc(Exchange, ImplicitAPI):
3958
3976
  'previousFundingRate': None,
3959
3977
  'previousFundingTimestamp': None,
3960
3978
  'previousFundingDatetime': None,
3961
- 'interval': None,
3979
+ 'interval': intervalString,
3962
3980
  }
3963
3981
 
3982
+ def fetch_funding_interval(self, symbol: str, params={}) -> FundingRate:
3983
+ """
3984
+ fetch the current funding rate interval
3985
+ :see: https://mexcdevelop.github.io/apidocs/contract_v1_en/#get-contract-funding-rate
3986
+ :param str symbol: unified market symbol
3987
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3988
+ :returns dict: a `funding rate structure <https://docs.ccxt.com/#/?id=funding-rate-structure>`
3989
+ """
3990
+ return self.fetch_funding_rate(symbol, params)
3991
+
3964
3992
  def fetch_funding_rate(self, symbol: str, params={}) -> FundingRate:
3965
3993
  """
3966
3994
  fetch the current funding rate
@@ -4229,7 +4257,15 @@ class mexc(Exchange, ImplicitAPI):
4229
4257
  networkCode = self.safe_string(params, 'network')
4230
4258
  networkId = None
4231
4259
  if networkCode is not None:
4232
- networkId = self.network_code_to_id(networkCode, code)
4260
+ # createDepositAddress and fetchDepositAddress use a different network-id compared to withdraw
4261
+ networkUnified = self.network_id_to_code(networkCode, code)
4262
+ networks = self.safe_dict(currency, 'networks', {})
4263
+ if networkUnified in networks:
4264
+ network = self.safe_dict(networks, networkUnified, {})
4265
+ networkInfo = self.safe_value(network, 'info', {})
4266
+ networkId = self.safe_string(networkInfo, 'network')
4267
+ else:
4268
+ networkId = self.network_code_to_id(networkCode, code)
4233
4269
  if networkId is not None:
4234
4270
  request['network'] = networkId
4235
4271
  params = self.omit(params, 'network')
@@ -4265,7 +4301,16 @@ class mexc(Exchange, ImplicitAPI):
4265
4301
  networkCode = self.safe_string(params, 'network')
4266
4302
  if networkCode is None:
4267
4303
  raise ArgumentsRequired(self.id + ' createDepositAddress requires a `network` parameter')
4268
- networkId = self.network_code_to_id(networkCode, code)
4304
+ # createDepositAddress and fetchDepositAddress use a different network-id compared to withdraw
4305
+ networkId = None
4306
+ networkUnified = self.network_id_to_code(networkCode, code)
4307
+ networks = self.safe_dict(currency, 'networks', {})
4308
+ if networkUnified in networks:
4309
+ network = self.safe_dict(networks, networkUnified, {})
4310
+ networkInfo = self.safe_value(network, 'info', {})
4311
+ networkId = self.safe_string(networkInfo, 'network')
4312
+ else:
4313
+ networkId = self.network_code_to_id(networkCode, code)
4269
4314
  if networkId is not None:
4270
4315
  request['network'] = networkId
4271
4316
  params = self.omit(params, 'network')
@@ -4288,7 +4333,6 @@ class mexc(Exchange, ImplicitAPI):
4288
4333
  :returns dict: an `address structure <https://docs.ccxt.com/#/?id=address-structure>`
4289
4334
  """
4290
4335
  network = self.safe_string(params, 'network')
4291
- params = self.omit(params, ['network'])
4292
4336
  addressStructures = self.fetch_deposit_addresses_by_network(code, params)
4293
4337
  result = None
4294
4338
  if network is not None:
ccxt/okx.py CHANGED
@@ -104,6 +104,8 @@ class okx(Exchange, ImplicitAPI):
104
104
  'fetchDepositWithdrawFee': 'emulated',
105
105
  'fetchDepositWithdrawFees': True,
106
106
  'fetchFundingHistory': True,
107
+ 'fetchFundingInterval': True,
108
+ 'fetchFundingIntervals': False,
107
109
  'fetchFundingRate': True,
108
110
  'fetchFundingRateHistory': True,
109
111
  'fetchFundingRates': False,
@@ -120,6 +122,7 @@ class okx(Exchange, ImplicitAPI):
120
122
  'fetchMarketLeverageTiers': True,
121
123
  'fetchMarkets': True,
122
124
  'fetchMarkOHLCV': True,
125
+ 'fetchMarkPrices': True,
123
126
  'fetchMySettlementHistory': False,
124
127
  'fetchMyTrades': True,
125
128
  'fetchOHLCV': True,
@@ -1784,6 +1787,13 @@ class okx(Exchange, ImplicitAPI):
1784
1787
  return self.parse_order_book(first, symbol, timestamp)
1785
1788
 
1786
1789
  def parse_ticker(self, ticker: dict, market: Market = None) -> Ticker:
1790
+ #
1791
+ # {
1792
+ # "instType":"SWAP",
1793
+ # "instId":"BTC-USDT-SWAP",
1794
+ # "markPx":"200",
1795
+ # "ts":"1597026383085"
1796
+ # }
1787
1797
  #
1788
1798
  # {
1789
1799
  # "instType": "SPOT",
@@ -1835,6 +1845,7 @@ class okx(Exchange, ImplicitAPI):
1835
1845
  'average': None,
1836
1846
  'baseVolume': baseVolume,
1837
1847
  'quoteVolume': quoteVolume,
1848
+ 'markPrice': self.safe_string(ticker, 'markPx'),
1838
1849
  'info': ticker,
1839
1850
  }, market)
1840
1851
 
@@ -1935,6 +1946,33 @@ class okx(Exchange, ImplicitAPI):
1935
1946
  tickers = self.safe_list(response, 'data', [])
1936
1947
  return self.parse_tickers(tickers, symbols)
1937
1948
 
1949
+ def fetch_mark_prices(self, symbols: Strings = None, params={}) -> Tickers:
1950
+ """
1951
+ fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market
1952
+ :see: https://www.okx.com/docs-v5/en/#public-data-rest-api-get-mark-price
1953
+ :param str[] [symbols]: unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
1954
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1955
+ :returns dict: a dictionary of `ticker structures <https://docs.ccxt.com/#/?id=ticker-structure>`
1956
+ """
1957
+ self.load_markets()
1958
+ symbols = self.market_symbols(symbols)
1959
+ market = self.get_market_from_symbols(symbols)
1960
+ marketType = None
1961
+ marketType, params = self.handle_market_type_and_params('fetchTickers', market, params, 'swap')
1962
+ request: dict = {
1963
+ 'instType': self.convert_to_instrument_type(marketType),
1964
+ }
1965
+ if marketType == 'option':
1966
+ defaultUnderlying = self.safe_string(self.options, 'defaultUnderlying', 'BTC-USD')
1967
+ currencyId = self.safe_string_2(params, 'uly', 'marketId', defaultUnderlying)
1968
+ if currencyId is None:
1969
+ raise ArgumentsRequired(self.id + ' fetchTickers() requires an underlying uly or marketId parameter for options markets')
1970
+ else:
1971
+ request['uly'] = currencyId
1972
+ response = self.publicGetPublicMarkPrice(self.extend(request, params))
1973
+ tickers = self.safe_list(response, 'data', [])
1974
+ return self.parse_tickers(tickers, symbols)
1975
+
1938
1976
  def parse_trade(self, trade: dict, market: Market = None) -> Trade:
1939
1977
  #
1940
1978
  # public fetchTrades
@@ -5689,6 +5727,16 @@ class okx(Exchange, ImplicitAPI):
5689
5727
  }
5690
5728
  return self.safe_string(intervals, interval, interval)
5691
5729
 
5730
+ def fetch_funding_interval(self, symbol: str, params={}) -> FundingRate:
5731
+ """
5732
+ fetch the current funding rate interval
5733
+ :see: https://www.okx.com/docs-v5/en/#public-data-rest-api-get-funding-rate
5734
+ :param str symbol: unified market symbol
5735
+ :param dict [params]: extra parameters specific to the exchange API endpoint
5736
+ :returns dict: a `funding rate structure <https://docs.ccxt.com/#/?id=funding-rate-structure>`
5737
+ """
5738
+ return self.fetch_funding_rate(symbol, params)
5739
+
5692
5740
  def fetch_funding_rate(self, symbol: str, params={}) -> FundingRate:
5693
5741
  """
5694
5742
  fetch the current funding rate
ccxt/oxfun.py CHANGED
@@ -858,6 +858,7 @@ class oxfun(Exchange, ImplicitAPI):
858
858
  'average': None,
859
859
  'baseVolume': self.safe_string(ticker, 'currencyVolume24h'),
860
860
  'quoteVolume': None, # the exchange returns cost in OX
861
+ 'markPrice': self.safe_string(ticker, 'markPrice'),
861
862
  'info': ticker,
862
863
  }, market)
863
864
 
ccxt/paradex.py CHANGED
@@ -652,6 +652,7 @@ class paradex(Exchange, ImplicitAPI):
652
652
  'average': None,
653
653
  'baseVolume': None,
654
654
  'quoteVolume': self.safe_string(ticker, 'volume_24h'),
655
+ 'markPrice': self.safe_string(ticker, 'mark_price'),
655
656
  'info': ticker,
656
657
  }, market)
657
658
 
ccxt/poloniex.py CHANGED
@@ -633,6 +633,7 @@ class poloniex(Exchange, ImplicitAPI):
633
633
  'average': None,
634
634
  'baseVolume': self.safe_string(ticker, 'quantity'),
635
635
  'quoteVolume': self.safe_string(ticker, 'amount'),
636
+ 'markPrice': self.safe_string(ticker, 'markPrice'),
636
637
  'info': ticker,
637
638
  }, market)
638
639
 
ccxt/poloniexfutures.py CHANGED
@@ -48,6 +48,8 @@ class poloniexfutures(Exchange, ImplicitAPI):
48
48
  'fetchDepositAddress': False,
49
49
  'fetchDepositAddresses': False,
50
50
  'fetchDepositAddressesByNetwork': False,
51
+ 'fetchFundingInterval': True,
52
+ 'fetchFundingIntervals': False,
51
53
  'fetchFundingRate': True,
52
54
  'fetchFundingRateHistory': False,
53
55
  'fetchL3OrderBook': True,
@@ -1550,28 +1552,50 @@ class poloniexfutures(Exchange, ImplicitAPI):
1550
1552
  # "predictedValue": 0.00375
1551
1553
  # }
1552
1554
  #
1553
- data = self.safe_value(response, 'data')
1555
+ data = self.safe_dict(response, 'data', {})
1556
+ return self.parse_funding_rate(data, market)
1557
+
1558
+ def fetch_funding_interval(self, symbol: str, params={}) -> FundingRate:
1559
+ """
1560
+ fetch the current funding rate interval
1561
+ :see: https://api-docs.poloniex.com/futures/api/futures-index#get-premium-index
1562
+ :param str symbol: unified market symbol
1563
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1564
+ :returns dict: a `funding rate structure <https://docs.ccxt.com/#/?id=funding-rate-structure>`
1565
+ """
1566
+ return self.fetch_funding_rate(symbol, params)
1567
+
1568
+ def parse_funding_rate(self, data, market: Market = None) -> FundingRate:
1569
+ #
1570
+ # {
1571
+ # "symbol": ".ETHUSDTMFPI8H",
1572
+ # "granularity": 28800000,
1573
+ # "timePoint": 1637380800000,
1574
+ # "value": 0.0001,
1575
+ # "predictedValue": 0.0001,
1576
+ # }
1577
+ #
1554
1578
  fundingTimestamp = self.safe_integer(data, 'timePoint')
1555
- # the website displayes the previous funding rate as "funding rate"
1579
+ marketId = self.safe_string(data, 'symbol')
1556
1580
  return {
1557
1581
  'info': data,
1558
- 'symbol': market['symbol'],
1582
+ 'symbol': self.safe_symbol(marketId, market, None, 'contract'),
1559
1583
  'markPrice': None,
1560
1584
  'indexPrice': None,
1561
1585
  'interestRate': None,
1562
1586
  'estimatedSettlePrice': None,
1563
1587
  'timestamp': None,
1564
1588
  'datetime': None,
1565
- 'fundingRate': self.safe_number(data, 'predictedValue'),
1566
- 'fundingTimestamp': None,
1567
- 'fundingDatetime': None,
1568
- 'nextFundingRate': None,
1589
+ 'fundingRate': self.safe_number(data, 'value'),
1590
+ 'fundingTimestamp': fundingTimestamp,
1591
+ 'fundingDatetime': self.iso8601(fundingTimestamp),
1592
+ 'nextFundingRate': self.safe_number(data, 'predictedValue'),
1569
1593
  'nextFundingTimestamp': None,
1570
1594
  'nextFundingDatetime': None,
1571
- 'previousFundingRate': self.safe_number(data, 'value'),
1572
- 'previousFundingTimestamp': fundingTimestamp,
1573
- 'previousFundingDatetime': self.iso8601(fundingTimestamp),
1574
- 'interval': self.parse_funding_interval(self.safe_string(data, 'interval')),
1595
+ 'previousFundingRate': None,
1596
+ 'previousFundingTimestamp': None,
1597
+ 'previousFundingDatetime': None,
1598
+ 'interval': self.parse_funding_interval(self.safe_string(data, 'granularity')),
1575
1599
  }
1576
1600
 
1577
1601
  def parse_funding_interval(self, interval):
ccxt/pro/__init__.py CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  # ----------------------------------------------------------------------------
6
6
 
7
- __version__ = '4.4.12'
7
+ __version__ = '4.4.14'
8
8
 
9
9
  # ----------------------------------------------------------------------------
10
10
 
ccxt/pro/binance.py CHANGED
@@ -43,6 +43,8 @@ class binance(ccxt.async_support.binance):
43
43
  'watchPositions': True,
44
44
  'watchTicker': True,
45
45
  'watchTickers': True,
46
+ 'watchMarkPrices': True,
47
+ 'watchMarkPrice': True,
46
48
  'watchTrades': True,
47
49
  'watchTradesForSymbols': True,
48
50
  'createOrderWs': True,
@@ -159,6 +161,7 @@ class binance(ccxt.async_support.binance):
159
161
  'tickerChannelsMap': {
160
162
  '24hrTicker': 'ticker',
161
163
  '24hrMiniTicker': 'miniTicker',
164
+ 'markPriceUpdate': 'markPrice',
162
165
  # rolling window tickers
163
166
  '1hTicker': 'ticker_1h',
164
167
  '4hTicker': 'ticker_4h',
@@ -1641,6 +1644,39 @@ class binance(ccxt.async_support.binance):
1641
1644
  tickers = await self.watch_tickers([symbol], self.extend(params, {'callerMethodName': 'watchTicker'}))
1642
1645
  return tickers[symbol]
1643
1646
 
1647
+ async def watch_mark_price(self, symbol: str, params={}) -> Ticker:
1648
+ """
1649
+ :see: https://developers.binance.com/docs/derivatives/usds-margined-futures/websocket-market-streams/Mark-Price-Stream
1650
+ watches a mark price for a specific market
1651
+ :param str symbol: unified symbol of the market to fetch the ticker for
1652
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1653
+ :param boolean [params.use1sFreq]: *default is True* if set to True, the mark price will be updated every second, otherwise every 3 seconds
1654
+ :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
1655
+ """
1656
+ await self.load_markets()
1657
+ symbol = self.symbol(symbol)
1658
+ tickers = await self.watch_mark_prices([symbol], self.extend(params, {'callerMethodName': 'watchMarkPrice'}))
1659
+ return tickers[symbol]
1660
+
1661
+ async def watch_mark_prices(self, symbols: Strings = None, params={}) -> Tickers:
1662
+ """
1663
+ :see: https://developers.binance.com/docs/derivatives/usds-margined-futures/websocket-market-streams/Mark-Price-Stream-for-All-market
1664
+ watches the mark price for all markets
1665
+ :param str[] symbols: unified symbol of the market to fetch the ticker for
1666
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1667
+ :param boolean [params.use1sFreq]: *default is True* if set to True, the mark price will be updated every second, otherwise every 3 seconds
1668
+ :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
1669
+ """
1670
+ channelName = None
1671
+ # for now watchmarkPrice uses the same messageHash
1672
+ # so it's impossible to watch both at the same time
1673
+ # refactor self to use different messageHashes
1674
+ channelName, params = self.handle_option_and_params(params, 'watchMarkPrices', 'name', 'markPrice')
1675
+ newTickers = await self.watch_multi_ticker_helper('watchMarkPrices', channelName, symbols, params)
1676
+ if self.newUpdates:
1677
+ return newTickers
1678
+ return self.filter_by_array(self.tickers, 'symbol', symbols)
1679
+
1644
1680
  async def watch_tickers(self, symbols: Strings = None, params={}) -> Tickers:
1645
1681
  """
1646
1682
  :see: https://binance-docs.github.io/apidocs/spot/en/#individual-symbol-mini-ticker-stream
@@ -1775,12 +1811,16 @@ class binance(ccxt.async_support.binance):
1775
1811
  async def watch_multi_ticker_helper(self, methodName, channelName: str, symbols: Strings = None, params={}):
1776
1812
  await self.load_markets()
1777
1813
  symbols = self.market_symbols(symbols, None, True, False, True)
1814
+ isBidAsk = (channelName == 'bookTicker')
1815
+ isMarkPrice = (channelName == 'markPrice')
1816
+ use1sFreq = self.safe_bool(params, 'use1sFreq', True)
1778
1817
  firstMarket = None
1779
1818
  marketType = None
1780
1819
  symbolsDefined = (symbols is not None)
1781
1820
  if symbolsDefined:
1782
1821
  firstMarket = self.market(symbols[0])
1783
- marketType, params = self.handle_market_type_and_params(methodName, firstMarket, params)
1822
+ defaultMarket = 'swap' if (isMarkPrice) else 'spot'
1823
+ marketType, params = self.handle_market_type_and_params(methodName, firstMarket, params, defaultMarket)
1784
1824
  subType = None
1785
1825
  subType, params = self.handle_sub_type_and_params(methodName, firstMarket, params)
1786
1826
  rawMarketType = None
@@ -1792,20 +1832,24 @@ class binance(ccxt.async_support.binance):
1792
1832
  rawMarketType = marketType
1793
1833
  else:
1794
1834
  raise NotSupported(self.id + ' ' + methodName + '() does not support options markets')
1795
- isBidAsk = (channelName == 'bookTicker')
1796
1835
  subscriptionArgs = []
1797
1836
  messageHashes = []
1837
+ suffix = ''
1838
+ if isMarkPrice:
1839
+ suffix = '@1s' if (use1sFreq) else ''
1798
1840
  if symbolsDefined:
1799
1841
  for i in range(0, len(symbols)):
1800
1842
  symbol = symbols[i]
1801
1843
  market = self.market(symbol)
1802
- subscriptionArgs.append(market['lowercaseId'] + '@' + channelName)
1844
+ subscriptionArgs.append(market['lowercaseId'] + '@' + channelName + suffix)
1803
1845
  messageHashes.append(self.get_message_hash(channelName, market['symbol'], isBidAsk))
1804
1846
  else:
1805
1847
  if isBidAsk:
1806
1848
  if marketType == 'spot':
1807
1849
  raise ArgumentsRequired(self.id + ' ' + methodName + '() requires symbols for self channel for spot markets')
1808
1850
  subscriptionArgs.append('!' + channelName)
1851
+ elif isMarkPrice:
1852
+ subscriptionArgs.append('!' + channelName + '@arr' + suffix)
1809
1853
  else:
1810
1854
  subscriptionArgs.append('!' + channelName + '@arr')
1811
1855
  messageHashes.append(self.get_message_hash(channelName, None, isBidAsk))
@@ -1833,6 +1877,17 @@ class binance(ccxt.async_support.binance):
1833
1877
  return newDict
1834
1878
 
1835
1879
  def parse_ws_ticker(self, message, marketType):
1880
+ # markPrice
1881
+ # {
1882
+ # "e": "markPriceUpdate", # Event type
1883
+ # "E": 1562305380000, # Event time
1884
+ # "s": "BTCUSDT", # Symbol
1885
+ # "p": "11794.15000000", # Mark price
1886
+ # "i": "11784.62659091", # Index price
1887
+ # "P": "11784.25641265", # Estimated Settle Price, only useful in the last hour before the settlement starts
1888
+ # "r": "0.00038167", # Funding rate
1889
+ # "T": 1562306400000 # Next funding time
1890
+ # }
1836
1891
  #
1837
1892
  # ticker
1838
1893
  # {
@@ -1890,9 +1945,21 @@ class binance(ccxt.async_support.binance):
1890
1945
  # "time":1589437530011,
1891
1946
  # }
1892
1947
  #
1948
+ marketId = self.safe_string_2(message, 's', 'symbol')
1949
+ symbol = self.safe_symbol(marketId, None, None, marketType)
1893
1950
  event = self.safe_string(message, 'e', 'bookTicker')
1894
1951
  if event == '24hrTicker':
1895
1952
  event = 'ticker'
1953
+ if event == 'markPriceUpdate':
1954
+ # handle self separately because some fields clash with the ticker fields
1955
+ return self.safe_ticker({
1956
+ 'symbol': symbol,
1957
+ 'timestamp': self.safe_integer(message, 'E'),
1958
+ 'datetime': self.iso8601(self.safe_integer(message, 'E')),
1959
+ 'info': message,
1960
+ 'markPrice': self.safe_string(message, 'p'),
1961
+ 'indexPrice': self.safe_string(message, 'i'),
1962
+ })
1896
1963
  timestamp = None
1897
1964
  if event == 'bookTicker':
1898
1965
  # take the event timestamp, if available, for spot tickers it is not
@@ -1900,8 +1967,6 @@ class binance(ccxt.async_support.binance):
1900
1967
  else:
1901
1968
  # take the timestamp of the closing price for candlestick streams
1902
1969
  timestamp = self.safe_integer_n(message, ['C', 'E', 'time'])
1903
- marketId = self.safe_string_2(message, 's', 'symbol')
1904
- symbol = self.safe_symbol(marketId, None, None, marketType)
1905
1970
  market = self.safe_market(marketId, None, None, marketType)
1906
1971
  last = self.safe_string_2(message, 'c', 'price')
1907
1972
  return self.safe_ticker({
@@ -3864,6 +3929,8 @@ class binance(ccxt.async_support.binance):
3864
3929
  '1dTicker': self.handle_tickers,
3865
3930
  '24hrTicker': self.handle_tickers,
3866
3931
  '24hrMiniTicker': self.handle_tickers,
3932
+ 'markPriceUpdate': self.handle_tickers,
3933
+ 'markPriceUpdate@arr': self.handle_tickers,
3867
3934
  'bookTicker': self.handle_bids_asks, # there is no "bookTicker@arr" endpoint
3868
3935
  'outboundAccountPosition': self.handle_balance,
3869
3936
  'balanceUpdate': self.handle_balance,
ccxt/pro/bitfinex.py CHANGED
@@ -213,15 +213,15 @@ class bitfinex(ccxt.async_support.bitfinex):
213
213
  open = None
214
214
  if (last is not None) and (change is not None):
215
215
  open = Precise.string_sub(last, change)
216
- result = {
216
+ result = self.safe_ticker({
217
217
  'symbol': symbol,
218
218
  'timestamp': None,
219
219
  'datetime': None,
220
- 'high': self.safe_float(message, 9),
221
- 'low': self.safe_float(message, 10),
222
- 'bid': self.safe_float(message, 1),
220
+ 'high': self.safe_string(message, 9),
221
+ 'low': self.safe_string(message, 10),
222
+ 'bid': self.safe_string(message, 1),
223
223
  'bidVolume': None,
224
- 'ask': self.safe_float(message, 3),
224
+ 'ask': self.safe_string(message, 3),
225
225
  'askVolume': None,
226
226
  'vwap': None,
227
227
  'open': self.parse_number(open),
@@ -229,12 +229,12 @@ class bitfinex(ccxt.async_support.bitfinex):
229
229
  'last': self.parse_number(last),
230
230
  'previousClose': None,
231
231
  'change': self.parse_number(change),
232
- 'percentage': self.safe_float(message, 6),
232
+ 'percentage': self.safe_string(message, 6),
233
233
  'average': None,
234
- 'baseVolume': self.safe_float(message, 8),
234
+ 'baseVolume': self.safe_string(message, 8),
235
235
  'quoteVolume': None,
236
236
  'info': message,
237
- }
237
+ })
238
238
  self.tickers[symbol] = result
239
239
  client.resolve(result, messageHash)
240
240
 
ccxt/pro/krakenfutures.py CHANGED
@@ -998,6 +998,8 @@ class krakenfutures(ccxt.async_support.krakenfutures):
998
998
  'average': None,
999
999
  'baseVolume': self.safe_string(ticker, 'volume'),
1000
1000
  'quoteVolume': self.safe_string(ticker, 'volumeQuote'),
1001
+ 'markPrice': self.safe_string(ticker, 'markPrice'),
1002
+ 'indexPrice': self.safe_string(ticker, 'index'),
1001
1003
  })
1002
1004
 
1003
1005
  def handle_order_book_snapshot(self, client: Client, message):
ccxt/pro/okx.py CHANGED
@@ -25,6 +25,8 @@ class okx(ccxt.async_support.okx):
25
25
  'has': {
26
26
  'ws': True,
27
27
  'watchTicker': True,
28
+ 'watchMarkPrice': True,
29
+ 'watchMarkPrices': True,
28
30
  'watchTickers': True,
29
31
  'watchBidsAsks': True,
30
32
  'watchOrderBook': True,
@@ -408,6 +410,41 @@ class okx(ccxt.async_support.okx):
408
410
  return newTickers
409
411
  return self.filter_by_array(self.tickers, 'symbol', symbols)
410
412
 
413
+ async def watch_mark_price(self, symbol: str, params={}) -> Ticker:
414
+ """
415
+ :see: https://www.okx.com/docs-v5/en/#public-data-websocket-mark-price-channel
416
+ watches a mark price
417
+ :param str symbol: unified symbol of the market to fetch the ticker for
418
+ :param dict [params]: extra parameters specific to the exchange API endpoint
419
+ :param str [params.channel]: the channel to subscribe to, tickers by default. Can be tickers, sprd-tickers, index-tickers, block-tickers
420
+ :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
421
+ """
422
+ channel = None
423
+ channel, params = self.handle_option_and_params(params, 'watchMarkPrice', 'channel', 'mark-price')
424
+ params['channel'] = channel
425
+ market = self.market(symbol)
426
+ symbol = market['symbol']
427
+ ticker = await self.watch_mark_prices([symbol], params)
428
+ return ticker[symbol]
429
+
430
+ async def watch_mark_prices(self, symbols: Strings = None, params={}) -> Tickers:
431
+ """
432
+ :see: https://www.okx.com/docs-v5/en/#public-data-websocket-mark-price-channel
433
+ watches mark prices
434
+ :param str[] [symbols]: unified symbol of the market to fetch the ticker for
435
+ :param dict [params]: extra parameters specific to the exchange API endpoint
436
+ :param str [params.channel]: the channel to subscribe to, tickers by default. Can be tickers, sprd-tickers, index-tickers, block-tickers
437
+ :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
438
+ """
439
+ await self.load_markets()
440
+ symbols = self.market_symbols(symbols, None, False)
441
+ channel = None
442
+ channel, params = self.handle_option_and_params(params, 'watchMarkPrices', 'channel', 'mark-price')
443
+ newTickers = await self.subscribe_multiple('public', channel, symbols, params)
444
+ if self.newUpdates:
445
+ return newTickers
446
+ return self.filter_by_array(self.tickers, 'symbol', symbols)
447
+
411
448
  async def un_watch_tickers(self, symbols: Strings = None, params={}) -> Any:
412
449
  """
413
450
  :see: https://www.okx.com/docs-v5/en/#order-book-trading-market-data-ws-tickers-channel
@@ -2157,6 +2194,7 @@ class okx(ccxt.async_support.okx):
2157
2194
  'books50-l2-tbt': self.handle_order_book, # only users who're VIP4 and above can subscribe, identity verification required before subscription
2158
2195
  'books-l2-tbt': self.handle_order_book, # only users who're VIP5 and above can subscribe, identity verification required before subscription
2159
2196
  'tickers': self.handle_ticker,
2197
+ 'mark-price': self.handle_ticker,
2160
2198
  'positions': self.handle_positions,
2161
2199
  'index-tickers': self.handle_ticker,
2162
2200
  'sprd-tickers': self.handle_ticker,
ccxt/pro/phemex.py CHANGED
@@ -132,6 +132,8 @@ class phemex(ccxt.async_support.phemex):
132
132
  'average': average,
133
133
  'baseVolume': baseVolume,
134
134
  'quoteVolume': quoteVolume,
135
+ 'markPrice': self.parse_number(self.from_ep(self.safe_string(ticker, 'markPrice'), market)),
136
+ 'indexPrice': self.parse_number(self.from_ep(self.safe_string(ticker, 'indexPrice'), market)),
135
137
  'info': ticker,
136
138
  }
137
139
  return result