cryptofeed 3.0.0__tar.gz → 3.0.1__tar.gz

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 (79) hide show
  1. {cryptofeed-3.0.0 → cryptofeed-3.0.1}/CHANGES.md +7 -0
  2. {cryptofeed-3.0.0/cryptofeed.egg-info → cryptofeed-3.0.1}/PKG-INFO +4 -4
  3. {cryptofeed-3.0.0 → cryptofeed-3.0.1}/README.md +2 -2
  4. {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/defines.py +2 -2
  5. {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/exchanges/__init__.py +4 -4
  6. {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/exchanges/binance.py +9 -3
  7. {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/exchanges/binance_delivery.py +1 -0
  8. {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/exchanges/binance_futures.py +1 -0
  9. {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/exchanges/coinbase.py +9 -2
  10. {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/exchanges/dydx.py +7 -5
  11. cryptofeed-3.0.0/cryptofeed/exchanges/gateio.py → cryptofeed-3.0.1/cryptofeed/exchanges/gate.py +7 -4
  12. cryptofeed-3.0.0/cryptofeed/exchanges/gateio_futures.py → cryptofeed-3.0.1/cryptofeed/exchanges/gate_futures.py +39 -15
  13. {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/exchanges/kraken_futures.py +27 -4
  14. {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/exchanges/okx.py +14 -7
  15. {cryptofeed-3.0.0 → cryptofeed-3.0.1/cryptofeed.egg-info}/PKG-INFO +4 -4
  16. {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed.egg-info/SOURCES.txt +2 -2
  17. {cryptofeed-3.0.0 → cryptofeed-3.0.1}/pyproject.toml +2 -2
  18. {cryptofeed-3.0.0 → cryptofeed-3.0.1}/LICENSE +0 -0
  19. {cryptofeed-3.0.0 → cryptofeed-3.0.1}/MANIFEST.in +0 -0
  20. {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/__init__.py +0 -0
  21. {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/_json.py +0 -0
  22. {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/backends/__init__.py +0 -0
  23. {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/backends/_line_protocol.py +0 -0
  24. {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/backends/backend.py +0 -0
  25. {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/backends/http.py +0 -0
  26. {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/backends/influxdb.py +0 -0
  27. {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/backends/kafka.py +0 -0
  28. {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/backends/mongo.py +0 -0
  29. {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/backends/postgres.py +0 -0
  30. {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/backends/quest.py +0 -0
  31. {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/backends/redis.py +0 -0
  32. {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/backends/socket.py +0 -0
  33. {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/backends/zmq.py +0 -0
  34. {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/callback.py +0 -0
  35. {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/capture/__init__.py +0 -0
  36. {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/capture/_zstd.py +0 -0
  37. {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/capture/pcap.py +0 -0
  38. {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/capture/playback.py +0 -0
  39. {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/capture/recorder.py +0 -0
  40. {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/config.py +0 -0
  41. {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/connection.py +0 -0
  42. {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/connection_handler.py +0 -0
  43. {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/exceptions.py +0 -0
  44. {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/exchange.py +0 -0
  45. {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/exchanges/binance_us.py +0 -0
  46. {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/exchanges/bitfinex.py +0 -0
  47. {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/exchanges/bitflyer.py +0 -0
  48. {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/exchanges/bitget.py +0 -0
  49. {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/exchanges/bithumb.py +0 -0
  50. {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/exchanges/bitstamp.py +0 -0
  51. {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/exchanges/bybit.py +0 -0
  52. {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/exchanges/cryptodotcom.py +0 -0
  53. {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/exchanges/deribit.py +0 -0
  54. {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/exchanges/gemini.py +0 -0
  55. {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/exchanges/htx.py +0 -0
  56. {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/exchanges/htx_swap.py +0 -0
  57. {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/exchanges/hyperliquid.py +0 -0
  58. {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/exchanges/independent_reserve.py +0 -0
  59. {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/exchanges/kraken.py +0 -0
  60. {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/exchanges/kucoin.py +0 -0
  61. {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/exchanges/kucoin_futures.py +0 -0
  62. {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/exchanges/mexc.py +0 -0
  63. {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/exchanges/phemex.py +0 -0
  64. {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/exchanges/poloniex.py +0 -0
  65. {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/exchanges/upbit.py +0 -0
  66. {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/feed.py +0 -0
  67. {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/feedhandler.py +0 -0
  68. {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/log.py +0 -0
  69. {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/nbbo.py +0 -0
  70. {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/py.typed +0 -0
  71. {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/symbols.py +0 -0
  72. {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/types.pyi +0 -0
  73. {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/types.pyx +0 -0
  74. {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/util/__init__.py +0 -0
  75. {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/util/time.py +0 -0
  76. {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed.egg-info/dependency_links.txt +0 -0
  77. {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed.egg-info/requires.txt +0 -0
  78. {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed.egg-info/top_level.txt +0 -0
  79. {cryptofeed-3.0.0 → cryptofeed-3.0.1}/setup.cfg +0 -0
@@ -1,5 +1,12 @@
1
1
  ## Changelog
2
2
 
3
+ ### 3.0.1 (2026-09-27)
4
+ * Update: Gate.io -> Gate rebranding
5
+ * Bugfix: Binance Futures and Binance Delivery L2_BOOK with `depth_interval='250ms'` subscribed to `<symbol>@depth@250ms`, which Binance accepts but never sends data on. The default interval now uses the bare `<symbol>@depth` stream.
6
+ * Bugfix: `depth_interval=None` on Binance Futures and Binance Delivery produced an invalid subscription. `None` now resolves to the venue default
7
+ * Bugfix: Coinbase, OKX, Gate, Kraken data quality issues
8
+ * Bugfix: dYdX subscribe/reconnect connection issues
9
+
3
10
  ### 3.0.0 (2026-09-21)
4
11
  * Feature: New asyncio core
5
12
  * Update: REST endpoints removed (trading functionality moves to the cryptotrade project)
@@ -1,11 +1,11 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cryptofeed
3
- Version: 3.0.0
3
+ Version: 3.0.1
4
4
  Summary: Cryptocurrency Exchange Websocket Data Feed Handler
5
5
  Author-email: Bryant Moscon <bmoscon@gmail.com>
6
6
  License-Expression: AGPL-3.0-or-later
7
7
  Project-URL: Homepage, https://github.com/bmoscon/cryptofeed
8
- Keywords: cryptocurrency,bitcoin,btc,feed handler,market feed,market data,crypto assets,Trades,Tickers,BBO,Funding,Open Interest,Liquidation,Order book,Bid,Ask,Binance,Binance Delivery,Binance Futures,Binance US,Bitfinex,bitFlyer,Bitget,Bithumb,Bitstamp,Bybit,Coinbase,Crypto.com,Deribit,Gate.io,Gate.io Futures,dYdX,Gemini,Hyperliquid,HTX,HTX Swap,Independent Reserve,Kraken,Kraken Futures,KuCoin,MEXC,OKX,Phemex,Poloniex,Upbit
8
+ Keywords: cryptocurrency,bitcoin,btc,feed handler,market feed,market data,crypto assets,Trades,Tickers,BBO,Funding,Open Interest,Liquidation,Order book,Bid,Ask,Binance,Binance Delivery,Binance Futures,Binance US,Bitfinex,bitFlyer,Bitget,Bithumb,Bitstamp,Bybit,Coinbase,Crypto.com,Deribit,Gate,Gate Futures,dYdX,Gemini,Hyperliquid,HTX,HTX Swap,Independent Reserve,Kraken,Kraken Futures,KuCoin,MEXC,OKX,Phemex,Poloniex,Upbit
9
9
  Classifier: Intended Audience :: Developers
10
10
  Classifier: Development Status :: 4 - Beta
11
11
  Classifier: Programming Language :: Python :: 3 :: Only
@@ -70,8 +70,8 @@ Handles multiple cryptocurrency exchange data feeds and returns normalized and s
70
70
  * [Coinbase](https://www.coinbase.com/)
71
71
  * [Crypto.com](https://www.crypto.com)
72
72
  * [Deribit](https://www.deribit.com/)
73
- * [Gate.io](https://www.gate.io/)
74
- * [Gate.io Futures](https://www.gate.io/futures_center)
73
+ * [Gate](https://www.gate.com/)
74
+ * [Gate Futures](https://www.gate.com/futures)
75
75
  * [dYdX v4](https://dydx.trade/)
76
76
  * [Gemini](https://gemini.com/)
77
77
  * [Hyperliquid](https://hyperliquid.xyz/)
@@ -21,8 +21,8 @@ Handles multiple cryptocurrency exchange data feeds and returns normalized and s
21
21
  * [Coinbase](https://www.coinbase.com/)
22
22
  * [Crypto.com](https://www.crypto.com)
23
23
  * [Deribit](https://www.deribit.com/)
24
- * [Gate.io](https://www.gate.io/)
25
- * [Gate.io Futures](https://www.gate.io/futures_center)
24
+ * [Gate](https://www.gate.com/)
25
+ * [Gate Futures](https://www.gate.com/futures)
26
26
  * [dYdX v4](https://dydx.trade/)
27
27
  * [Gemini](https://gemini.com/)
28
28
  * [Hyperliquid](https://hyperliquid.xyz/)
@@ -22,8 +22,8 @@ BYBIT = 'BYBIT'
22
22
  COINBASE = 'COINBASE'
23
23
  CRYPTODOTCOM = "CRYPTO.COM"
24
24
  DERIBIT = 'DERIBIT'
25
- GATEIO = 'GATEIO'
26
- GATEIO_FUTURES = 'GATEIO_FUTURES'
25
+ GATE = 'GATE'
26
+ GATE_FUTURES = 'GATE_FUTURES'
27
27
  GEMINI = 'GEMINI'
28
28
  DYDX = 'DYDX'
29
29
  HYPERLIQUID = 'HYPERLIQUID'
@@ -21,8 +21,8 @@ from .bybit import Bybit
21
21
  from .coinbase import Coinbase
22
22
  from .cryptodotcom import CryptoDotCom
23
23
  from .deribit import Deribit
24
- from .gateio import Gateio
25
- from .gateio_futures import GateioFutures
24
+ from .gate import Gate
25
+ from .gate_futures import GateFutures
26
26
  from .gemini import Gemini
27
27
  from .htx import HTX
28
28
  from .htx_swap import HTXSwap
@@ -53,8 +53,8 @@ EXCHANGE_MAP = {
53
53
  COINBASE: Coinbase,
54
54
  CRYPTODOTCOM: CryptoDotCom,
55
55
  DERIBIT: Deribit,
56
- GATEIO: Gateio,
57
- GATEIO_FUTURES: GateioFutures,
56
+ GATE: Gate,
57
+ GATE_FUTURES: GateFutures,
58
58
  GEMINI: Gemini,
59
59
  HTX_SWAP: HTXSwap,
60
60
  HTX_str: HTX,
@@ -33,6 +33,9 @@ class BinanceBase(Feed):
33
33
  DEFAULT_SNAPSHOT_DEPTH = 1000
34
34
  SNAPSHOT_RETRIES = 5
35
35
  SNAPSHOT_RETRY_DELAY = 15
36
+ # Depth interval Binance serves on the bare `<symbol>@depth` stream. The
37
+ # futures endpoints send nothing on an explicit `@250ms` suffix.
38
+ default_depth_interval = None
36
39
  # m -> minutes; h -> hours; d -> days; w -> weeks; M -> months
37
40
  valid_candle_intervals = {'1m', '3m', '5m', '15m', '30m', '1h', '2h', '4h', '6h', '8h', '12h', '1d', '3d', '1w', '1M'}
38
41
  websocket_channels = {
@@ -79,11 +82,14 @@ class BinanceBase(Feed):
79
82
 
80
83
  def __init__(self, depth_interval='100ms', open_interest_interval=1.0, **kwargs):
81
84
  """
82
- depth_interval: str
83
- time between l2_book/delta updates {'100ms', '1000ms'} (different from BINANCE_FUTURES & BINANCE_DELIVERY)
85
+ depth_interval: str or None
86
+ time between l2_book/delta updates {'100ms', '1000ms'} (different from BINANCE_FUTURES & BINANCE_DELIVERY).
87
+ None selects the venue's default speed, i.e. the bare <symbol>@depth stream
84
88
  open_interest_interval: float
85
89
  time in seconds between open_interest polls
86
90
  """
91
+ if depth_interval is None:
92
+ depth_interval = self.default_depth_interval
87
93
  if depth_interval is not None and depth_interval not in self.valid_depth_intervals:
88
94
  raise ValueError(f"Depth interval must be one of {self.valid_depth_intervals}")
89
95
 
@@ -152,7 +158,7 @@ class BinanceBase(Feed):
152
158
  stream = chan
153
159
  if normalized_chan == CANDLES:
154
160
  stream = f"{chan}{self.candle_interval}"
155
- elif normalized_chan == L2_BOOK:
161
+ elif normalized_chan == L2_BOOK and self.depth_interval != self.default_depth_interval:
156
162
  stream = f"{chan}@{self.depth_interval}"
157
163
 
158
164
  for pair in self.subscription[chan]:
@@ -24,6 +24,7 @@ class BinanceDelivery(BinanceBase):
24
24
 
25
25
  valid_depths = [5, 10, 20, 50, 100, 500, 1000]
26
26
  valid_depth_intervals = {'100ms', '250ms', '500ms'}
27
+ default_depth_interval = '250ms'
27
28
  websocket_channels = {
28
29
  **BinanceBase.websocket_channels,
29
30
  FUNDING: 'markPrice',
@@ -25,6 +25,7 @@ class BinanceFutures(BinanceBase):
25
25
 
26
26
  valid_depths = [5, 10, 20, 50, 100, 500, 1000]
27
27
  valid_depth_intervals = {'100ms', '250ms', '500ms'}
28
+ default_depth_interval = '250ms'
28
29
  websocket_channels = {
29
30
  **BinanceBase.websocket_channels,
30
31
  FUNDING: 'markPrice',
@@ -83,21 +83,28 @@ class Coinbase(Feed):
83
83
  async def _trade_update(self, msg: dict, timestamp: float):
84
84
  '''
85
85
  {
86
- 'trade_id': 43736593
86
+ 'trade_id': '43736593',
87
87
  'side': 'BUY' or 'SELL',
88
88
  'size': '0.01235647',
89
89
  'price': '8506.26000000',
90
90
  'product_id': 'BTC-USD',
91
91
  'time': '2018-05-21T00:26:05.585000Z'
92
92
  }
93
+
94
+ 'side' is the maker side of the trade but we report the taker side
93
95
  '''
96
+ side = SELL if msg.get('side') == 'BUY' else BUY if msg.get('side') == 'SELL' else None
97
+ if side is None:
98
+ LOG.warning('%s: unexpected market_trades side %r for %s trade %s - skipping', self.id, msg.get('side'), msg.get('product_id'), msg.get('trade_id'))
99
+ return
100
+
94
101
  pair = self.exchange_symbol_to_std_symbol(msg['product_id'])
95
102
  ts = self.timestamp_normalize(msg['time'])
96
103
  order_type = 'market'
97
104
  t = Trade(
98
105
  self.id,
99
106
  pair,
100
- SELL if msg['side'] == 'SELL' else BUY,
107
+ side,
101
108
  Decimal(msg['size']),
102
109
  Decimal(msg['price']),
103
110
  ts,
@@ -54,14 +54,16 @@ class dYdX(Feed):
54
54
 
55
55
  def __init__(self, **kwargs):
56
56
  super().__init__(**kwargs)
57
- self._reset()
58
-
59
- def _reset(self):
60
- self._l2_book = {}
61
57
  self._message_id = {}
62
58
 
59
+ def _reset(self, conn: AsyncConnection):
60
+ for symbol in conn.subscription.get(self.std_channel_to_exchange(L2_BOOK), []):
61
+ self._l2_book.pop(self.exchange_symbol_to_std_symbol(symbol), None)
62
+ # message ids reset to 0
63
+ self._message_id.pop(conn.uuid, None)
64
+
63
65
  async def subscribe(self, conn: AsyncConnection):
64
- self._reset()
66
+ self._reset(conn)
65
67
  for channel, symbols in conn.subscription.items():
66
68
  for symbol in symbols:
67
69
  await conn.write(json.dumps({'type': 'subscribe', 'channel': channel, 'id': symbol}))
@@ -13,7 +13,7 @@ from typing import Dict, Tuple
13
13
  from cryptofeed import _json as json
14
14
 
15
15
  from cryptofeed.connection import AsyncConnection, RestEndpoint, Routes, WebsocketEndpoint
16
- from cryptofeed.defines import BID, ASK, CANDLES, GATEIO, L2_BOOK, TICKER, TRADES, BUY, SELL
16
+ from cryptofeed.defines import BID, ASK, CANDLES, GATE, L2_BOOK, TICKER, TRADES, BUY, SELL
17
17
  from cryptofeed.exceptions import MissingSequenceNumber
18
18
  from cryptofeed.feed import Feed
19
19
  from cryptofeed.symbols import Symbol
@@ -24,8 +24,8 @@ from cryptofeed.util.time import timedelta_str_to_sec
24
24
  LOG = logging.getLogger(__name__)
25
25
 
26
26
 
27
- class Gateio(Feed):
28
- id = GATEIO
27
+ class Gate(Feed):
28
+ id = GATE
29
29
  provides_sequence_number = True
30
30
  validates_sequence_number = True
31
31
  MAX_STALE_SNAPSHOTS = 3
@@ -122,6 +122,9 @@ class Gateio(Feed):
122
122
  def _snapshot_url(self, symbol: str) -> str:
123
123
  return self.rest_endpoints[0].route('l2book', self.sandbox).format(symbol, self.SNAPSHOT_DEPTH)
124
124
 
125
+ def _book_subscription(self, symbol: str) -> list:
126
+ return [symbol, '100ms']
127
+
125
128
  def _parse_snapshot(self, symbol: str, data) -> OrderBook:
126
129
  """
127
130
  {
@@ -292,7 +295,7 @@ class Gateio(Feed):
292
295
  "time": int(time.time()),
293
296
  "channel": chan,
294
297
  "event": 'subscribe',
295
- "payload": [symbol, '100ms'] if nchan == L2_BOOK else [self.candle_interval, symbol],
298
+ "payload": self._book_subscription(symbol) if nchan == L2_BOOK else [self.candle_interval, symbol],
296
299
  }
297
300
  ))
298
301
  else:
@@ -11,9 +11,9 @@ from decimal import Decimal
11
11
  from cryptofeed import _json as json
12
12
 
13
13
  from cryptofeed.connection import RestEndpoint, Routes, WebsocketEndpoint
14
- from cryptofeed.defines import GATEIO_FUTURES, PERPETUAL, CANDLES, L2_BOOK, TICKER, TRADES, BID, ASK, BUY, SELL, OPEN_INTEREST, INDEX, FUNDING
14
+ from cryptofeed.defines import GATE_FUTURES, PERPETUAL, CANDLES, L2_BOOK, TICKER, TRADES, BID, ASK, BUY, SELL, OPEN_INTEREST, INDEX, FUNDING
15
15
 
16
- from cryptofeed.exchanges.gateio import Gateio
16
+ from cryptofeed.exchanges.gate import Gate
17
17
  from typing import Dict, Tuple
18
18
  from cryptofeed.symbols import Symbol
19
19
  from cryptofeed.types import OrderBook, Trade, Ticker, Candle, Index, OpenInterest, Funding
@@ -22,8 +22,8 @@ from cryptofeed.util.time import timedelta_str_to_sec
22
22
  LOG = logging.getLogger(__name__)
23
23
 
24
24
 
25
- class GateioFutures(Gateio):
26
- id = GATEIO_FUTURES
25
+ class GateFutures(Gate):
26
+ id = GATE_FUTURES
27
27
  SNAPSHOT_DEPTH = 100
28
28
  provides_sequence_number = True
29
29
  websocket_endpoints = [WebsocketEndpoint('wss://fx-ws.gateio.ws/v4/ws/usdt', options={'compression': None})]
@@ -39,9 +39,17 @@ class GateioFutures(Gateio):
39
39
  INDEX: 'futures.tickers'
40
40
  }
41
41
 
42
+ BOOK_LEVELS = (20, 50, 100)
43
+
42
44
  def __init__(self, **kwargs):
43
45
  super().__init__(**kwargs)
44
46
  self._sub_contract_trades = set()
47
+ self.SNAPSHOT_DEPTH = next((level for level in self.BOOK_LEVELS if level >= self.max_depth), self.BOOK_LEVELS[-1]) if self.max_depth else self.BOOK_LEVELS[-1]
48
+ self._book_window = {}
49
+ self._book_window_warned = False
50
+
51
+ def _book_subscription(self, symbol: str) -> list:
52
+ return [symbol, '100ms', str(self.SNAPSHOT_DEPTH)]
45
53
 
46
54
  @classmethod
47
55
  def _parse_symbol_data(cls, data: dict) -> Tuple[Dict, Dict]:
@@ -167,11 +175,13 @@ class GateioFutures(Gateio):
167
175
  }
168
176
  """
169
177
  data = json.loads(data, parse_float=Decimal)
170
- book = OrderBook(self.id, symbol, max_depth=self.max_depth)
171
- book.book.bids = {Decimal(bid["p"]): Decimal(bid["s"]) for bid in data['bids']}
172
- book.book.asks = {Decimal(ask["p"]): Decimal(ask["s"]) for ask in data['asks']}
178
+ depth = self._book_window.get(symbol, self.SNAPSHOT_DEPTH)
179
+ book = OrderBook(self.id, symbol, max_depth=depth, truncate=True, bids={Decimal(bid["p"]): Decimal(bid["s"]) for bid in data['bids']}, asks={Decimal(ask["p"]): Decimal(ask["s"]) for ask in data['asks']})
180
+ book.book.bids.truncate()
181
+ book.book.asks.truncate()
173
182
  book.sequence_number = data['id']
174
183
  book.raw = data
184
+
175
185
  return book
176
186
 
177
187
  async def _process_l2_book(self, msg: dict, timestamp: float):
@@ -187,6 +197,7 @@ class GateioFutures(Gateio):
187
197
  "s": "BTC_USD", symbol
188
198
  "U": 2517661101, start of update seq no
189
199
  "u": 2517661113, end of update seq no
200
+ "l": "100", levels per side the updates cover
190
201
  "b": [
191
202
  {
192
203
  "p": "54672.1",
@@ -210,28 +221,41 @@ class GateioFutures(Gateio):
210
221
  }
211
222
  }
212
223
  """
213
- symbol = self.exchange_symbol_to_std_symbol(msg['result']['s'])
224
+ result = msg['result']
225
+ symbol = self.exchange_symbol_to_std_symbol(result['s'])
226
+ window = int(result['l']) if result.get('l') else self.SNAPSHOT_DEPTH
227
+
228
+ if window < self.SNAPSHOT_DEPTH and not self._book_window_warned:
229
+ self._book_window_warned = True
230
+ LOG.warning('%s: %s order book updates cover the top %d levels, not the %d requested - keeping the book to %d levels', self.id, symbol, window, self.SNAPSHOT_DEPTH, window)
231
+
232
+ self._book_window[symbol] = window
233
+ if symbol in self._l2_book and self._l2_book[symbol].book.max_depth != window:
234
+ self._l2_book.pop(symbol, None)
235
+ self.last_update_id.pop(symbol, None)
236
+ self.forced[symbol] = False
214
237
  if symbol not in self._l2_book:
215
- await self._snapshot(msg['result']['s'])
238
+ await self._snapshot(result['s'])
216
239
 
217
- skip_update = self._check_update_id(symbol, msg['result'])
240
+ skip_update = self._check_update_id(symbol, result)
218
241
  if skip_update:
219
242
  return
220
243
 
221
- ts = msg['result']['t'] / 1000
244
+ ts = result['t'] / 1000
222
245
  delta = {BID: [], ASK: []}
246
+ book = self._l2_book[symbol].book
223
247
 
224
248
  for s, side in (('b', BID), ('a', ASK)):
225
- for update in msg['result'][s]:
249
+ for update in result[s]:
226
250
  price = Decimal(update["p"])
227
251
  amount = Decimal(update["s"])
228
252
 
229
253
  if amount == 0:
230
- if price in self._l2_book[symbol].book[side]:
231
- del self._l2_book[symbol].book[side][price]
254
+ if price in book[side]:
255
+ del book[side][price]
232
256
  delta[side].append((price, amount))
233
257
  else:
234
- self._l2_book[symbol].book[side][price] = amount
258
+ book[side][price] = amount
235
259
  delta[side].append((price, amount))
236
260
 
237
261
  await self.book_callback(L2_BOOK, self._l2_book[symbol], timestamp, delta=delta, timestamp=ts, raw=msg)
@@ -213,15 +213,38 @@ class KrakenFutures(Feed):
213
213
  await self.book_callback(L2_BOOK, self._l2_book[pair], timestamp, delta=delta, sequence_number=msg['seq'], raw=msg)
214
214
 
215
215
  async def _funding(self, msg: dict, pair: str, timestamp: float):
216
- if 'funding_rate' in msg:
216
+ """
217
+ {
218
+ "feed": "ticker",
219
+ "product_id": "PF_XBTUSD",
220
+ "time": 1787582328387,
221
+ "funding_rate": 1.1333053522361405,
222
+ "funding_rate_prediction": 1.4125904284706516,
223
+ "relative_funding_rate": 0.000014425483333333,
224
+ "relative_funding_rate_prediction": 0.000017720654166667,
225
+ "next_funding_rate_time": 1787583600000,
226
+ "openInterest": 2096.2634,
227
+ "markPrice": 79734.71790589426,
228
+ ...
229
+ }
230
+
231
+ funding_rate and funding_rate_prediction are absolute amounts, paid per contract per hour (quote currency
232
+ on linear contracts, base currency on inverse ones). The relative_* fields are fractional hourly rate
233
+ Kraken displays as the funding rate, so they populate rate and predicted_rate
234
+ """
235
+ if 'funding_rate' in msg or 'relative_funding_rate' in msg:
236
+ rate = msg.get('relative_funding_rate')
237
+ predicted = msg.get('relative_funding_rate_prediction', None if 'funding_rate_prediction' in msg else 0)
238
+ mark = msg.get('markPrice')
239
+
217
240
  f = Funding(
218
241
  self.id,
219
242
  pair,
220
- None,
221
- msg['funding_rate'],
243
+ Decimal(mark) if mark is not None else None,
244
+ Decimal(rate) if rate is not None else None,
222
245
  self.timestamp_normalize(msg['next_funding_rate_time']),
223
246
  self.timestamp_normalize(msg['time']),
224
- predicted_rate=msg['funding_rate_prediction'],
247
+ predicted_rate=Decimal(predicted) if predicted is not None else None,
225
248
  raw=msg
226
249
  )
227
250
  await self.callback(FUNDING, f, timestamp)
@@ -178,26 +178,33 @@ class OKX(Feed):
178
178
  },
179
179
  "data": [
180
180
  [
181
- "1597026383085", // ts
181
+ "1597026383085", // ts, opening time of this row's candle
182
182
  "8533.02", // open
183
183
  "8553.74", // high
184
184
  "8527.17", // low
185
185
  "8548.26", // close
186
- "45247", // contracts, spot/margin -> amount of base ccy, derivatives -> contracts,
187
- "529.5858061" // currency, spot/margin -> amount of quote ccy, derivatives -> amount of base ccy
186
+ "45247", // vol, spot/margin -> amount of base ccy, derivatives -> contracts
187
+ "529.5858061", // volCcy, spot/margin -> amount of quote ccy, derivatives -> amount of base ccy
188
+ "5529.5858061", // volCcyQuote, amount of quote ccy
189
+ "0" // confirm, 0 -> candle is still forming, 1 -> candle is complete
188
190
  ]
189
191
  ]
190
192
  }
191
193
  '''
192
194
  symbol = self.exchange_symbol_to_std_symbol(msg['arg']['instId'])
193
- ts = int(msg['data'][0][0]) / 1_000
195
+ interval = self.candle_interval_map[self.candle_interval]
194
196
 
195
197
  for entry in msg['data']:
198
+ closed = len(entry) > 8 and entry[8] == '1'
199
+ if self.candle_closed_only and not closed:
200
+ continue
201
+
202
+ start = int(entry[0]) / 1_000
196
203
  candle = Candle(
197
204
  self.id,
198
205
  symbol,
199
- ts,
200
- ts + self.candle_interval_map[self.candle_interval],
206
+ start,
207
+ start + interval,
201
208
  self.candle_interval,
202
209
  None,
203
210
  Decimal(entry[1]),
@@ -205,7 +212,7 @@ class OKX(Feed):
205
212
  Decimal(entry[2]),
206
213
  Decimal(entry[3]),
207
214
  Decimal(entry[5]),
208
- Decimal(entry[6]),
215
+ closed,
209
216
  timestamp,
210
217
  raw=msg
211
218
  )
@@ -1,11 +1,11 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cryptofeed
3
- Version: 3.0.0
3
+ Version: 3.0.1
4
4
  Summary: Cryptocurrency Exchange Websocket Data Feed Handler
5
5
  Author-email: Bryant Moscon <bmoscon@gmail.com>
6
6
  License-Expression: AGPL-3.0-or-later
7
7
  Project-URL: Homepage, https://github.com/bmoscon/cryptofeed
8
- Keywords: cryptocurrency,bitcoin,btc,feed handler,market feed,market data,crypto assets,Trades,Tickers,BBO,Funding,Open Interest,Liquidation,Order book,Bid,Ask,Binance,Binance Delivery,Binance Futures,Binance US,Bitfinex,bitFlyer,Bitget,Bithumb,Bitstamp,Bybit,Coinbase,Crypto.com,Deribit,Gate.io,Gate.io Futures,dYdX,Gemini,Hyperliquid,HTX,HTX Swap,Independent Reserve,Kraken,Kraken Futures,KuCoin,MEXC,OKX,Phemex,Poloniex,Upbit
8
+ Keywords: cryptocurrency,bitcoin,btc,feed handler,market feed,market data,crypto assets,Trades,Tickers,BBO,Funding,Open Interest,Liquidation,Order book,Bid,Ask,Binance,Binance Delivery,Binance Futures,Binance US,Bitfinex,bitFlyer,Bitget,Bithumb,Bitstamp,Bybit,Coinbase,Crypto.com,Deribit,Gate,Gate Futures,dYdX,Gemini,Hyperliquid,HTX,HTX Swap,Independent Reserve,Kraken,Kraken Futures,KuCoin,MEXC,OKX,Phemex,Poloniex,Upbit
9
9
  Classifier: Intended Audience :: Developers
10
10
  Classifier: Development Status :: 4 - Beta
11
11
  Classifier: Programming Language :: Python :: 3 :: Only
@@ -70,8 +70,8 @@ Handles multiple cryptocurrency exchange data feeds and returns normalized and s
70
70
  * [Coinbase](https://www.coinbase.com/)
71
71
  * [Crypto.com](https://www.crypto.com)
72
72
  * [Deribit](https://www.deribit.com/)
73
- * [Gate.io](https://www.gate.io/)
74
- * [Gate.io Futures](https://www.gate.io/futures_center)
73
+ * [Gate](https://www.gate.com/)
74
+ * [Gate Futures](https://www.gate.com/futures)
75
75
  * [dYdX v4](https://dydx.trade/)
76
76
  * [Gemini](https://gemini.com/)
77
77
  * [Hyperliquid](https://hyperliquid.xyz/)
@@ -57,8 +57,8 @@ cryptofeed/exchanges/coinbase.py
57
57
  cryptofeed/exchanges/cryptodotcom.py
58
58
  cryptofeed/exchanges/deribit.py
59
59
  cryptofeed/exchanges/dydx.py
60
- cryptofeed/exchanges/gateio.py
61
- cryptofeed/exchanges/gateio_futures.py
60
+ cryptofeed/exchanges/gate.py
61
+ cryptofeed/exchanges/gate_futures.py
62
62
  cryptofeed/exchanges/gemini.py
63
63
  cryptofeed/exchanges/htx.py
64
64
  cryptofeed/exchanges/htx_swap.py
@@ -9,7 +9,7 @@ build-backend = "setuptools.build_meta"
9
9
 
10
10
  [project]
11
11
  name = "cryptofeed"
12
- version = "3.0.0"
12
+ version = "3.0.1"
13
13
  description = "Cryptocurrency Exchange Websocket Data Feed Handler"
14
14
  readme = "README.md"
15
15
  license = "AGPL-3.0-or-later"
@@ -21,7 +21,7 @@ keywords = [
21
21
  "cryptocurrency", "bitcoin", "btc", "feed handler", "market feed", "market data", "crypto assets",
22
22
  "Trades", "Tickers", "BBO", "Funding", "Open Interest", "Liquidation", "Order book", "Bid", "Ask",
23
23
  "Binance", "Binance Delivery", "Binance Futures", "Binance US", "Bitfinex", "bitFlyer", "Bitget",
24
- "Bithumb", "Bitstamp", "Bybit", "Coinbase", "Crypto.com", "Deribit", "Gate.io", "Gate.io Futures",
24
+ "Bithumb", "Bitstamp", "Bybit", "Coinbase", "Crypto.com", "Deribit", "Gate", "Gate Futures",
25
25
  "dYdX", "Gemini", "Hyperliquid", "HTX", "HTX Swap", "Independent Reserve", "Kraken", "Kraken Futures", "KuCoin", "MEXC",
26
26
  "OKX", "Phemex", "Poloniex", "Upbit"
27
27
  ]
File without changes
File without changes
File without changes
File without changes