walrasquant-lib 0.5.0__tar.gz → 0.5.2__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.
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/PKG-INFO +2 -1
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/pyproject.toml +2 -1
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/base/oms.py +1 -1
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/exchange/bitget/connector.py +288 -24
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/exchange/bitget/constants.py +47 -8
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/exchange/bitget/oms.py +766 -5
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/exchange/bitget/rest_api.py +152 -3
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/exchange/bitget/schema.py +56 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/exchange/bitget/websockets.py +16 -2
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/README.md +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/__init__.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/aggregation.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/backends/__init__.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/backends/db.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/backends/db_memory.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/backends/db_postgresql.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/backends/db_sqlite.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/base/__init__.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/base/api_client.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/base/connector.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/base/ems.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/base/exchange.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/base/retry.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/base/sms.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/base/ws_client.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/config.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/constants.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/core/__init__.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/core/cache.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/core/clock.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/core/connection.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/core/entity.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/core/nautilius_core.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/core/registry.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/engine.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/error.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/exchange/__init__.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/exchange/base_factory.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/exchange/binance/__init__.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/exchange/binance/connector.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/exchange/binance/constants.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/exchange/binance/ems.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/exchange/binance/error.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/exchange/binance/exchange.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/exchange/binance/factory.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/exchange/binance/oms.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/exchange/binance/rest_api.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/exchange/binance/schema.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/exchange/binance/websockets.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/exchange/bitget/__init__.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/exchange/bitget/ems.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/exchange/bitget/error.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/exchange/bitget/exchange.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/exchange/bitget/factory.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/exchange/bybit/__init__.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/exchange/bybit/connector.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/exchange/bybit/constants.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/exchange/bybit/ems.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/exchange/bybit/error.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/exchange/bybit/exchange.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/exchange/bybit/factory.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/exchange/bybit/oms.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/exchange/bybit/rest_api.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/exchange/bybit/schema.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/exchange/bybit/websockets.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/exchange/deribit/__init__.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/exchange/deribit/connector.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/exchange/deribit/constants.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/exchange/deribit/ems.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/exchange/deribit/error.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/exchange/deribit/exchange.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/exchange/deribit/factory.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/exchange/deribit/oms.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/exchange/deribit/rest_api.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/exchange/deribit/schema.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/exchange/deribit/websockets.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/exchange/hyperliquid/__init__.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/exchange/hyperliquid/connector.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/exchange/hyperliquid/constants.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/exchange/hyperliquid/ems.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/exchange/hyperliquid/error.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/exchange/hyperliquid/exchange.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/exchange/hyperliquid/factory.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/exchange/hyperliquid/oms.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/exchange/hyperliquid/rest_api.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/exchange/hyperliquid/schema.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/exchange/hyperliquid/signing.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/exchange/hyperliquid/websockets.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/exchange/okx/__init__.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/exchange/okx/connector.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/exchange/okx/constants.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/exchange/okx/ems.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/exchange/okx/error.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/exchange/okx/exchange.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/exchange/okx/factory.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/exchange/okx/oms.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/exchange/okx/rest_api.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/exchange/okx/schema.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/exchange/okx/websockets.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/exchange/registry.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/execution/__init__.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/execution/algorithm.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/execution/algorithms/__init__.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/execution/algorithms/twap.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/execution/config.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/execution/constants.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/execution/schema.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/indicator.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/push.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/schema.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/strategy.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/tools/__init__.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/tools/pm2_wrapper.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/web/__init__.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/web/app.py +0 -0
- {walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/web/server.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: walrasquant-lib
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.2
|
|
4
4
|
Summary: fastest python trading bot
|
|
5
5
|
Author: River-Shi
|
|
6
6
|
Author-email: River-Shi <nachuan.shi.quant@gmail.com>
|
|
@@ -30,6 +30,7 @@ Requires-Dist: msgspec>=0.21.1
|
|
|
30
30
|
Requires-Dist: pandas<3.0.0
|
|
31
31
|
Requires-Dist: numpy>=2.2.0
|
|
32
32
|
Requires-Dist: ccxt>=4.5.64
|
|
33
|
+
Requires-Dist: aiofastnet>=0.21.0
|
|
33
34
|
Requires-Python: >=3.11, <3.15
|
|
34
35
|
Description-Content-Type: text/markdown
|
|
35
36
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "walrasquant-lib"
|
|
3
|
-
version = "0.5.
|
|
3
|
+
version = "0.5.2"
|
|
4
4
|
description = "fastest python trading bot"
|
|
5
5
|
authors = [
|
|
6
6
|
{name = "River-Shi",email = "nachuan.shi.quant@gmail.com"}
|
|
@@ -34,6 +34,7 @@ dependencies = [
|
|
|
34
34
|
"pandas<3.0.0",
|
|
35
35
|
"numpy>=2.2.0",
|
|
36
36
|
"ccxt>=4.5.64",
|
|
37
|
+
"aiofastnet>=0.21.0",
|
|
37
38
|
]
|
|
38
39
|
|
|
39
40
|
[project.scripts]
|
|
@@ -513,7 +513,7 @@ class OrderManagementSystem(ABC):
|
|
|
513
513
|
pass
|
|
514
514
|
|
|
515
515
|
@abstractmethod
|
|
516
|
-
async def cancel_batch_orders(self, orders: List[CancelOrderSubmit]) -> None:
|
|
516
|
+
async def cancel_batch_orders(self, orders: List[CancelOrderSubmit]) -> bool | None:
|
|
517
517
|
"""Cancel multiple orders in a single batch request"""
|
|
518
518
|
pass
|
|
519
519
|
|
{walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/exchange/bitget/connector.py
RENAMED
|
@@ -12,11 +12,11 @@ from walrasquant.schema import (
|
|
|
12
12
|
BookL1,
|
|
13
13
|
Trade,
|
|
14
14
|
Kline,
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
15
|
+
BookL2,
|
|
16
|
+
BookOrderData,
|
|
17
|
+
FundingRate,
|
|
18
|
+
IndexPrice,
|
|
19
|
+
MarkPrice,
|
|
20
20
|
KlineList,
|
|
21
21
|
Ticker,
|
|
22
22
|
)
|
|
@@ -31,6 +31,8 @@ from walrasquant.exchange.bitget.schema import (
|
|
|
31
31
|
BitgetBooks1WsMsg,
|
|
32
32
|
BitgetWsTradeWsMsg,
|
|
33
33
|
BitgetWsCandleWsMsg,
|
|
34
|
+
BitgetBooksWsMsg,
|
|
35
|
+
BitgetWsTickerWsMsg,
|
|
34
36
|
)
|
|
35
37
|
from walrasquant.exchange.bitget.rest_api import BitgetApiClient
|
|
36
38
|
from walrasquant.exchange.bitget.websockets import BitgetWSClient
|
|
@@ -48,6 +50,7 @@ from walrasquant.exchange.bitget.exchange import BitgetExchangeManager
|
|
|
48
50
|
class BitgetPublicConnector(PublicConnector):
|
|
49
51
|
_uta_inst_type_map = {
|
|
50
52
|
BitgetUtaInstType.SPOT: "spot",
|
|
53
|
+
BitgetUtaInstType.MARGIN: "spot",
|
|
51
54
|
BitgetUtaInstType.USDC_FUTURES: "linear",
|
|
52
55
|
BitgetUtaInstType.USDT_FUTURES: "linear",
|
|
53
56
|
BitgetUtaInstType.COIN_FUTURES: "inverse",
|
|
@@ -109,6 +112,9 @@ class BitgetPublicConnector(PublicConnector):
|
|
|
109
112
|
self._ws_books1_decoder = msgspec.json.Decoder(BitgetBooks1WsMsg)
|
|
110
113
|
self._ws_trade_decoder = msgspec.json.Decoder(BitgetWsTradeWsMsg)
|
|
111
114
|
self._ws_candle_decoder = msgspec.json.Decoder(BitgetWsCandleWsMsg)
|
|
115
|
+
self._ws_books_decoder = msgspec.json.Decoder(BitgetBooksWsMsg)
|
|
116
|
+
self._ws_ticker_decoder = msgspec.json.Decoder(BitgetWsTickerWsMsg)
|
|
117
|
+
self._last_kline: Dict[tuple[str, KlineInterval], Kline] = {}
|
|
112
118
|
|
|
113
119
|
def _get_inst_type(self, market: BitgetMarket):
|
|
114
120
|
if market.spot:
|
|
@@ -118,6 +124,15 @@ class BitgetPublicConnector(PublicConnector):
|
|
|
118
124
|
elif market.inverse:
|
|
119
125
|
return "coin-futures"
|
|
120
126
|
|
|
127
|
+
def _get_category(self, market: BitgetMarket) -> str:
|
|
128
|
+
if market.spot:
|
|
129
|
+
return "SPOT"
|
|
130
|
+
if market.linear:
|
|
131
|
+
return "USDT-FUTURES" if market.quote == "USDT" else "USDC-FUTURES"
|
|
132
|
+
if market.inverse:
|
|
133
|
+
return "COIN-FUTURES"
|
|
134
|
+
raise ValueError(f"Unsupported market type: {market.type}")
|
|
135
|
+
|
|
121
136
|
def _uta_inst_type_suffix(self, inst_type: BitgetUtaInstType):
|
|
122
137
|
return self._uta_inst_type_map[inst_type]
|
|
123
138
|
|
|
@@ -133,7 +148,14 @@ class BitgetPublicConnector(PublicConnector):
|
|
|
133
148
|
end_time: int | None = None,
|
|
134
149
|
) -> KlineList:
|
|
135
150
|
"""Request klines"""
|
|
136
|
-
|
|
151
|
+
return await self._request_klines(
|
|
152
|
+
symbol=symbol,
|
|
153
|
+
interval=interval,
|
|
154
|
+
kline_type="MARKET",
|
|
155
|
+
limit=limit,
|
|
156
|
+
start_time=start_time,
|
|
157
|
+
end_time=end_time,
|
|
158
|
+
)
|
|
137
159
|
|
|
138
160
|
async def request_ticker(
|
|
139
161
|
self,
|
|
@@ -144,16 +166,11 @@ class BitgetPublicConnector(PublicConnector):
|
|
|
144
166
|
if not market:
|
|
145
167
|
raise ValueError(f"Symbol is not available: {symbol}")
|
|
146
168
|
|
|
147
|
-
|
|
148
|
-
category = "SPOT"
|
|
149
|
-
elif market.linear:
|
|
150
|
-
category = "USDT-FUTURES" if market.quote == "USDT" else "USDC-FUTURES"
|
|
151
|
-
elif market.inverse:
|
|
152
|
-
category = "COIN-FUTURES"
|
|
169
|
+
category = self._get_category(market)
|
|
153
170
|
|
|
154
171
|
res = await self._api_client.get_api_v3_market_tickers(
|
|
155
172
|
category=category,
|
|
156
|
-
symbol=
|
|
173
|
+
symbol=market.id,
|
|
157
174
|
)
|
|
158
175
|
|
|
159
176
|
ticker_response = res.data[0]
|
|
@@ -174,6 +191,8 @@ class BitgetPublicConnector(PublicConnector):
|
|
|
174
191
|
) -> Dict[str, Ticker]:
|
|
175
192
|
"""Request 24hr ticker data for multiple symbols"""
|
|
176
193
|
all_tickers: Dict[str, Ticker] = {}
|
|
194
|
+
# COIN-FUTURES (inverse) is intentionally excluded from load_markets, so
|
|
195
|
+
# its tickers would all be dropped by the market_id lookup below.
|
|
177
196
|
for category in ["SPOT", "USDT-FUTURES", "USDC-FUTURES"]:
|
|
178
197
|
res = await self._api_client.get_api_v3_market_tickers(
|
|
179
198
|
category=category,
|
|
@@ -207,7 +226,118 @@ class BitgetPublicConnector(PublicConnector):
|
|
|
207
226
|
end_time: int | None = None,
|
|
208
227
|
) -> KlineList:
|
|
209
228
|
"""Request index klines"""
|
|
210
|
-
|
|
229
|
+
market = self._market.get(symbol)
|
|
230
|
+
if not market:
|
|
231
|
+
raise ValueError(f"Symbol {symbol} formated wrongly, or not supported")
|
|
232
|
+
if market.spot:
|
|
233
|
+
raise ValueError("Spot market is not supported for index klines")
|
|
234
|
+
return await self._request_klines(
|
|
235
|
+
symbol=symbol,
|
|
236
|
+
interval=interval,
|
|
237
|
+
kline_type="INDEX",
|
|
238
|
+
limit=limit,
|
|
239
|
+
start_time=start_time,
|
|
240
|
+
end_time=end_time,
|
|
241
|
+
)
|
|
242
|
+
|
|
243
|
+
async def _request_klines(
|
|
244
|
+
self,
|
|
245
|
+
*,
|
|
246
|
+
symbol: str,
|
|
247
|
+
interval: KlineInterval,
|
|
248
|
+
kline_type: str,
|
|
249
|
+
limit: int | None,
|
|
250
|
+
start_time: int | None,
|
|
251
|
+
end_time: int | None,
|
|
252
|
+
) -> KlineList:
|
|
253
|
+
market = self._market.get(symbol)
|
|
254
|
+
if not market:
|
|
255
|
+
raise ValueError(f"Symbol {symbol} formated wrongly, or not supported")
|
|
256
|
+
|
|
257
|
+
bitget_interval = BitgetEnumParser.to_bitget_kline_interval(interval)
|
|
258
|
+
all_klines: list[Kline] = []
|
|
259
|
+
seen_timestamps: set[int] = set()
|
|
260
|
+
prev_start_time: int | None = None
|
|
261
|
+
|
|
262
|
+
while True:
|
|
263
|
+
if prev_start_time is not None and prev_start_time == start_time:
|
|
264
|
+
break
|
|
265
|
+
prev_start_time = start_time
|
|
266
|
+
|
|
267
|
+
response = await self._api_client.get_api_v3_market_candles(
|
|
268
|
+
category=self._get_category(market),
|
|
269
|
+
symbol=market.id,
|
|
270
|
+
interval=bitget_interval.value,
|
|
271
|
+
type=kline_type,
|
|
272
|
+
startTime=start_time,
|
|
273
|
+
endTime=end_time,
|
|
274
|
+
limit=100,
|
|
275
|
+
)
|
|
276
|
+
response_rows = sorted(response.data, key=lambda row: int(row[0]))
|
|
277
|
+
if not response_rows:
|
|
278
|
+
break
|
|
279
|
+
|
|
280
|
+
new_klines = [
|
|
281
|
+
self._handle_candlesticks(
|
|
282
|
+
symbol=symbol,
|
|
283
|
+
interval=interval,
|
|
284
|
+
row=row,
|
|
285
|
+
timestamp=response.requestTime,
|
|
286
|
+
)
|
|
287
|
+
for row in response_rows
|
|
288
|
+
if int(row[0]) not in seen_timestamps
|
|
289
|
+
]
|
|
290
|
+
if not new_klines:
|
|
291
|
+
break
|
|
292
|
+
|
|
293
|
+
all_klines.extend(new_klines)
|
|
294
|
+
seen_timestamps.update(int(row[0]) for row in response_rows)
|
|
295
|
+
start_time = int(response_rows[-1][0]) + 1
|
|
296
|
+
if end_time is not None and start_time >= end_time:
|
|
297
|
+
break
|
|
298
|
+
|
|
299
|
+
if limit is not None and len(all_klines) > limit:
|
|
300
|
+
all_klines = all_klines[-limit:]
|
|
301
|
+
|
|
302
|
+
return KlineList(
|
|
303
|
+
all_klines,
|
|
304
|
+
fields=[
|
|
305
|
+
"timestamp",
|
|
306
|
+
"symbol",
|
|
307
|
+
"open",
|
|
308
|
+
"high",
|
|
309
|
+
"low",
|
|
310
|
+
"close",
|
|
311
|
+
"volume",
|
|
312
|
+
"quote_volume",
|
|
313
|
+
"confirm",
|
|
314
|
+
],
|
|
315
|
+
)
|
|
316
|
+
|
|
317
|
+
def _handle_candlesticks(
|
|
318
|
+
self,
|
|
319
|
+
*,
|
|
320
|
+
symbol: str,
|
|
321
|
+
interval: KlineInterval,
|
|
322
|
+
row: List[str],
|
|
323
|
+
timestamp: int,
|
|
324
|
+
) -> Kline:
|
|
325
|
+
start = int(row[0])
|
|
326
|
+
confirm = self._clock.timestamp_ms() >= start + interval.seconds * 1000 - 1
|
|
327
|
+
return Kline(
|
|
328
|
+
exchange=self._exchange_id,
|
|
329
|
+
symbol=symbol,
|
|
330
|
+
interval=interval,
|
|
331
|
+
open=float(row[1]),
|
|
332
|
+
high=float(row[2]),
|
|
333
|
+
low=float(row[3]),
|
|
334
|
+
close=float(row[4]),
|
|
335
|
+
volume=float(row[5]),
|
|
336
|
+
quote_volume=float(row[6]),
|
|
337
|
+
start=start,
|
|
338
|
+
timestamp=timestamp,
|
|
339
|
+
confirm=confirm,
|
|
340
|
+
)
|
|
211
341
|
|
|
212
342
|
def _ws_msg_handler(self, raw: bytes):
|
|
213
343
|
"""Handle incoming WebSocket messages"""
|
|
@@ -224,10 +354,14 @@ class BitgetPublicConnector(PublicConnector):
|
|
|
224
354
|
elif msg.arg is not None:
|
|
225
355
|
if msg.arg.topic == "books1":
|
|
226
356
|
self._handle_books1_data(raw, msg.arg)
|
|
357
|
+
elif msg.arg.topic in ("books5", "books50"):
|
|
358
|
+
self._handle_books_data(raw, msg.arg)
|
|
227
359
|
elif msg.arg.topic == "publicTrade":
|
|
228
360
|
self._handle_trade_data(raw, msg.arg)
|
|
229
361
|
elif msg.arg.topic == "kline":
|
|
230
362
|
self._handle_candle_data(raw, msg.arg)
|
|
363
|
+
elif msg.arg.topic == "ticker":
|
|
364
|
+
self._handle_ticker_data(raw, msg.arg)
|
|
231
365
|
|
|
232
366
|
# print(f"Received WebSocket message: {raw}")
|
|
233
367
|
except msgspec.DecodeError as e:
|
|
@@ -251,6 +385,12 @@ class BitgetPublicConnector(PublicConnector):
|
|
|
251
385
|
BitgetKlineInterval(arg.interval)
|
|
252
386
|
)
|
|
253
387
|
for data in msg.data:
|
|
388
|
+
key = (symbol, interval)
|
|
389
|
+
cached = self._last_kline.get(key)
|
|
390
|
+
if cached is not None and int(data.start) > cached.start:
|
|
391
|
+
self._msgbus.publish(
|
|
392
|
+
topic="kline", msg=msgspec.structs.replace(cached, confirm=True)
|
|
393
|
+
)
|
|
254
394
|
kline = Kline(
|
|
255
395
|
exchange=self._exchange_id,
|
|
256
396
|
symbol=symbol,
|
|
@@ -263,10 +403,11 @@ class BitgetPublicConnector(PublicConnector):
|
|
|
263
403
|
start=int(data.start),
|
|
264
404
|
timestamp=self._clock.timestamp_ms(),
|
|
265
405
|
interval=interval,
|
|
266
|
-
confirm=False,
|
|
406
|
+
confirm=False,
|
|
267
407
|
)
|
|
268
408
|
self._msgbus.publish(topic="kline", msg=kline)
|
|
269
|
-
|
|
409
|
+
if cached is None or kline.start >= cached.start:
|
|
410
|
+
self._last_kline[key] = kline
|
|
270
411
|
|
|
271
412
|
def _handle_trade_data(self, raw: bytes, arg: BitgetWsUtaArgMsg):
|
|
272
413
|
msg = self._ws_trade_decoder.decode(raw)
|
|
@@ -302,6 +443,68 @@ class BitgetPublicConnector(PublicConnector):
|
|
|
302
443
|
self._msgbus.publish(topic="bookl1", msg=bookl1)
|
|
303
444
|
# self._log.debug(f"BookL1 update: {str(bookl1)}")
|
|
304
445
|
|
|
446
|
+
def _handle_books_data(self, raw: bytes, arg: BitgetWsUtaArgMsg):
|
|
447
|
+
msg = self._ws_books_decoder.decode(raw)
|
|
448
|
+
sym_id = f"{arg.symbol}_{self._uta_inst_type_suffix(arg.instType)}"
|
|
449
|
+
symbol = self._market_id[sym_id]
|
|
450
|
+
for data in msg.data:
|
|
451
|
+
bids = [
|
|
452
|
+
BookOrderData(price=float(book.px), size=float(book.sz))
|
|
453
|
+
for book in data.b
|
|
454
|
+
] or [BookOrderData(price=0, size=0)]
|
|
455
|
+
asks = [
|
|
456
|
+
BookOrderData(price=float(book.px), size=float(book.sz))
|
|
457
|
+
for book in data.a
|
|
458
|
+
] or [BookOrderData(price=0, size=0)]
|
|
459
|
+
self._msgbus.publish(
|
|
460
|
+
topic="bookl2",
|
|
461
|
+
msg=BookL2(
|
|
462
|
+
exchange=self._exchange_id,
|
|
463
|
+
symbol=symbol,
|
|
464
|
+
bids=bids,
|
|
465
|
+
asks=asks,
|
|
466
|
+
timestamp=int(data.ts),
|
|
467
|
+
),
|
|
468
|
+
)
|
|
469
|
+
|
|
470
|
+
def _handle_ticker_data(self, raw: bytes, arg: BitgetWsUtaArgMsg):
|
|
471
|
+
msg = self._ws_ticker_decoder.decode(raw)
|
|
472
|
+
sym_id = f"{arg.symbol}_{self._uta_inst_type_suffix(arg.instType)}"
|
|
473
|
+
symbol = self._market_id[sym_id]
|
|
474
|
+
timestamp = int(msg.ts) if msg.ts is not None else self._clock.timestamp_ms()
|
|
475
|
+
for data in msg.data:
|
|
476
|
+
if data.fundingRate is not None and data.nextFundingTime is not None:
|
|
477
|
+
self._msgbus.publish(
|
|
478
|
+
topic="funding_rate",
|
|
479
|
+
msg=FundingRate(
|
|
480
|
+
exchange=self._exchange_id,
|
|
481
|
+
symbol=symbol,
|
|
482
|
+
rate=float(data.fundingRate),
|
|
483
|
+
next_funding_time=int(data.nextFundingTime),
|
|
484
|
+
timestamp=timestamp,
|
|
485
|
+
),
|
|
486
|
+
)
|
|
487
|
+
if data.indexPrice is not None:
|
|
488
|
+
self._msgbus.publish(
|
|
489
|
+
topic="index_price",
|
|
490
|
+
msg=IndexPrice(
|
|
491
|
+
exchange=self._exchange_id,
|
|
492
|
+
symbol=symbol,
|
|
493
|
+
price=float(data.indexPrice),
|
|
494
|
+
timestamp=timestamp,
|
|
495
|
+
),
|
|
496
|
+
)
|
|
497
|
+
if data.markPrice is not None:
|
|
498
|
+
self._msgbus.publish(
|
|
499
|
+
topic="mark_price",
|
|
500
|
+
msg=MarkPrice(
|
|
501
|
+
exchange=self._exchange_id,
|
|
502
|
+
symbol=symbol,
|
|
503
|
+
price=float(data.markPrice),
|
|
504
|
+
timestamp=timestamp,
|
|
505
|
+
),
|
|
506
|
+
)
|
|
507
|
+
|
|
305
508
|
def subscribe_bookl1(self, symbol: str | List[str]):
|
|
306
509
|
symbol = symbol if isinstance(symbol, list) else [symbol]
|
|
307
510
|
symbols_by_inst_type = {}
|
|
@@ -408,35 +611,92 @@ class BitgetPublicConnector(PublicConnector):
|
|
|
408
611
|
|
|
409
612
|
def subscribe_bookl2(self, symbol: str | List[str], level: BookLevel):
|
|
410
613
|
"""Subscribe to the bookl2 data"""
|
|
411
|
-
|
|
614
|
+
topic_by_level = {BookLevel.L5: "books5", BookLevel.L50: "books50"}
|
|
615
|
+
topic = topic_by_level.get(level)
|
|
616
|
+
if topic is None:
|
|
617
|
+
raise ValueError(
|
|
618
|
+
f"Unsupported book level for Bitget: {level}. Use L5 or L50."
|
|
619
|
+
)
|
|
620
|
+
symbol = symbol if isinstance(symbol, list) else [symbol]
|
|
621
|
+
symbols_by_inst_type: Dict[str, List[str]] = {}
|
|
622
|
+
for sym in symbol:
|
|
623
|
+
market = self._market.get(sym)
|
|
624
|
+
if not market:
|
|
625
|
+
raise ValueError(f"Symbol {sym} not found in market data.")
|
|
626
|
+
symbols_by_inst_type.setdefault(self._get_inst_type(market), []).append(
|
|
627
|
+
market.id
|
|
628
|
+
)
|
|
629
|
+
for inst_type, symbols in symbols_by_inst_type.items():
|
|
630
|
+
self._ws_client.subscribe_depth_v3(symbols, inst_type, topic)
|
|
412
631
|
|
|
413
632
|
def unsubscribe_bookl2(self, symbol: str | List[str], level: BookLevel):
|
|
414
633
|
"""Unsubscribe from the bookl2 data"""
|
|
415
|
-
|
|
634
|
+
topic_by_level = {BookLevel.L5: "books5", BookLevel.L50: "books50"}
|
|
635
|
+
topic = topic_by_level.get(level)
|
|
636
|
+
if topic is None:
|
|
637
|
+
raise ValueError(
|
|
638
|
+
f"Unsupported book level for Bitget: {level}. Use L5 or L50."
|
|
639
|
+
)
|
|
640
|
+
symbol = symbol if isinstance(symbol, list) else [symbol]
|
|
641
|
+
symbols_by_inst_type: Dict[str, List[str]] = {}
|
|
642
|
+
for sym in symbol:
|
|
643
|
+
market = self._market.get(sym)
|
|
644
|
+
if not market:
|
|
645
|
+
raise ValueError(f"Symbol {sym} not found in market data.")
|
|
646
|
+
symbols_by_inst_type.setdefault(self._get_inst_type(market), []).append(
|
|
647
|
+
market.id
|
|
648
|
+
)
|
|
649
|
+
for inst_type, symbols in symbols_by_inst_type.items():
|
|
650
|
+
self._ws_client.unsubscribe_depth_v3(symbols, inst_type, topic)
|
|
651
|
+
|
|
652
|
+
def _ticker_symbols_by_inst_type(
|
|
653
|
+
self, symbol: str | List[str]
|
|
654
|
+
) -> Dict[str, List[str]]:
|
|
655
|
+
symbol = symbol if isinstance(symbol, list) else [symbol]
|
|
656
|
+
symbols_by_inst_type: Dict[str, List[str]] = {}
|
|
657
|
+
for sym in symbol:
|
|
658
|
+
market = self._market.get(sym)
|
|
659
|
+
if not market:
|
|
660
|
+
raise ValueError(f"Symbol {sym} not found in market data.")
|
|
661
|
+
if market.spot:
|
|
662
|
+
raise ValueError(
|
|
663
|
+
"Funding, index, and mark ticker subscriptions are not "
|
|
664
|
+
"supported for Bitget spot markets"
|
|
665
|
+
)
|
|
666
|
+
symbols_by_inst_type.setdefault(self._get_inst_type(market), []).append(
|
|
667
|
+
market.id
|
|
668
|
+
)
|
|
669
|
+
return symbols_by_inst_type
|
|
416
670
|
|
|
417
671
|
def subscribe_funding_rate(self, symbol: str | List[str]):
|
|
418
672
|
"""Subscribe to the funding rate data"""
|
|
419
|
-
|
|
673
|
+
for inst_type, symbols in self._ticker_symbols_by_inst_type(symbol).items():
|
|
674
|
+
self._ws_client.subscribe_ticker_v3(symbols, inst_type)
|
|
420
675
|
|
|
421
676
|
def unsubscribe_funding_rate(self, symbol: str | List[str]):
|
|
422
677
|
"""Unsubscribe from the funding rate data"""
|
|
423
|
-
|
|
678
|
+
for inst_type, symbols in self._ticker_symbols_by_inst_type(symbol).items():
|
|
679
|
+
self._ws_client.unsubscribe_ticker_v3(symbols, inst_type)
|
|
424
680
|
|
|
425
681
|
def subscribe_index_price(self, symbol: str | List[str]):
|
|
426
682
|
"""Subscribe to the index price data"""
|
|
427
|
-
|
|
683
|
+
for inst_type, symbols in self._ticker_symbols_by_inst_type(symbol).items():
|
|
684
|
+
self._ws_client.subscribe_ticker_v3(symbols, inst_type)
|
|
428
685
|
|
|
429
686
|
def unsubscribe_index_price(self, symbol: str | List[str]):
|
|
430
687
|
"""Unsubscribe from the index price data"""
|
|
431
|
-
|
|
688
|
+
for inst_type, symbols in self._ticker_symbols_by_inst_type(symbol).items():
|
|
689
|
+
self._ws_client.unsubscribe_ticker_v3(symbols, inst_type)
|
|
432
690
|
|
|
433
691
|
def subscribe_mark_price(self, symbol: str | List[str]):
|
|
434
692
|
"""Subscribe to the mark price data"""
|
|
435
|
-
|
|
693
|
+
for inst_type, symbols in self._ticker_symbols_by_inst_type(symbol).items():
|
|
694
|
+
self._ws_client.subscribe_ticker_v3(symbols, inst_type)
|
|
436
695
|
|
|
437
696
|
def unsubscribe_mark_price(self, symbol: str | List[str]):
|
|
438
697
|
"""Unsubscribe from the mark price data"""
|
|
439
|
-
|
|
698
|
+
for inst_type, symbols in self._ticker_symbols_by_inst_type(symbol).items():
|
|
699
|
+
self._ws_client.unsubscribe_ticker_v3(symbols, inst_type)
|
|
440
700
|
|
|
441
701
|
|
|
442
702
|
class BitgetPrivateConnector(PrivateConnector):
|
|
@@ -508,6 +768,10 @@ class BitgetPrivateConnector(PrivateConnector):
|
|
|
508
768
|
|
|
509
769
|
async def connect(self):
|
|
510
770
|
if self._account_type.is_uta:
|
|
771
|
+
self._log.warning(
|
|
772
|
+
"Bitget UTA private trading support is beta and under development; "
|
|
773
|
+
"use classic SPOT/FUTURE accounts for stable trading workflows."
|
|
774
|
+
)
|
|
511
775
|
self._oms._ws_client.subscribe_v3_order()
|
|
512
776
|
self._oms._ws_client.subscribe_v3_position()
|
|
513
777
|
self._oms._ws_client.subscribe_v3_account()
|
{walrasquant_lib-0.5.0 → walrasquant_lib-0.5.2}/src/walrasquant/exchange/bitget/constants.py
RENAMED
|
@@ -10,6 +10,7 @@ from walrasquant.constants import (
|
|
|
10
10
|
OrderType,
|
|
11
11
|
KlineInterval,
|
|
12
12
|
RateLimiter,
|
|
13
|
+
TriggerType,
|
|
13
14
|
)
|
|
14
15
|
from walrasquant.error import KlineSupportedError
|
|
15
16
|
from walrasquant.exchange.bitget.error import BitgetRateLimitError
|
|
@@ -95,6 +96,7 @@ class BitgetInstType(Enum):
|
|
|
95
96
|
|
|
96
97
|
class BitgetUtaInstType(Enum):
|
|
97
98
|
SPOT = "spot"
|
|
99
|
+
MARGIN = "margin"
|
|
98
100
|
USDT_FUTURES = "usdt-futures"
|
|
99
101
|
COIN_FUTURES = "coin-futures"
|
|
100
102
|
USDC_FUTURES = "usdc-futures"
|
|
@@ -102,31 +104,39 @@ class BitgetUtaInstType(Enum):
|
|
|
102
104
|
|
|
103
105
|
@property
|
|
104
106
|
def is_spot(self) -> bool:
|
|
105
|
-
return self ==
|
|
107
|
+
return self == BitgetUtaInstType.SPOT
|
|
106
108
|
|
|
107
109
|
@property
|
|
108
110
|
def is_swap(self) -> bool:
|
|
109
|
-
return
|
|
111
|
+
return self in (
|
|
112
|
+
BitgetUtaInstType.USDT_FUTURES,
|
|
113
|
+
BitgetUtaInstType.USDC_FUTURES,
|
|
114
|
+
BitgetUtaInstType.COIN_FUTURES,
|
|
115
|
+
)
|
|
110
116
|
|
|
111
117
|
@property
|
|
112
118
|
def is_linear(self) -> bool:
|
|
113
|
-
return self in (
|
|
119
|
+
return self in (
|
|
120
|
+
BitgetUtaInstType.USDT_FUTURES,
|
|
121
|
+
BitgetUtaInstType.USDC_FUTURES,
|
|
122
|
+
)
|
|
114
123
|
|
|
115
124
|
@property
|
|
116
125
|
def is_inverse(self) -> bool:
|
|
117
|
-
return self ==
|
|
126
|
+
return self == BitgetUtaInstType.COIN_FUTURES
|
|
118
127
|
|
|
119
128
|
@property
|
|
120
129
|
def is_usdc_swap(self) -> bool:
|
|
121
|
-
return self ==
|
|
130
|
+
return self == BitgetUtaInstType.USDC_FUTURES
|
|
122
131
|
|
|
123
132
|
@property
|
|
124
133
|
def is_usdt_swap(self) -> bool:
|
|
125
|
-
return self ==
|
|
134
|
+
return self == BitgetUtaInstType.USDT_FUTURES
|
|
126
135
|
|
|
127
136
|
|
|
128
137
|
class BitgetKlineInterval(Enum):
|
|
129
138
|
MINUTE_1 = "1m"
|
|
139
|
+
MINUTE_3 = "3m"
|
|
130
140
|
MINUTE_5 = "5m"
|
|
131
141
|
MINUTE_15 = "15m"
|
|
132
142
|
MINUTE_30 = "30m"
|
|
@@ -147,7 +157,7 @@ class BitgetOrderStatus(Enum):
|
|
|
147
157
|
NEW = "new"
|
|
148
158
|
FILLED = "filled"
|
|
149
159
|
CANCELED = "canceled"
|
|
150
|
-
CANCELLED = "cancelled" #
|
|
160
|
+
CANCELLED = "cancelled" # Used by endpoints that spell canceled with two l's
|
|
151
161
|
PARTIALLY_FILLED = "partially_filled"
|
|
152
162
|
|
|
153
163
|
|
|
@@ -216,6 +226,7 @@ class BitgetPositionSide(Enum):
|
|
|
216
226
|
class BitgetEnumParser:
|
|
217
227
|
_kline_interval_map = {
|
|
218
228
|
BitgetKlineInterval.MINUTE_1: KlineInterval.MINUTE_1,
|
|
229
|
+
BitgetKlineInterval.MINUTE_3: KlineInterval.MINUTE_3,
|
|
219
230
|
BitgetKlineInterval.MINUTE_5: KlineInterval.MINUTE_5,
|
|
220
231
|
BitgetKlineInterval.MINUTE_15: KlineInterval.MINUTE_15,
|
|
221
232
|
BitgetKlineInterval.MINUTE_30: KlineInterval.MINUTE_30,
|
|
@@ -231,7 +242,7 @@ class BitgetEnumParser:
|
|
|
231
242
|
BitgetOrderStatus.NEW: OrderStatus.ACCEPTED,
|
|
232
243
|
BitgetOrderStatus.FILLED: OrderStatus.FILLED,
|
|
233
244
|
BitgetOrderStatus.CANCELED: OrderStatus.CANCELED,
|
|
234
|
-
BitgetOrderStatus.CANCELLED: OrderStatus.CANCELED,
|
|
245
|
+
BitgetOrderStatus.CANCELLED: OrderStatus.CANCELED,
|
|
235
246
|
BitgetOrderStatus.PARTIALLY_FILLED: OrderStatus.PARTIALLY_FILLED,
|
|
236
247
|
}
|
|
237
248
|
|
|
@@ -297,6 +308,14 @@ class BitgetEnumParser:
|
|
|
297
308
|
def parse_order_type(cls, order_type: BitgetOrderType) -> OrderType:
|
|
298
309
|
return cls._order_type_map[order_type]
|
|
299
310
|
|
|
311
|
+
@classmethod
|
|
312
|
+
def to_bitget_trigger_type(cls, trigger_type: TriggerType) -> str:
|
|
313
|
+
if trigger_type == TriggerType.LAST_PRICE:
|
|
314
|
+
return "market"
|
|
315
|
+
if trigger_type == TriggerType.MARK_PRICE:
|
|
316
|
+
return "mark"
|
|
317
|
+
raise ValueError(f"Unsupported Bitget trigger type: {trigger_type}")
|
|
318
|
+
|
|
300
319
|
|
|
301
320
|
class BitgetRateLimiter(RateLimiter):
|
|
302
321
|
def __init__(self, enable_rate_limit: bool = True):
|
|
@@ -332,6 +351,26 @@ class BitgetRateLimiter(RateLimiter):
|
|
|
332
351
|
timeout=-1,
|
|
333
352
|
using=RateLimiterType.FIXED_WINDOW.value,
|
|
334
353
|
),
|
|
354
|
+
"/api/v3/trade/place-batch": Throttled(
|
|
355
|
+
quota=rate_limiter.per_sec(5),
|
|
356
|
+
timeout=-1,
|
|
357
|
+
using=RateLimiterType.FIXED_WINDOW.value,
|
|
358
|
+
),
|
|
359
|
+
"/api/v3/trade/modify-order": Throttled(
|
|
360
|
+
quota=rate_limiter.per_sec(10),
|
|
361
|
+
timeout=-1,
|
|
362
|
+
using=RateLimiterType.FIXED_WINDOW.value,
|
|
363
|
+
),
|
|
364
|
+
"/api/v2/spot/trade/batch-orders": Throttled(
|
|
365
|
+
quota=rate_limiter.per_sec(5),
|
|
366
|
+
timeout=-1,
|
|
367
|
+
using=RateLimiterType.FIXED_WINDOW.value,
|
|
368
|
+
),
|
|
369
|
+
"/api/v2/mix/order/batch-place-order": Throttled(
|
|
370
|
+
quota=rate_limiter.per_sec(5),
|
|
371
|
+
timeout=-1,
|
|
372
|
+
using=RateLimiterType.FIXED_WINDOW.value,
|
|
373
|
+
),
|
|
335
374
|
"/api/v3/trade/cancel-order": Throttled(
|
|
336
375
|
quota=rate_limiter.per_sec(10),
|
|
337
376
|
timeout=-1,
|