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.
- {cryptofeed-3.0.0 → cryptofeed-3.0.1}/CHANGES.md +7 -0
- {cryptofeed-3.0.0/cryptofeed.egg-info → cryptofeed-3.0.1}/PKG-INFO +4 -4
- {cryptofeed-3.0.0 → cryptofeed-3.0.1}/README.md +2 -2
- {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/defines.py +2 -2
- {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/exchanges/__init__.py +4 -4
- {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/exchanges/binance.py +9 -3
- {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/exchanges/binance_delivery.py +1 -0
- {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/exchanges/binance_futures.py +1 -0
- {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/exchanges/coinbase.py +9 -2
- {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/exchanges/dydx.py +7 -5
- cryptofeed-3.0.0/cryptofeed/exchanges/gateio.py → cryptofeed-3.0.1/cryptofeed/exchanges/gate.py +7 -4
- cryptofeed-3.0.0/cryptofeed/exchanges/gateio_futures.py → cryptofeed-3.0.1/cryptofeed/exchanges/gate_futures.py +39 -15
- {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/exchanges/kraken_futures.py +27 -4
- {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/exchanges/okx.py +14 -7
- {cryptofeed-3.0.0 → cryptofeed-3.0.1/cryptofeed.egg-info}/PKG-INFO +4 -4
- {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed.egg-info/SOURCES.txt +2 -2
- {cryptofeed-3.0.0 → cryptofeed-3.0.1}/pyproject.toml +2 -2
- {cryptofeed-3.0.0 → cryptofeed-3.0.1}/LICENSE +0 -0
- {cryptofeed-3.0.0 → cryptofeed-3.0.1}/MANIFEST.in +0 -0
- {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/__init__.py +0 -0
- {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/_json.py +0 -0
- {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/backends/__init__.py +0 -0
- {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/backends/_line_protocol.py +0 -0
- {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/backends/backend.py +0 -0
- {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/backends/http.py +0 -0
- {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/backends/influxdb.py +0 -0
- {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/backends/kafka.py +0 -0
- {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/backends/mongo.py +0 -0
- {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/backends/postgres.py +0 -0
- {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/backends/quest.py +0 -0
- {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/backends/redis.py +0 -0
- {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/backends/socket.py +0 -0
- {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/backends/zmq.py +0 -0
- {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/callback.py +0 -0
- {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/capture/__init__.py +0 -0
- {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/capture/_zstd.py +0 -0
- {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/capture/pcap.py +0 -0
- {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/capture/playback.py +0 -0
- {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/capture/recorder.py +0 -0
- {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/config.py +0 -0
- {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/connection.py +0 -0
- {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/connection_handler.py +0 -0
- {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/exceptions.py +0 -0
- {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/exchange.py +0 -0
- {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/exchanges/binance_us.py +0 -0
- {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/exchanges/bitfinex.py +0 -0
- {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/exchanges/bitflyer.py +0 -0
- {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/exchanges/bitget.py +0 -0
- {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/exchanges/bithumb.py +0 -0
- {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/exchanges/bitstamp.py +0 -0
- {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/exchanges/bybit.py +0 -0
- {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/exchanges/cryptodotcom.py +0 -0
- {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/exchanges/deribit.py +0 -0
- {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/exchanges/gemini.py +0 -0
- {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/exchanges/htx.py +0 -0
- {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/exchanges/htx_swap.py +0 -0
- {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/exchanges/hyperliquid.py +0 -0
- {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/exchanges/independent_reserve.py +0 -0
- {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/exchanges/kraken.py +0 -0
- {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/exchanges/kucoin.py +0 -0
- {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/exchanges/kucoin_futures.py +0 -0
- {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/exchanges/mexc.py +0 -0
- {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/exchanges/phemex.py +0 -0
- {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/exchanges/poloniex.py +0 -0
- {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/exchanges/upbit.py +0 -0
- {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/feed.py +0 -0
- {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/feedhandler.py +0 -0
- {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/log.py +0 -0
- {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/nbbo.py +0 -0
- {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/py.typed +0 -0
- {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/symbols.py +0 -0
- {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/types.pyi +0 -0
- {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/types.pyx +0 -0
- {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/util/__init__.py +0 -0
- {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed/util/time.py +0 -0
- {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed.egg-info/dependency_links.txt +0 -0
- {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed.egg-info/requires.txt +0 -0
- {cryptofeed-3.0.0 → cryptofeed-3.0.1}/cryptofeed.egg-info/top_level.txt +0 -0
- {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.
|
|
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
|
|
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
|
|
74
|
-
* [Gate
|
|
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
|
|
25
|
-
* [Gate
|
|
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
|
-
|
|
26
|
-
|
|
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 .
|
|
25
|
-
from .
|
|
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
|
-
|
|
57
|
-
|
|
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
|
-
|
|
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}))
|
cryptofeed-3.0.0/cryptofeed/exchanges/gateio.py → cryptofeed-3.0.1/cryptofeed/exchanges/gate.py
RENAMED
|
@@ -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,
|
|
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
|
|
28
|
-
id =
|
|
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":
|
|
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
|
|
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.
|
|
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
|
|
26
|
-
id =
|
|
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
|
-
|
|
171
|
-
book.
|
|
172
|
-
book.book.
|
|
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
|
-
|
|
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(
|
|
238
|
+
await self._snapshot(result['s'])
|
|
216
239
|
|
|
217
|
-
skip_update = self._check_update_id(symbol,
|
|
240
|
+
skip_update = self._check_update_id(symbol, result)
|
|
218
241
|
if skip_update:
|
|
219
242
|
return
|
|
220
243
|
|
|
221
|
-
ts =
|
|
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
|
|
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
|
|
231
|
-
del
|
|
254
|
+
if price in book[side]:
|
|
255
|
+
del book[side][price]
|
|
232
256
|
delta[side].append((price, amount))
|
|
233
257
|
else:
|
|
234
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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=
|
|
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", //
|
|
187
|
-
"529.5858061"
|
|
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
|
-
|
|
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
|
-
|
|
200
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
|
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
|
|
74
|
-
* [Gate
|
|
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/
|
|
61
|
-
cryptofeed/exchanges/
|
|
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.
|
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|