walrasquant-lib 0.4.27__tar.gz → 0.4.28__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.4.27 → walrasquant_lib-0.4.28}/PKG-INFO +1 -1
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/pyproject.toml +1 -1
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/base/ems.py +36 -47
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/constants.py +1 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/exchange/__init__.py +2 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/exchange/bitget/ems.py +6 -37
- walrasquant_lib-0.4.28/src/walrasquant/exchange/deribit/__init__.py +26 -0
- walrasquant_lib-0.4.28/src/walrasquant/exchange/deribit/connector.py +439 -0
- walrasquant_lib-0.4.28/src/walrasquant/exchange/deribit/constants.py +112 -0
- walrasquant_lib-0.4.28/src/walrasquant/exchange/deribit/ems.py +66 -0
- walrasquant_lib-0.4.28/src/walrasquant/exchange/deribit/exchange.py +86 -0
- walrasquant_lib-0.4.28/src/walrasquant/exchange/deribit/factory.py +101 -0
- walrasquant_lib-0.4.28/src/walrasquant/exchange/deribit/oms.py +670 -0
- walrasquant_lib-0.4.28/src/walrasquant/exchange/deribit/rest_api.py +106 -0
- walrasquant_lib-0.4.28/src/walrasquant/exchange/deribit/schema.py +41 -0
- walrasquant_lib-0.4.28/src/walrasquant/exchange/deribit/websockets.py +184 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/README.md +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/__init__.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/aggregation.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/backends/__init__.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/backends/db.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/backends/db_memory.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/backends/db_postgresql.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/backends/db_sqlite.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/base/__init__.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/base/api_client.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/base/connector.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/base/exchange.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/base/oms.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/base/retry.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/base/sms.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/base/ws_client.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/config.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/core/__init__.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/core/cache.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/core/clock.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/core/connection.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/core/entity.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/core/nautilius_core.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/core/registry.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/engine.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/error.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/exchange/base_factory.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/exchange/binance/__init__.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/exchange/binance/connector.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/exchange/binance/constants.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/exchange/binance/ems.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/exchange/binance/error.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/exchange/binance/exchange.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/exchange/binance/factory.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/exchange/binance/oms.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/exchange/binance/rest_api.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/exchange/binance/schema.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/exchange/binance/websockets.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/exchange/bitget/__init__.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/exchange/bitget/connector.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/exchange/bitget/constants.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/exchange/bitget/error.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/exchange/bitget/exchange.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/exchange/bitget/factory.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/exchange/bitget/oms.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/exchange/bitget/rest_api.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/exchange/bitget/schema.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/exchange/bitget/websockets.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/exchange/bybit/__init__.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/exchange/bybit/connector.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/exchange/bybit/constants.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/exchange/bybit/ems.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/exchange/bybit/error.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/exchange/bybit/exchange.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/exchange/bybit/factory.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/exchange/bybit/oms.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/exchange/bybit/rest_api.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/exchange/bybit/schema.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/exchange/bybit/websockets.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/exchange/hyperliquid/__init__.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/exchange/hyperliquid/connector.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/exchange/hyperliquid/constants.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/exchange/hyperliquid/ems.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/exchange/hyperliquid/error.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/exchange/hyperliquid/exchange.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/exchange/hyperliquid/factory.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/exchange/hyperliquid/oms.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/exchange/hyperliquid/rest_api.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/exchange/hyperliquid/schema.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/exchange/hyperliquid/signing.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/exchange/hyperliquid/websockets.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/exchange/okx/__init__.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/exchange/okx/connector.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/exchange/okx/constants.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/exchange/okx/ems.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/exchange/okx/error.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/exchange/okx/exchange.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/exchange/okx/factory.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/exchange/okx/oms.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/exchange/okx/rest_api.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/exchange/okx/schema.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/exchange/okx/websockets.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/exchange/registry.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/execution/__init__.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/execution/algorithm.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/execution/algorithms/__init__.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/execution/algorithms/twap.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/execution/config.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/execution/constants.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/execution/schema.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/indicator.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/push.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/schema.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/strategy.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/tools/__init__.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/tools/pm2_wrapper.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/web/__init__.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/web/app.py +0 -0
- {walrasquant_lib-0.4.27 → walrasquant_lib-0.4.28}/src/walrasquant/web/server.py +0 -0
|
@@ -168,6 +168,40 @@ class ExecutionManagementSystem(ABC):
|
|
|
168
168
|
self._build_order_submit_queues()
|
|
169
169
|
self._set_account_type()
|
|
170
170
|
|
|
171
|
+
@staticmethod
|
|
172
|
+
def _quantize_step(
|
|
173
|
+
value: float,
|
|
174
|
+
step: float | str,
|
|
175
|
+
mode: Literal["round", "ceil", "floor"] = "round",
|
|
176
|
+
) -> Decimal:
|
|
177
|
+
"""
|
|
178
|
+
Snap ``value`` to the nearest integer multiple of ``step``.
|
|
179
|
+
|
|
180
|
+
Unlike ``Decimal.quantize`` (which aligns to a number of decimal
|
|
181
|
+
places), this aligns to the actual step value, so it is correct for
|
|
182
|
+
arbitrary steps such as tick sizes of 0.5 or 0.2 as well as the usual
|
|
183
|
+
powers of ten. The result is normalized to the number of decimal places
|
|
184
|
+
implied by ``step`` so its string form matches decimal-place rounding
|
|
185
|
+
for power-of-ten / integer steps (no spurious trailing zeros).
|
|
186
|
+
|
|
187
|
+
``step`` arrives either as a float (ccxt ``market.precision``) or a str
|
|
188
|
+
(exchange-native tick fields); both are normalized via ``Decimal(str())``
|
|
189
|
+
to avoid binary-float error.
|
|
190
|
+
"""
|
|
191
|
+
rounding = {
|
|
192
|
+
"round": ROUND_HALF_UP,
|
|
193
|
+
"ceil": ROUND_CEILING,
|
|
194
|
+
"floor": ROUND_FLOOR,
|
|
195
|
+
}[mode]
|
|
196
|
+
value_decimal = Decimal(str(value))
|
|
197
|
+
step_decimal = Decimal(str(step))
|
|
198
|
+
multiples = (value_decimal / step_decimal).quantize(
|
|
199
|
+
Decimal("1"), rounding=rounding
|
|
200
|
+
)
|
|
201
|
+
result = multiples * step_decimal
|
|
202
|
+
ndigits = max(0, -step_decimal.normalize().as_tuple().exponent)
|
|
203
|
+
return result.quantize(Decimal(1).scaleb(-ndigits))
|
|
204
|
+
|
|
171
205
|
def _amount_to_precision(
|
|
172
206
|
self,
|
|
173
207
|
symbol: str,
|
|
@@ -178,29 +212,7 @@ class ExecutionManagementSystem(ABC):
|
|
|
178
212
|
Convert the amount to the precision of the market
|
|
179
213
|
"""
|
|
180
214
|
market = self._market[symbol]
|
|
181
|
-
|
|
182
|
-
precision = market.precision.amount
|
|
183
|
-
|
|
184
|
-
if precision >= 1:
|
|
185
|
-
exp = Decimal(int(precision))
|
|
186
|
-
precision_decimal = Decimal("1")
|
|
187
|
-
else:
|
|
188
|
-
exp = Decimal("1")
|
|
189
|
-
precision_decimal = Decimal(str(precision))
|
|
190
|
-
|
|
191
|
-
if mode == "round":
|
|
192
|
-
format_amount = (amount_decimal / exp).quantize(
|
|
193
|
-
precision_decimal, rounding=ROUND_HALF_UP
|
|
194
|
-
) * exp
|
|
195
|
-
elif mode == "ceil":
|
|
196
|
-
format_amount = (amount_decimal / exp).quantize(
|
|
197
|
-
precision_decimal, rounding=ROUND_CEILING
|
|
198
|
-
) * exp
|
|
199
|
-
elif mode == "floor":
|
|
200
|
-
format_amount = (amount_decimal / exp).quantize(
|
|
201
|
-
precision_decimal, rounding=ROUND_FLOOR
|
|
202
|
-
) * exp
|
|
203
|
-
return format_amount
|
|
215
|
+
return self._quantize_step(amount, market.precision.amount, mode)
|
|
204
216
|
|
|
205
217
|
def _price_to_precision(
|
|
206
218
|
self,
|
|
@@ -212,30 +224,7 @@ class ExecutionManagementSystem(ABC):
|
|
|
212
224
|
Convert the price to the precision of the market
|
|
213
225
|
"""
|
|
214
226
|
market = self._market[symbol]
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
decimal = market.precision.price
|
|
218
|
-
|
|
219
|
-
if decimal >= 1:
|
|
220
|
-
exp = Decimal(int(decimal))
|
|
221
|
-
precision_decimal = Decimal("1")
|
|
222
|
-
else:
|
|
223
|
-
exp = Decimal("1")
|
|
224
|
-
precision_decimal = Decimal(str(decimal))
|
|
225
|
-
|
|
226
|
-
if mode == "round":
|
|
227
|
-
format_price = (price_decimal / exp).quantize(
|
|
228
|
-
precision_decimal, rounding=ROUND_HALF_UP
|
|
229
|
-
) * exp
|
|
230
|
-
elif mode == "ceil":
|
|
231
|
-
format_price = (price_decimal / exp).quantize(
|
|
232
|
-
precision_decimal, rounding=ROUND_CEILING
|
|
233
|
-
) * exp
|
|
234
|
-
elif mode == "floor":
|
|
235
|
-
format_price = (price_decimal / exp).quantize(
|
|
236
|
-
precision_decimal, rounding=ROUND_FLOOR
|
|
237
|
-
) * exp
|
|
238
|
-
return format_price
|
|
227
|
+
return self._quantize_step(price, market.precision.price, mode)
|
|
239
228
|
|
|
240
229
|
@abstractmethod
|
|
241
230
|
def _instrument_id_to_account_type(
|
|
@@ -3,6 +3,7 @@ from walrasquant.exchange.bybit import BybitAccountType
|
|
|
3
3
|
from walrasquant.exchange.okx import OkxAccountType
|
|
4
4
|
from walrasquant.exchange.hyperliquid import HyperLiquidAccountType
|
|
5
5
|
from walrasquant.exchange.bitget import BitgetAccountType
|
|
6
|
+
from walrasquant.exchange.deribit import DeribitAccountType
|
|
6
7
|
|
|
7
8
|
__all__ = [
|
|
8
9
|
"BinanceAccountType",
|
|
@@ -10,4 +11,5 @@ __all__ = [
|
|
|
10
11
|
"OkxAccountType",
|
|
11
12
|
"HyperLiquidAccountType",
|
|
12
13
|
"BitgetAccountType",
|
|
14
|
+
"DeribitAccountType",
|
|
13
15
|
]
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
from typing import Dict, cast
|
|
2
2
|
from decimal import Decimal
|
|
3
3
|
from typing import Literal
|
|
4
|
-
from decimal import ROUND_HALF_UP, ROUND_CEILING, ROUND_FLOOR
|
|
5
4
|
|
|
6
5
|
from walrasquant.constants import AccountType
|
|
7
6
|
from walrasquant.schema import (
|
|
@@ -124,26 +123,11 @@ class BitgetExecutionManagementSystem(ExecutionManagementSystem):
|
|
|
124
123
|
mode: Literal["round", "ceil", "floor"] = "round",
|
|
125
124
|
) -> Decimal:
|
|
126
125
|
market = self._market[symbol]
|
|
126
|
+
# Spot amount precision is a plain ccxt step handled by the base class;
|
|
127
|
+
# derivatives quantize to the contract sizeMultiplier.
|
|
127
128
|
if market.spot:
|
|
128
129
|
return super()._amount_to_precision(symbol, amount, mode)
|
|
129
|
-
|
|
130
|
-
amount: Decimal = Decimal(str(amount))
|
|
131
|
-
amount_multiplier = Decimal(market.info.sizeMultiplier or "1")
|
|
132
|
-
multiplier_count = amount / amount_multiplier
|
|
133
|
-
|
|
134
|
-
if mode == "round":
|
|
135
|
-
amount = (
|
|
136
|
-
multiplier_count.quantize(Decimal("1"), rounding=ROUND_HALF_UP)
|
|
137
|
-
) * amount_multiplier
|
|
138
|
-
elif mode == "ceil":
|
|
139
|
-
amount = (
|
|
140
|
-
multiplier_count.quantize(Decimal("1"), rounding=ROUND_CEILING)
|
|
141
|
-
) * amount_multiplier
|
|
142
|
-
elif mode == "floor":
|
|
143
|
-
amount = (
|
|
144
|
-
multiplier_count.quantize(Decimal("1"), rounding=ROUND_FLOOR)
|
|
145
|
-
) * amount_multiplier
|
|
146
|
-
return amount
|
|
130
|
+
return self._quantize_step(amount, market.info.sizeMultiplier or "1", mode)
|
|
147
131
|
|
|
148
132
|
def _price_to_precision(
|
|
149
133
|
self,
|
|
@@ -152,26 +136,11 @@ class BitgetExecutionManagementSystem(ExecutionManagementSystem):
|
|
|
152
136
|
mode: Literal["round", "ceil", "floor"] = "round",
|
|
153
137
|
) -> Decimal:
|
|
154
138
|
market = self._market[symbol]
|
|
139
|
+
# Spot price precision is a plain ccxt step handled by the base class;
|
|
140
|
+
# derivatives quantize to the priceEndStep tick.
|
|
155
141
|
if market.spot:
|
|
156
142
|
return super()._price_to_precision(symbol, price, mode)
|
|
157
|
-
|
|
158
|
-
price: Decimal = Decimal(str(price))
|
|
159
|
-
price_multiplier = Decimal(market.info.priceEndStep or "1")
|
|
160
|
-
multiplier_count = price / price_multiplier
|
|
161
|
-
|
|
162
|
-
if mode == "round":
|
|
163
|
-
price = (
|
|
164
|
-
multiplier_count.quantize(Decimal("1"), rounding=ROUND_HALF_UP)
|
|
165
|
-
) * price_multiplier
|
|
166
|
-
elif mode == "ceil":
|
|
167
|
-
price = (
|
|
168
|
-
multiplier_count.quantize(Decimal("1"), rounding=ROUND_CEILING)
|
|
169
|
-
) * price_multiplier
|
|
170
|
-
elif mode == "floor":
|
|
171
|
-
price = (
|
|
172
|
-
multiplier_count.quantize(Decimal("1"), rounding=ROUND_FLOOR)
|
|
173
|
-
) * price_multiplier
|
|
174
|
-
return price
|
|
143
|
+
return self._quantize_step(price, market.info.priceEndStep or "1", mode)
|
|
175
144
|
|
|
176
145
|
async def _cancel_all_orders(
|
|
177
146
|
self, order_submit: CancelAllOrderSubmit, account_type: AccountType
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
from walrasquant.exchange.deribit.constants import DeribitAccountType
|
|
2
|
+
from walrasquant.exchange.deribit.connector import (
|
|
3
|
+
DeribitPrivateConnector,
|
|
4
|
+
DeribitPublicConnector,
|
|
5
|
+
)
|
|
6
|
+
from walrasquant.exchange.deribit.ems import DeribitExecutionManagementSystem
|
|
7
|
+
from walrasquant.exchange.deribit.exchange import DeribitExchangeManager
|
|
8
|
+
from walrasquant.exchange.deribit.factory import DeribitFactory
|
|
9
|
+
from walrasquant.exchange.deribit.oms import DeribitOrderManagementSystem
|
|
10
|
+
|
|
11
|
+
try:
|
|
12
|
+
from walrasquant.exchange.registry import register_factory
|
|
13
|
+
|
|
14
|
+
register_factory(DeribitFactory())
|
|
15
|
+
except ImportError:
|
|
16
|
+
pass
|
|
17
|
+
|
|
18
|
+
__all__ = [
|
|
19
|
+
"DeribitAccountType",
|
|
20
|
+
"DeribitExchangeManager",
|
|
21
|
+
"DeribitPublicConnector",
|
|
22
|
+
"DeribitPrivateConnector",
|
|
23
|
+
"DeribitOrderManagementSystem",
|
|
24
|
+
"DeribitExecutionManagementSystem",
|
|
25
|
+
"DeribitFactory",
|
|
26
|
+
]
|
|
@@ -0,0 +1,439 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any, cast
|
|
4
|
+
|
|
5
|
+
import msgspec
|
|
6
|
+
|
|
7
|
+
from walrasquant.base import PrivateConnector, PublicConnector
|
|
8
|
+
from walrasquant.config import OrderQueryConfig
|
|
9
|
+
from walrasquant.constants import BookLevel, KlineInterval
|
|
10
|
+
from walrasquant.core.cache import AsyncCache
|
|
11
|
+
from walrasquant.core.entity import TaskManager
|
|
12
|
+
from walrasquant.core.nautilius_core import LiveClock, MessageBus
|
|
13
|
+
from walrasquant.core.registry import OrderRegistry
|
|
14
|
+
from walrasquant.exchange.deribit.constants import (
|
|
15
|
+
DeribitAccountType,
|
|
16
|
+
DeribitEnumParser,
|
|
17
|
+
)
|
|
18
|
+
from walrasquant.exchange.deribit.exchange import DeribitExchangeManager
|
|
19
|
+
from walrasquant.exchange.deribit.oms import DeribitOrderManagementSystem
|
|
20
|
+
from walrasquant.exchange.deribit.rest_api import DeribitApiClient
|
|
21
|
+
from walrasquant.exchange.deribit.websockets import DeribitWSClient
|
|
22
|
+
from walrasquant.schema import (
|
|
23
|
+
BookL1,
|
|
24
|
+
BookL2,
|
|
25
|
+
BookOrderData,
|
|
26
|
+
IndexPrice,
|
|
27
|
+
Kline,
|
|
28
|
+
KlineList,
|
|
29
|
+
MarkPrice,
|
|
30
|
+
Ticker,
|
|
31
|
+
Trade,
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class DeribitPublicConnector(PublicConnector):
|
|
36
|
+
_ws_client: DeribitWSClient
|
|
37
|
+
_api_client: DeribitApiClient
|
|
38
|
+
|
|
39
|
+
def __init__(
|
|
40
|
+
self,
|
|
41
|
+
account_type: DeribitAccountType,
|
|
42
|
+
exchange: DeribitExchangeManager,
|
|
43
|
+
msgbus: MessageBus,
|
|
44
|
+
clock: LiveClock,
|
|
45
|
+
task_manager: TaskManager,
|
|
46
|
+
custom_url: str | None = None,
|
|
47
|
+
max_subscriptions_per_client: int | None = None,
|
|
48
|
+
max_clients: int | None = None,
|
|
49
|
+
**_: Any,
|
|
50
|
+
):
|
|
51
|
+
super().__init__(
|
|
52
|
+
account_type=account_type,
|
|
53
|
+
market=exchange.market,
|
|
54
|
+
market_id=exchange.market_id,
|
|
55
|
+
exchange_id=exchange.exchange_id,
|
|
56
|
+
ws_client=DeribitWSClient(
|
|
57
|
+
account_type=account_type,
|
|
58
|
+
handler=self._ws_msg_handler,
|
|
59
|
+
task_manager=task_manager,
|
|
60
|
+
clock=clock,
|
|
61
|
+
custom_url=custom_url,
|
|
62
|
+
max_subscriptions_per_client=max_subscriptions_per_client,
|
|
63
|
+
max_clients=max_clients,
|
|
64
|
+
),
|
|
65
|
+
msgbus=msgbus,
|
|
66
|
+
clock=clock,
|
|
67
|
+
api_client=DeribitApiClient(clock=clock, account_type=account_type),
|
|
68
|
+
task_manager=task_manager,
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
def _symbols(self, symbol: str | list[str]) -> list[tuple[str, str]]:
|
|
72
|
+
requested = [symbol] if isinstance(symbol, str) else symbol
|
|
73
|
+
result = []
|
|
74
|
+
for item in requested:
|
|
75
|
+
market = self._market.get(item)
|
|
76
|
+
if market is None:
|
|
77
|
+
raise ValueError(f"Unsupported Deribit symbol: {item}")
|
|
78
|
+
result.append((item, market.id))
|
|
79
|
+
return result
|
|
80
|
+
|
|
81
|
+
def _ws_msg_handler(self, raw: bytes) -> None:
|
|
82
|
+
try:
|
|
83
|
+
message = msgspec.json.decode(raw)
|
|
84
|
+
params = message.get("params", {})
|
|
85
|
+
channel = params.get("channel", "")
|
|
86
|
+
data = params.get("data")
|
|
87
|
+
if channel.startswith("trades."):
|
|
88
|
+
self._handle_trades(data)
|
|
89
|
+
elif channel.startswith("book."):
|
|
90
|
+
self._handle_book(channel, data)
|
|
91
|
+
elif channel.startswith("chart.trades."):
|
|
92
|
+
self._handle_kline(channel, data)
|
|
93
|
+
elif channel.startswith("ticker."):
|
|
94
|
+
self._handle_ticker(data)
|
|
95
|
+
except (KeyError, TypeError, ValueError, msgspec.DecodeError) as exc:
|
|
96
|
+
self._log.error(
|
|
97
|
+
"Error handling Deribit websocket message: %s: %s", raw, exc
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
def _handle_trades(self, data: list[dict[str, Any]]) -> None:
|
|
101
|
+
for item in data:
|
|
102
|
+
symbol = self._market_id[item["instrument_name"]]
|
|
103
|
+
self._msgbus.publish(
|
|
104
|
+
topic="trade",
|
|
105
|
+
msg=Trade(
|
|
106
|
+
exchange=self._exchange_id,
|
|
107
|
+
symbol=symbol,
|
|
108
|
+
side=DeribitEnumParser.parse_direction(item["direction"]),
|
|
109
|
+
price=float(item["price"]),
|
|
110
|
+
size=float(item["amount"]),
|
|
111
|
+
timestamp=int(item["timestamp"]),
|
|
112
|
+
),
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
def _handle_book(self, channel: str, data: dict[str, Any]) -> None:
|
|
116
|
+
symbol = self._market_id[data["instrument_name"]]
|
|
117
|
+
bids = [
|
|
118
|
+
BookOrderData(price=float(px), size=float(size))
|
|
119
|
+
for px, size in data["bids"]
|
|
120
|
+
]
|
|
121
|
+
asks = [
|
|
122
|
+
BookOrderData(price=float(px), size=float(size))
|
|
123
|
+
for px, size in data["asks"]
|
|
124
|
+
]
|
|
125
|
+
timestamp = int(data["timestamp"])
|
|
126
|
+
depth = int(channel.split(".")[-2])
|
|
127
|
+
if depth == 1:
|
|
128
|
+
if not bids or not asks:
|
|
129
|
+
return
|
|
130
|
+
self._msgbus.publish(
|
|
131
|
+
topic="bookl1",
|
|
132
|
+
msg=BookL1(
|
|
133
|
+
exchange=self._exchange_id,
|
|
134
|
+
symbol=symbol,
|
|
135
|
+
bid=bids[0].price,
|
|
136
|
+
ask=asks[0].price,
|
|
137
|
+
bid_size=bids[0].size,
|
|
138
|
+
ask_size=asks[0].size,
|
|
139
|
+
timestamp=timestamp,
|
|
140
|
+
),
|
|
141
|
+
)
|
|
142
|
+
else:
|
|
143
|
+
self._msgbus.publish(
|
|
144
|
+
topic="bookl2",
|
|
145
|
+
msg=BookL2(
|
|
146
|
+
exchange=self._exchange_id,
|
|
147
|
+
symbol=symbol,
|
|
148
|
+
bids=bids,
|
|
149
|
+
asks=asks,
|
|
150
|
+
timestamp=timestamp,
|
|
151
|
+
),
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
def _handle_kline(self, channel: str, data: dict[str, Any]) -> None:
|
|
155
|
+
instrument_name = channel.split(".")[2]
|
|
156
|
+
resolution = channel.split(".")[3]
|
|
157
|
+
symbol = self._market_id[instrument_name]
|
|
158
|
+
interval = DeribitEnumParser.parse_resolution(resolution)
|
|
159
|
+
start = int(data["tick"])
|
|
160
|
+
self._msgbus.publish(
|
|
161
|
+
topic="kline",
|
|
162
|
+
msg=Kline(
|
|
163
|
+
exchange=self._exchange_id,
|
|
164
|
+
symbol=symbol,
|
|
165
|
+
interval=interval,
|
|
166
|
+
open=float(data["open"]),
|
|
167
|
+
high=float(data["high"]),
|
|
168
|
+
low=float(data["low"]),
|
|
169
|
+
close=float(data["close"]),
|
|
170
|
+
volume=float(data["volume"]),
|
|
171
|
+
start=start,
|
|
172
|
+
timestamp=self._clock.timestamp_ms(),
|
|
173
|
+
confirm=self._clock.timestamp_ms() >= start + interval.milliseconds,
|
|
174
|
+
),
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
def _handle_ticker(self, data: dict[str, Any]) -> None:
|
|
178
|
+
symbol = self._market_id[data["instrument_name"]]
|
|
179
|
+
timestamp = int(data["timestamp"])
|
|
180
|
+
mark_price = data.get("mark_price")
|
|
181
|
+
index_price = data.get("index_price")
|
|
182
|
+
if mark_price is not None:
|
|
183
|
+
self._msgbus.publish(
|
|
184
|
+
topic="mark_price",
|
|
185
|
+
msg=MarkPrice(
|
|
186
|
+
exchange=self._exchange_id,
|
|
187
|
+
symbol=symbol,
|
|
188
|
+
price=float(mark_price),
|
|
189
|
+
timestamp=timestamp,
|
|
190
|
+
),
|
|
191
|
+
)
|
|
192
|
+
if index_price is not None:
|
|
193
|
+
self._msgbus.publish(
|
|
194
|
+
topic="index_price",
|
|
195
|
+
msg=IndexPrice(
|
|
196
|
+
exchange=self._exchange_id,
|
|
197
|
+
symbol=symbol,
|
|
198
|
+
price=float(index_price),
|
|
199
|
+
timestamp=timestamp,
|
|
200
|
+
),
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
async def request_ticker(self, symbol: str) -> Ticker:
|
|
204
|
+
market = self._market.get(symbol)
|
|
205
|
+
if market is None:
|
|
206
|
+
raise ValueError(f"Unsupported Deribit symbol: {symbol}")
|
|
207
|
+
result = await self._api_client.get_book_summary_by_instrument(market.id)
|
|
208
|
+
if not result:
|
|
209
|
+
raise ValueError(f"No Deribit ticker data for {symbol}")
|
|
210
|
+
data = result[0]
|
|
211
|
+
return Ticker(
|
|
212
|
+
exchange=self._exchange_id,
|
|
213
|
+
symbol=symbol,
|
|
214
|
+
last_price=float(data.get("last") or 0),
|
|
215
|
+
timestamp=int(data["creation_timestamp"]),
|
|
216
|
+
volume=float(data.get("volume") or 0),
|
|
217
|
+
volumeCcy=float(
|
|
218
|
+
(data.get("volume") if market.inverse else data.get("volume_notional"))
|
|
219
|
+
or 0
|
|
220
|
+
),
|
|
221
|
+
)
|
|
222
|
+
|
|
223
|
+
async def request_all_tickers(self) -> dict[str, Ticker]:
|
|
224
|
+
currencies = {market.base for market in self._market.values()}
|
|
225
|
+
result: dict[str, Ticker] = {}
|
|
226
|
+
timestamp = self._clock.timestamp_ms()
|
|
227
|
+
for currency in currencies:
|
|
228
|
+
for item in await self._api_client.get_book_summary_by_currency(currency):
|
|
229
|
+
symbol = self._market_id.get(item["instrument_name"])
|
|
230
|
+
if symbol is None:
|
|
231
|
+
continue
|
|
232
|
+
result[symbol] = Ticker(
|
|
233
|
+
exchange=self._exchange_id,
|
|
234
|
+
symbol=symbol,
|
|
235
|
+
last_price=float(item.get("last") or 0),
|
|
236
|
+
timestamp=timestamp,
|
|
237
|
+
volume=float(item.get("volume") or 0),
|
|
238
|
+
volumeCcy=float(
|
|
239
|
+
(
|
|
240
|
+
item.get("volume")
|
|
241
|
+
if self._market[symbol].inverse
|
|
242
|
+
else item.get("volume_notional")
|
|
243
|
+
)
|
|
244
|
+
or 0
|
|
245
|
+
),
|
|
246
|
+
)
|
|
247
|
+
return result
|
|
248
|
+
|
|
249
|
+
async def request_klines(
|
|
250
|
+
self,
|
|
251
|
+
symbol: str,
|
|
252
|
+
interval: KlineInterval,
|
|
253
|
+
limit: int | None = None,
|
|
254
|
+
start_time: int | None = None,
|
|
255
|
+
end_time: int | None = None,
|
|
256
|
+
) -> KlineList:
|
|
257
|
+
market = self._market.get(symbol)
|
|
258
|
+
if market is None:
|
|
259
|
+
raise ValueError(f"Unsupported Deribit symbol: {symbol}")
|
|
260
|
+
end = end_time or self._clock.timestamp_ms()
|
|
261
|
+
count = limit or 1000
|
|
262
|
+
start = (
|
|
263
|
+
start_time
|
|
264
|
+
if start_time is not None
|
|
265
|
+
else end - count * interval.milliseconds
|
|
266
|
+
)
|
|
267
|
+
data = await self._api_client.get_chart_data(
|
|
268
|
+
market.id, DeribitEnumParser.to_resolution(interval), start, end
|
|
269
|
+
)
|
|
270
|
+
klines = []
|
|
271
|
+
for index, tick in enumerate(data.get("ticks", [])):
|
|
272
|
+
klines.append(
|
|
273
|
+
Kline(
|
|
274
|
+
exchange=self._exchange_id,
|
|
275
|
+
symbol=symbol,
|
|
276
|
+
interval=interval,
|
|
277
|
+
open=float(data["open"][index]),
|
|
278
|
+
high=float(data["high"][index]),
|
|
279
|
+
low=float(data["low"][index]),
|
|
280
|
+
close=float(data["close"][index]),
|
|
281
|
+
volume=float(data["volume"][index]),
|
|
282
|
+
start=int(tick),
|
|
283
|
+
timestamp=end,
|
|
284
|
+
confirm=end >= int(tick) + interval.milliseconds,
|
|
285
|
+
)
|
|
286
|
+
)
|
|
287
|
+
if limit is not None:
|
|
288
|
+
klines = klines[-limit:]
|
|
289
|
+
return KlineList(klines)
|
|
290
|
+
|
|
291
|
+
async def request_index_klines(
|
|
292
|
+
self,
|
|
293
|
+
symbol: str,
|
|
294
|
+
interval: KlineInterval,
|
|
295
|
+
limit: int | None = None,
|
|
296
|
+
start_time: int | None = None,
|
|
297
|
+
end_time: int | None = None,
|
|
298
|
+
) -> KlineList:
|
|
299
|
+
raise NotImplementedError("Deribit index klines are not supported")
|
|
300
|
+
|
|
301
|
+
def subscribe_trade(self, symbol: str | list[str]):
|
|
302
|
+
self._ws_client.subscribe(
|
|
303
|
+
[f"trades.{item}.100ms" for _, item in self._symbols(symbol)]
|
|
304
|
+
)
|
|
305
|
+
|
|
306
|
+
def unsubscribe_trade(self, symbol: str | list[str]):
|
|
307
|
+
self._ws_client.unsubscribe(
|
|
308
|
+
[f"trades.{item}.100ms" for _, item in self._symbols(symbol)]
|
|
309
|
+
)
|
|
310
|
+
|
|
311
|
+
def subscribe_bookl1(self, symbol: str | list[str]):
|
|
312
|
+
self._ws_client.subscribe(
|
|
313
|
+
[f"book.{item}.none.1.100ms" for _, item in self._symbols(symbol)]
|
|
314
|
+
)
|
|
315
|
+
|
|
316
|
+
def unsubscribe_bookl1(self, symbol: str | list[str]):
|
|
317
|
+
self._ws_client.unsubscribe(
|
|
318
|
+
[f"book.{item}.none.1.100ms" for _, item in self._symbols(symbol)]
|
|
319
|
+
)
|
|
320
|
+
|
|
321
|
+
def subscribe_bookl2(self, symbol: str | list[str], level: BookLevel):
|
|
322
|
+
if level not in {BookLevel.L10, BookLevel.L20}:
|
|
323
|
+
raise ValueError(
|
|
324
|
+
f"Deribit only supports BookLevel.L10 and BookLevel.L20, got {level}"
|
|
325
|
+
)
|
|
326
|
+
self._ws_client.subscribe(
|
|
327
|
+
[
|
|
328
|
+
f"book.{item}.none.{level.value}.100ms"
|
|
329
|
+
for _, item in self._symbols(symbol)
|
|
330
|
+
]
|
|
331
|
+
)
|
|
332
|
+
|
|
333
|
+
def unsubscribe_bookl2(self, symbol: str | list[str], level: BookLevel):
|
|
334
|
+
if level not in {BookLevel.L10, BookLevel.L20}:
|
|
335
|
+
raise ValueError(
|
|
336
|
+
f"Deribit only supports BookLevel.L10 and BookLevel.L20, got {level}"
|
|
337
|
+
)
|
|
338
|
+
self._ws_client.unsubscribe(
|
|
339
|
+
[
|
|
340
|
+
f"book.{item}.none.{level.value}.100ms"
|
|
341
|
+
for _, item in self._symbols(symbol)
|
|
342
|
+
]
|
|
343
|
+
)
|
|
344
|
+
|
|
345
|
+
def subscribe_kline(self, symbol: str | list[str], interval: KlineInterval):
|
|
346
|
+
resolution = DeribitEnumParser.to_resolution(interval)
|
|
347
|
+
self._ws_client.subscribe(
|
|
348
|
+
[f"chart.trades.{item}.{resolution}" for _, item in self._symbols(symbol)]
|
|
349
|
+
)
|
|
350
|
+
|
|
351
|
+
def unsubscribe_kline(self, symbol: str | list[str], interval: KlineInterval):
|
|
352
|
+
resolution = DeribitEnumParser.to_resolution(interval)
|
|
353
|
+
self._ws_client.unsubscribe(
|
|
354
|
+
[f"chart.trades.{item}.{resolution}" for _, item in self._symbols(symbol)]
|
|
355
|
+
)
|
|
356
|
+
|
|
357
|
+
def subscribe_mark_price(self, symbol: str | list[str]):
|
|
358
|
+
self._subscribe_tickers(symbol)
|
|
359
|
+
|
|
360
|
+
def unsubscribe_mark_price(self, symbol: str | list[str]):
|
|
361
|
+
self._unsubscribe_tickers(symbol)
|
|
362
|
+
|
|
363
|
+
def subscribe_index_price(self, symbol: str | list[str]):
|
|
364
|
+
self._subscribe_tickers(symbol)
|
|
365
|
+
|
|
366
|
+
def unsubscribe_index_price(self, symbol: str | list[str]):
|
|
367
|
+
self._unsubscribe_tickers(symbol)
|
|
368
|
+
|
|
369
|
+
def _subscribe_tickers(self, symbol: str | list[str]):
|
|
370
|
+
self._ws_client.subscribe(
|
|
371
|
+
[f"ticker.{item}.100ms" for _, item in self._symbols(symbol)]
|
|
372
|
+
)
|
|
373
|
+
|
|
374
|
+
def _unsubscribe_tickers(self, symbol: str | list[str]):
|
|
375
|
+
self._ws_client.unsubscribe(
|
|
376
|
+
[f"ticker.{item}.100ms" for _, item in self._symbols(symbol)]
|
|
377
|
+
)
|
|
378
|
+
|
|
379
|
+
def subscribe_funding_rate(self, symbol: str | list[str]):
|
|
380
|
+
raise NotImplementedError("Deribit funding rate is not supported")
|
|
381
|
+
|
|
382
|
+
def unsubscribe_funding_rate(self, symbol: str | list[str]):
|
|
383
|
+
raise NotImplementedError("Deribit funding rate is not supported")
|
|
384
|
+
|
|
385
|
+
|
|
386
|
+
class DeribitPrivateConnector(PrivateConnector):
|
|
387
|
+
def __init__(
|
|
388
|
+
self,
|
|
389
|
+
account_type: DeribitAccountType,
|
|
390
|
+
exchange: DeribitExchangeManager,
|
|
391
|
+
cache: AsyncCache,
|
|
392
|
+
registry: OrderRegistry,
|
|
393
|
+
clock: LiveClock,
|
|
394
|
+
msgbus: MessageBus,
|
|
395
|
+
task_manager: TaskManager,
|
|
396
|
+
order_query_config: OrderQueryConfig,
|
|
397
|
+
**kwargs: Any,
|
|
398
|
+
):
|
|
399
|
+
if not exchange.api_key or not exchange.secret:
|
|
400
|
+
raise ValueError("Deribit client_id and client_secret are required")
|
|
401
|
+
api_client = DeribitApiClient(
|
|
402
|
+
clock=clock,
|
|
403
|
+
account_type=account_type,
|
|
404
|
+
api_key=exchange.api_key,
|
|
405
|
+
secret=exchange.secret,
|
|
406
|
+
)
|
|
407
|
+
oms = DeribitOrderManagementSystem(
|
|
408
|
+
account_type=account_type,
|
|
409
|
+
api_key=exchange.api_key,
|
|
410
|
+
secret=exchange.secret,
|
|
411
|
+
market=cast(dict, exchange.market),
|
|
412
|
+
market_id=exchange.market_id,
|
|
413
|
+
registry=registry,
|
|
414
|
+
cache=cache,
|
|
415
|
+
api_client=api_client,
|
|
416
|
+
exchange_id=exchange.exchange_id,
|
|
417
|
+
clock=clock,
|
|
418
|
+
msgbus=msgbus,
|
|
419
|
+
task_manager=task_manager,
|
|
420
|
+
order_query_config=order_query_config,
|
|
421
|
+
)
|
|
422
|
+
super().__init__(
|
|
423
|
+
account_type=account_type,
|
|
424
|
+
market=exchange.market,
|
|
425
|
+
api_client=api_client,
|
|
426
|
+
task_manager=task_manager,
|
|
427
|
+
oms=oms,
|
|
428
|
+
)
|
|
429
|
+
|
|
430
|
+
async def connect(self):
|
|
431
|
+
self._oms._ws_client.subscribe(
|
|
432
|
+
[
|
|
433
|
+
"user.changes.future.any.100ms",
|
|
434
|
+
"user.changes.spot.any.100ms",
|
|
435
|
+
"user.portfolio.any",
|
|
436
|
+
]
|
|
437
|
+
)
|
|
438
|
+
await self._oms._ws_client.connect()
|
|
439
|
+
await self._oms._ws_api_client.connect()
|