walrasquant-lib 0.4.20__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. walrasquant/__init__.py +7 -0
  2. walrasquant/aggregation.py +449 -0
  3. walrasquant/backends/__init__.py +5 -0
  4. walrasquant/backends/db.py +109 -0
  5. walrasquant/backends/db_memory.py +61 -0
  6. walrasquant/backends/db_postgresql.py +321 -0
  7. walrasquant/backends/db_sqlite.py +310 -0
  8. walrasquant/base/__init__.py +24 -0
  9. walrasquant/base/api_client.py +46 -0
  10. walrasquant/base/connector.py +863 -0
  11. walrasquant/base/ems.py +794 -0
  12. walrasquant/base/exchange.py +213 -0
  13. walrasquant/base/oms.py +428 -0
  14. walrasquant/base/retry.py +220 -0
  15. walrasquant/base/sms.py +545 -0
  16. walrasquant/base/ws_client.py +408 -0
  17. walrasquant/config.py +284 -0
  18. walrasquant/constants.py +413 -0
  19. walrasquant/core/__init__.py +0 -0
  20. walrasquant/core/cache.py +688 -0
  21. walrasquant/core/clock.py +59 -0
  22. walrasquant/core/connection.py +41 -0
  23. walrasquant/core/entity.py +504 -0
  24. walrasquant/core/nautilius_core.py +103 -0
  25. walrasquant/core/registry.py +41 -0
  26. walrasquant/engine.py +745 -0
  27. walrasquant/error.py +34 -0
  28. walrasquant/exchange/__init__.py +13 -0
  29. walrasquant/exchange/base_factory.py +172 -0
  30. walrasquant/exchange/binance/__init__.py +30 -0
  31. walrasquant/exchange/binance/connector.py +1093 -0
  32. walrasquant/exchange/binance/constants.py +934 -0
  33. walrasquant/exchange/binance/ems.py +140 -0
  34. walrasquant/exchange/binance/error.py +48 -0
  35. walrasquant/exchange/binance/exchange.py +144 -0
  36. walrasquant/exchange/binance/factory.py +115 -0
  37. walrasquant/exchange/binance/oms.py +1807 -0
  38. walrasquant/exchange/binance/rest_api.py +1653 -0
  39. walrasquant/exchange/binance/schema.py +1063 -0
  40. walrasquant/exchange/binance/websockets.py +389 -0
  41. walrasquant/exchange/bitget/__init__.py +28 -0
  42. walrasquant/exchange/bitget/connector.py +578 -0
  43. walrasquant/exchange/bitget/constants.py +392 -0
  44. walrasquant/exchange/bitget/ems.py +202 -0
  45. walrasquant/exchange/bitget/error.py +36 -0
  46. walrasquant/exchange/bitget/exchange.py +128 -0
  47. walrasquant/exchange/bitget/factory.py +135 -0
  48. walrasquant/exchange/bitget/oms.py +1619 -0
  49. walrasquant/exchange/bitget/rest_api.py +610 -0
  50. walrasquant/exchange/bitget/schema.py +885 -0
  51. walrasquant/exchange/bitget/websockets.py +753 -0
  52. walrasquant/exchange/bybit/__init__.py +32 -0
  53. walrasquant/exchange/bybit/connector.py +819 -0
  54. walrasquant/exchange/bybit/constants.py +479 -0
  55. walrasquant/exchange/bybit/ems.py +93 -0
  56. walrasquant/exchange/bybit/error.py +36 -0
  57. walrasquant/exchange/bybit/exchange.py +108 -0
  58. walrasquant/exchange/bybit/factory.py +128 -0
  59. walrasquant/exchange/bybit/oms.py +1195 -0
  60. walrasquant/exchange/bybit/rest_api.py +570 -0
  61. walrasquant/exchange/bybit/schema.py +867 -0
  62. walrasquant/exchange/bybit/websockets.py +307 -0
  63. walrasquant/exchange/hyperliquid/__init__.py +28 -0
  64. walrasquant/exchange/hyperliquid/connector.py +370 -0
  65. walrasquant/exchange/hyperliquid/constants.py +371 -0
  66. walrasquant/exchange/hyperliquid/ems.py +156 -0
  67. walrasquant/exchange/hyperliquid/error.py +48 -0
  68. walrasquant/exchange/hyperliquid/exchange.py +120 -0
  69. walrasquant/exchange/hyperliquid/factory.py +135 -0
  70. walrasquant/exchange/hyperliquid/oms.py +1081 -0
  71. walrasquant/exchange/hyperliquid/rest_api.py +348 -0
  72. walrasquant/exchange/hyperliquid/schema.py +583 -0
  73. walrasquant/exchange/hyperliquid/websockets.py +592 -0
  74. walrasquant/exchange/okx/__init__.py +25 -0
  75. walrasquant/exchange/okx/connector.py +931 -0
  76. walrasquant/exchange/okx/constants.py +518 -0
  77. walrasquant/exchange/okx/ems.py +144 -0
  78. walrasquant/exchange/okx/error.py +66 -0
  79. walrasquant/exchange/okx/exchange.py +102 -0
  80. walrasquant/exchange/okx/factory.py +138 -0
  81. walrasquant/exchange/okx/oms.py +1199 -0
  82. walrasquant/exchange/okx/rest_api.py +799 -0
  83. walrasquant/exchange/okx/schema.py +1449 -0
  84. walrasquant/exchange/okx/websockets.py +420 -0
  85. walrasquant/exchange/registry.py +201 -0
  86. walrasquant/execution/__init__.py +24 -0
  87. walrasquant/execution/algorithm.py +968 -0
  88. walrasquant/execution/algorithms/__init__.py +3 -0
  89. walrasquant/execution/algorithms/twap.py +392 -0
  90. walrasquant/execution/config.py +34 -0
  91. walrasquant/execution/constants.py +27 -0
  92. walrasquant/execution/schema.py +62 -0
  93. walrasquant/indicator.py +382 -0
  94. walrasquant/push.py +77 -0
  95. walrasquant/schema.py +755 -0
  96. walrasquant/strategy.py +1805 -0
  97. walrasquant/tools/__init__.py +0 -0
  98. walrasquant/tools/pm2_wrapper.py +1016 -0
  99. walrasquant/web/__init__.py +26 -0
  100. walrasquant/web/app.py +157 -0
  101. walrasquant/web/server.py +92 -0
  102. walrasquant_lib-0.4.20.dist-info/METADATA +162 -0
  103. walrasquant_lib-0.4.20.dist-info/RECORD +105 -0
  104. walrasquant_lib-0.4.20.dist-info/WHEEL +4 -0
  105. walrasquant_lib-0.4.20.dist-info/entry_points.txt +3 -0
@@ -0,0 +1,885 @@
1
+ import msgspec
2
+ from decimal import Decimal
3
+ from typing import Optional
4
+ from typing import Any, List
5
+ from walrasquant.schema import BaseMarket, Balance
6
+ from walrasquant.exchange.bitget.constants import (
7
+ BitgetInstType,
8
+ BitgetUtaInstType,
9
+ BitgetOrderSide,
10
+ BitgetOrderStatus,
11
+ BitgetTimeInForce,
12
+ BitgetPositionSide,
13
+ BitgetOrderType,
14
+ )
15
+
16
+
17
+ class BitgetWsUtaArgMsg(msgspec.Struct):
18
+ instType: BitgetUtaInstType
19
+ topic: str
20
+ symbol: str | None = None
21
+ interval: str | None = None
22
+
23
+ @property
24
+ def message(self) -> str:
25
+ if not self.symbol:
26
+ return f"{self.instType.value}.{self.topic}"
27
+ if self.interval:
28
+ return f"{self.instType.value}.{self.topic}{self.interval}.{self.symbol}"
29
+ return f"{self.instType.value}.{self.topic}.{self.symbol}"
30
+
31
+
32
+ class BitgetWsUtaGeneralMsg(msgspec.Struct, kw_only=True):
33
+ event: str | None = None
34
+ arg: BitgetWsUtaArgMsg | None = None
35
+ code: int | None = None
36
+ msg: str | None = None
37
+
38
+ @property
39
+ def is_event_data(self) -> bool:
40
+ return self.event is not None
41
+
42
+
43
+ class BitgetGeneralResponse(msgspec.Struct, kw_only=True):
44
+ code: str
45
+ msg: str
46
+
47
+
48
+ class BitgetWsArgMsg(msgspec.Struct):
49
+ instType: BitgetInstType
50
+ channel: str
51
+ instId: str | None = None
52
+ coin: str | None = None
53
+
54
+ @property
55
+ def message(self) -> str:
56
+ if self.instId:
57
+ return f"{self.instType.value}.{self.channel}.{self.instId}"
58
+ if self.coin:
59
+ return f"{self.instType.value}.{self.channel}.{self.coin}"
60
+ return f"{self.instType.value}.{self.channel}"
61
+
62
+
63
+ class BitgetWsGeneralMsg(msgspec.Struct, kw_only=True):
64
+ event: str | None = None
65
+ arg: BitgetWsArgMsg | None = None
66
+ code: int | None = None
67
+ msg: str | None = None
68
+
69
+ @property
70
+ def is_event_data(self) -> bool:
71
+ return self.event is not None
72
+
73
+
74
+ class BookData(msgspec.Struct, array_like=True):
75
+ px: str
76
+ sz: str
77
+
78
+
79
+ class BitgetBooks1WsMsgData(msgspec.Struct):
80
+ a: List[BookData]
81
+ b: List[BookData]
82
+ ts: str
83
+
84
+
85
+ class BitgetBooks1WsMsg(msgspec.Struct):
86
+ data: list[BitgetBooks1WsMsgData]
87
+
88
+
89
+ class BitgetTradeWsMsgData(msgspec.Struct):
90
+ p: str # fill price
91
+ S: BitgetOrderSide # fill side
92
+ T: str # ts
93
+ v: str # fill size
94
+ i: str # trade id
95
+
96
+
97
+ class BitgetWsTradeWsMsg(msgspec.Struct):
98
+ data: list[BitgetTradeWsMsgData]
99
+
100
+
101
+ class BitgetWsCandleWsMsgData(msgspec.Struct):
102
+ start: str
103
+ open: str
104
+ close: str
105
+ high: str
106
+ low: str
107
+ volume: str
108
+ turnover: str
109
+
110
+
111
+ class BitgetWsCandleWsMsg(msgspec.Struct):
112
+ data: list[BitgetWsCandleWsMsgData]
113
+
114
+
115
+ # # --- Kline ---
116
+ # class BitgetKline(msgspec.Struct):
117
+ # openTime: int
118
+ # open: str
119
+ # high: str
120
+ # low: str
121
+ # close: str
122
+ # volume: str
123
+ # quoteVolume: str
124
+ # closeTime: int
125
+
126
+ # class BitgetKlineMsg(msgspec.Struct):
127
+ # event: str
128
+ # arg: Dict[str, Any]
129
+ # data: List[BitgetKline]
130
+
131
+
132
+ # # --- Trade ---
133
+ # class BitgetTrade(msgspec.Struct):
134
+ # tradeId: str
135
+ # price: str
136
+ # size: str
137
+ # side: str
138
+ # timestamp: int
139
+
140
+ # class BitgetTradeMsg(msgspec.Struct):
141
+ # event: str
142
+ # arg: Dict[str, Any]
143
+ # data: List[BitgetTrade]
144
+
145
+ # # --- Order Book ---
146
+ # class BitgetOrderBookSnapshot(msgspec.Struct):
147
+ # asks: List[List[str]]
148
+ # bids: List[List[str]]
149
+ # ts: int
150
+ # checksum: int
151
+
152
+ # class BitgetOrderBookUpdate(msgspec.Struct):
153
+ # asks: List[List[str]]
154
+ # bids: List[List[str]]
155
+ # ts: int
156
+ # checksum: int
157
+
158
+ # class BitgetOrderBookMsg(msgspec.Struct):
159
+ # event: str
160
+ # arg: Dict[str, Any]
161
+ # action: str # snapshot or update
162
+ # data: List[BitgetOrderBookSnapshot | BitgetOrderBookUpdate]
163
+
164
+ # class BitgetOrderBook(msgspec.Struct):
165
+ # bids: Dict[float, float] = {}
166
+ # asks: Dict[float, float] = {}
167
+
168
+ # def parse_orderbook(self, msg: BitgetOrderBookMsg, levels: int = 1):
169
+ # for entry in msg.data:
170
+ # if msg.action == "snapshot":
171
+ # self._handle_snapshot(entry)
172
+ # elif msg.action == "update":
173
+ # self._handle_delta(entry)
174
+ # return self._get_orderbook(levels)
175
+
176
+ # def _handle_snapshot(self, data: BitgetOrderBookSnapshot):
177
+ # self.bids.clear()
178
+ # self.asks.clear()
179
+ # for price, size in data.bids:
180
+ # self.bids[float(price)] = float(size)
181
+ # for price, size in data.asks:
182
+ # self.asks[float(price)] = float(size)
183
+
184
+ # def _handle_delta(self, data: BitgetOrderBookUpdate):
185
+ # for price, size in data.bids:
186
+ # price_f = float(price)
187
+ # size_f = float(size)
188
+ # if size_f == 0:
189
+ # self.bids.pop(price_f, None)
190
+ # else:
191
+ # self.bids[price_f] = size_f
192
+ # for price, size in data.asks:
193
+ # price_f = float(price)
194
+ # size_f = float(size)
195
+ # if size_f == 0:
196
+ # self.asks.pop(price_f, None)
197
+ # else:
198
+ # self.asks[price_f] = size_f
199
+
200
+ # def _get_orderbook(self, levels: int):
201
+ # bids = sorted(self.bids.items(), reverse=True)[:levels]
202
+ # asks = sorted(self.asks.items())[:levels]
203
+ # return {
204
+ # "bids": [BookOrderData(price=price, size=size) for price, size in bids],
205
+ # "asks": [BookOrderData(price=price, size=size) for price, size in asks],
206
+ # }
207
+
208
+ # # --- Ticker ---
209
+ # class BitgetTicker(msgspec.Struct):
210
+ # symbol: str
211
+ # markPrice: str | None = None
212
+ # indexPrice: str | None = None
213
+ # nextFundingTime: str | None = None
214
+ # fundingRate: str | None = None
215
+
216
+ # class BitgetTickerMsg(msgspec.Struct):
217
+ # event: str
218
+ # arg: Dict[str, Any]
219
+ # data: List[Dict[str, Any]]
220
+
221
+ # # --- Balance ---
222
+ # class BitgetBalanceCoin(msgspec.Struct):
223
+ # coin: str
224
+ # available: str
225
+ # frozen: str
226
+
227
+ # def parse_to_balance(self) -> Balance:
228
+ # locked = Decimal(self.frozen)
229
+ # free = Decimal(self.available)
230
+ # return Balance(asset=self.coin, locked=locked, free=free)
231
+
232
+ # class BitgetBalanceResponse(msgspec.Struct):
233
+ # code: str
234
+ # msg: str
235
+ # data: List[BitgetBalanceCoin]
236
+
237
+ # def parse_to_balances(self) -> List[Balance]:
238
+ # return [coin.parse_to_balance() for coin in self.data]
239
+
240
+
241
+ # # --- Market Info ---
242
+ class BitgetMarketInfo(msgspec.Struct, kw_only=True, omit_defaults=True):
243
+ # Common required fields
244
+ symbol: str
245
+ baseCoin: str
246
+ quoteCoin: str
247
+ makerFeeRate: str
248
+ takerFeeRate: str
249
+ minTradeUSDT: str
250
+
251
+ # Spot-only optional fields
252
+ minTradeAmount: Optional[str] = None
253
+ maxTradeAmount: Optional[str] = None
254
+ pricePrecision: Optional[str] = None
255
+ quantityPrecision: Optional[str] = None
256
+ quotePrecision: Optional[str] = None
257
+ status: Optional[str] = None
258
+ buyLimitPriceRatio: Optional[str] = None
259
+ sellLimitPriceRatio: Optional[str] = None
260
+ areaSymbol: Optional[str] = None
261
+ orderQuantity: Optional[str] = None
262
+ openTime: Optional[str] = None
263
+ offTime: Optional[str] = None
264
+
265
+ # Futures-only optional fields
266
+ feeRateUpRatio: Optional[str] = None
267
+ openCostUpRatio: Optional[str] = None
268
+ supportMarginCoins: Optional[List[str]] = None
269
+ minTradeNum: Optional[str] = None
270
+ priceEndStep: Optional[str] = None
271
+ volumePlace: Optional[str] = None
272
+ pricePlace: Optional[str] = None
273
+ sizeMultiplier: Optional[str] = None
274
+ symbolType: Optional[str] = None
275
+ maxSymbolOrderNum: Optional[str] = None
276
+ maxProductOrderNum: Optional[str] = None
277
+ maxPositionNum: Optional[str] = None
278
+ symbolStatus: Optional[str] = None
279
+ limitOpenTime: Optional[str] = None
280
+ deliveryTime: Optional[str] = None
281
+ deliveryStartTime: Optional[str] = None
282
+ launchTime: Optional[str] = None
283
+ fundInterval: Optional[str] = None
284
+ minLever: Optional[str] = None
285
+ maxLever: Optional[str] = None
286
+ posLimit: Optional[str] = None
287
+ maintainTime: Optional[str] = None
288
+ maxMarketOrderQty: Optional[str] = None
289
+ maxOrderQty: Optional[str] = None
290
+
291
+
292
+ class BitgetMarket(BaseMarket):
293
+ info: BitgetMarketInfo
294
+
295
+
296
+ class BitgetOrderCancelData(msgspec.Struct):
297
+ orderId: str
298
+ clientOid: str
299
+
300
+
301
+ class BitgetOrderCancelResponse(msgspec.Struct):
302
+ code: str
303
+ msg: str
304
+ requestTime: int
305
+ data: BitgetOrderCancelData
306
+
307
+
308
+ class BitgetOrderPlaceData(msgspec.Struct, kw_only=True):
309
+ orderId: str
310
+ clientOid: str | None = None
311
+
312
+
313
+ class BitgetOrderPlaceResponse(msgspec.Struct):
314
+ code: str
315
+ msg: str
316
+ requestTime: int
317
+ data: BitgetOrderPlaceData
318
+
319
+
320
+ class BitgetPositionItem(msgspec.Struct):
321
+ symbol: str
322
+ marginCoin: str
323
+ holdSide: BitgetPositionSide
324
+ openDelegateSize: str
325
+ marginSize: str
326
+ available: str
327
+ locked: str
328
+ total: str
329
+ leverage: str
330
+ openPriceAvg: str
331
+ marginMode: str
332
+ posMode: str
333
+ unrealizedPL: str
334
+ liquidationPrice: str
335
+ markPrice: str
336
+ breakEvenPrice: str
337
+ achievedProfits: str | None = None
338
+ keepMarginRate: str | None = None
339
+ totalFee: str | None = None
340
+ deductedFee: str | None = None
341
+ marginRatio: str | None = None
342
+ assetMode: str | None = None
343
+ uTime: str | None = None
344
+ autoMargin: str | None = None
345
+ cTime: str | None = None
346
+
347
+
348
+ class BitgetPositionListResponse(msgspec.Struct):
349
+ code: str
350
+ msg: str
351
+ requestTime: int
352
+ data: list[BitgetPositionItem]
353
+
354
+
355
+ class BitgetOrder(msgspec.Struct, kw_only=True):
356
+ orderId: str
357
+ clientOid: Optional[str]
358
+ symbol: str
359
+ baseCoin: str
360
+ quoteCoin: str
361
+ size: Decimal
362
+ price: Decimal
363
+ state: str
364
+ orderType: str
365
+ side: str
366
+ timeInForceValue: Optional[str] = None
367
+ force: Optional[str] = None
368
+ priceAvg: Optional[Decimal] = None
369
+ fillPrice: Optional[Decimal] = None
370
+ filledQty: Optional[Decimal] = None
371
+ fee: Optional[Decimal] = None
372
+ orderSource: Optional[str] = None
373
+ cTime: Optional[int] = None
374
+ uTime: Optional[int] = None
375
+ status: Optional[str] = None
376
+
377
+
378
+ class BitgetOpenOrdersResponse(msgspec.Struct, kw_only=True):
379
+ code: str
380
+ msg: Optional[str]
381
+ requestTime: int
382
+ data: List[BitgetOrder]
383
+
384
+
385
+ class BitgetOrderHistoryItem(msgspec.Struct, kw_only=True, omit_defaults=True):
386
+ orderId: str
387
+ symbol: str
388
+ price: str
389
+ size: str
390
+ orderType: str
391
+ side: str
392
+ status: str
393
+ createTime: int
394
+ baseCoin: Optional[str] = None
395
+ quoteCoin: Optional[str] = None
396
+ clientOid: Optional[str] = None
397
+ priceAvg: Optional[str] = None
398
+ filledAmount: Optional[str] = None
399
+ enterPointSource: Optional[str] = None
400
+ tradeSide: Optional[str] = None
401
+ forceClose: Optional[bool] = None
402
+ marginMode: Optional[str] = None
403
+ reduceOnly: Optional[bool] = None
404
+ presetStopSurplusPrice: Optional[str] = None
405
+ presetStopLossPrice: Optional[str] = None
406
+ feeDetail: Optional[str] = None
407
+ tradeId: Optional[str] = None
408
+
409
+
410
+ class BitgetOrderHistoryResponse(msgspec.Struct, kw_only=True, omit_defaults=True):
411
+ code: str
412
+ msg: str
413
+ requestTime: int
414
+ data: List[BitgetOrderHistoryItem]
415
+
416
+
417
+ class BitgetAccountAssetItem(msgspec.Struct):
418
+ coin: str
419
+ available: str
420
+ frozen: str
421
+ locked: str
422
+ limitAvailable: str
423
+ uTime: str
424
+
425
+
426
+ class BitgetAccountAssetResponse(msgspec.Struct):
427
+ code: str
428
+ message: str
429
+ requestTime: int
430
+ data: List[BitgetAccountAssetItem]
431
+
432
+
433
+ class BitgetOrderModifyResponse(msgspec.Struct, kw_only=True):
434
+ orderId: str
435
+ clientOid: str
436
+
437
+
438
+ class BitgetResponse(msgspec.Struct, kw_only=True):
439
+ code: str
440
+ msg: str
441
+ data: BitgetOrderModifyResponse
442
+ requestTime: int
443
+
444
+
445
+ class BitgetBaseResponse(msgspec.Struct, kw_only=True):
446
+ code: str
447
+ msg: str
448
+ requestTime: int
449
+ data: Any
450
+
451
+
452
+ class BitgetKlineItem(msgspec.Struct):
453
+ timestamp: str # index[0]
454
+ open: str # index[1]
455
+ high: str # index[2]
456
+ low: str # index[3]
457
+ close: str # index[4]
458
+ volume_base: str # index[5]
459
+ volume_quote: str # index[6]
460
+
461
+
462
+ class BitgetKlineResponse(msgspec.Struct):
463
+ code: str
464
+ msg: str
465
+ requestTime: int
466
+ data: List[List[str]]
467
+
468
+
469
+ class BitgetIndexPriceKlineItem(msgspec.Struct):
470
+ timestamp: str
471
+ open_price: str
472
+ high_price: str
473
+ low_price: str
474
+ close_price: str
475
+ base_volume: str
476
+ quote_volume: str
477
+
478
+
479
+ class BitgetIndexPriceKlineResponse(msgspec.Struct):
480
+ code: str
481
+ msg: str
482
+ requestTime: int
483
+ data: List[BitgetIndexPriceKlineItem]
484
+
485
+
486
+ class BitgetOrderFeeDetail(msgspec.Struct):
487
+ feeCoin: str
488
+ fee: str
489
+
490
+
491
+ class BitgetOrderData(msgspec.Struct, kw_only=True):
492
+ # Common required fields (present in both spot and futures)
493
+ instId: str
494
+ orderId: str
495
+ clientOid: str
496
+ size: str
497
+ orderType: BitgetOrderType
498
+ force: BitgetTimeInForce
499
+ side: BitgetOrderSide
500
+
501
+ tradeId: Optional[str] = None
502
+ fillTime: Optional[str] = None
503
+ fillFee: Optional[str] = None
504
+ fillFeeCoin: Optional[str] = None
505
+ tradeScope: Optional[str] = None
506
+ priceAvg: Optional[str] = None
507
+ status: BitgetOrderStatus
508
+ cTime: str
509
+ uTime: str
510
+ stpMode: str
511
+ feeDetail: List[BitgetOrderFeeDetail]
512
+ enterPointSource: str
513
+
514
+ # Optional fields (may be present in spot, futures, or both)
515
+ fillPrice: Optional[str] = None
516
+ newSize: Optional[str] = None
517
+ notional: Optional[str] = None
518
+ baseVolume: Optional[str] = None
519
+ accBaseVolume: Optional[str] = None
520
+
521
+ # Futures-specific optional fields
522
+ fillNotionalUsd: Optional[str] = None
523
+ leverage: Optional[str] = None
524
+ marginCoin: Optional[str] = None
525
+ marginMode: Optional[str] = None
526
+ notionalUsd: Optional[str] = None
527
+ pnl: Optional[str] = None
528
+ posMode: Optional[str] = None
529
+ posSide: Optional[BitgetPositionSide] = None
530
+ price: Optional[str] = None
531
+ reduceOnly: Optional[str] = None
532
+ tradeSide: Optional[str] = None
533
+ presetStopSurplusPrice: Optional[str] = None
534
+ totalProfits: Optional[str] = None
535
+ presetStopLossPrice: Optional[str] = None
536
+ cancelReason: Optional[str] = None
537
+
538
+
539
+ class BitgetOrderWsMsg(msgspec.Struct):
540
+ action: str
541
+ arg: BitgetWsArgMsg
542
+ data: List[BitgetOrderData]
543
+ ts: int
544
+
545
+
546
+ class BitgetPositionData(msgspec.Struct):
547
+ posId: str
548
+ instId: str
549
+ marginCoin: str
550
+ marginSize: str
551
+ marginMode: str
552
+ holdSide: BitgetPositionSide
553
+ posMode: str
554
+ total: str
555
+ available: str
556
+ frozen: str
557
+ openPriceAvg: str
558
+ leverage: int
559
+ achievedProfits: str
560
+ unrealizedPL: str
561
+ unrealizedPLR: str
562
+ liquidationPrice: str
563
+ keepMarginRate: str
564
+ marginRate: str
565
+ cTime: str
566
+ breakEvenPrice: str
567
+ totalFee: str
568
+ deductedFee: str
569
+ markPrice: str
570
+ uTime: str
571
+ autoMargin: str
572
+
573
+
574
+ class BitgetPositionWsMsg(msgspec.Struct):
575
+ action: str
576
+ arg: BitgetWsArgMsg
577
+ data: List[BitgetPositionData]
578
+ ts: int
579
+
580
+
581
+ class BitgetSpotAccountData(msgspec.Struct):
582
+ coin: str
583
+ available: str
584
+ frozen: str
585
+ locked: str
586
+ limitAvailable: str
587
+ uTime: str
588
+
589
+ def parse_to_balance(self) -> Balance:
590
+ locked = Decimal(self.frozen) + Decimal(self.locked)
591
+ free = Decimal(self.available)
592
+ return Balance(asset=self.coin, locked=locked, free=free)
593
+
594
+
595
+ class BitgetSpotAccountWsMsg(msgspec.Struct):
596
+ data: List[BitgetSpotAccountData]
597
+ ts: int
598
+
599
+ def parse_to_balances(self) -> List[Balance]:
600
+ return [account_data.parse_to_balance() for account_data in self.data]
601
+
602
+
603
+ class BitgetFuturesAccountData(msgspec.Struct):
604
+ marginCoin: str
605
+ frozen: str
606
+ available: str
607
+ maxOpenPosAvailable: str
608
+ maxTransferOut: str
609
+ equity: str
610
+ usdtEquity: str
611
+ crossedRiskRate: str
612
+ unrealizedPL: str
613
+
614
+ def parse_to_balance(self) -> Balance:
615
+ locked = Decimal(self.frozen)
616
+ free = Decimal(self.available)
617
+ return Balance(asset=self.marginCoin, locked=locked, free=free)
618
+
619
+
620
+ class BitgetFuturesAccountWsMsg(msgspec.Struct):
621
+ data: List[BitgetFuturesAccountData]
622
+ ts: int
623
+
624
+ def parse_to_balances(self) -> List[Balance]:
625
+ return [account_data.parse_to_balance() for account_data in self.data]
626
+
627
+
628
+ class BitgetUtaCoinData(msgspec.Struct):
629
+ debts: str
630
+ balance: str
631
+ available: str
632
+ borrow: str
633
+ locked: str
634
+ equity: str
635
+ coin: str
636
+ usdValue: str
637
+
638
+ def parse_to_balance(self) -> Balance:
639
+ locked = Decimal(self.locked)
640
+ free = Decimal(self.available)
641
+ return Balance(asset=self.coin, locked=locked, free=free)
642
+
643
+
644
+ class BitgetUtaAccountData(msgspec.Struct):
645
+ unrealisedPnL: str
646
+ totalEquity: str
647
+ positionMgnRatio: str
648
+ mmr: str
649
+ effEquity: str
650
+ imr: str
651
+ mgnRatio: str
652
+ coin: List[BitgetUtaCoinData]
653
+
654
+ def parse_to_balances(self) -> List[Balance]:
655
+ return [coin_data.parse_to_balance() for coin_data in self.coin]
656
+
657
+
658
+ class BitgetUtaAccountWsMsg(msgspec.Struct):
659
+ data: List[BitgetUtaAccountData]
660
+ ts: int
661
+
662
+ def parse_to_balances(self) -> List[Balance]:
663
+ balances = []
664
+ for account_data in self.data:
665
+ balances.extend(account_data.parse_to_balances())
666
+ return balances
667
+
668
+
669
+ class BitgetUtaOrderFeeDetail(msgspec.Struct):
670
+ feeCoin: str
671
+ fee: str
672
+
673
+
674
+ class BitgetUtaOrderData(msgspec.Struct, kw_only=True):
675
+ category: BitgetUtaInstType
676
+ symbol: str
677
+ orderId: str
678
+ clientOid: str
679
+ price: str
680
+ qty: str
681
+ holdMode: str
682
+ holdSide: str
683
+ tradeSide: str
684
+ orderType: BitgetOrderType
685
+ timeInForce: BitgetTimeInForce
686
+ side: BitgetOrderSide
687
+ marginMode: str
688
+ marginCoin: str
689
+ reduceOnly: str
690
+ cumExecQty: str
691
+ cumExecValue: str
692
+ avgPrice: str
693
+ totalProfit: str
694
+ orderStatus: BitgetOrderStatus
695
+ cancelReason: str
696
+ leverage: str
697
+ feeDetail: List[BitgetUtaOrderFeeDetail] | None = None
698
+ createdTime: str
699
+ updatedTime: str
700
+ stpMode: str
701
+
702
+
703
+ class BitgetUtaOrderWsMsg(msgspec.Struct):
704
+ data: List[BitgetUtaOrderData]
705
+ ts: int
706
+
707
+
708
+ class BitgetUtaPositionData(msgspec.Struct, kw_only=True):
709
+ symbol: str
710
+ leverage: str
711
+ openFeeTotal: str
712
+ mmr: str
713
+ breakEvenPrice: str
714
+ available: str
715
+ liqPrice: str
716
+ marginMode: str
717
+ unrealisedPnl: str
718
+ markPrice: str
719
+ createdTime: str
720
+ openPriceAvg: str | None = None
721
+ totalFundingFee: str
722
+ updatedTime: str
723
+ marginCoin: str
724
+ frozen: str
725
+ profitRate: str
726
+ closeFeeTotal: str
727
+ marginSize: str
728
+ curRealisedPnl: str
729
+ size: str
730
+ posSide: BitgetPositionSide
731
+ holdMode: str
732
+
733
+
734
+ class BitgetUtaPositionWsMsg(msgspec.Struct):
735
+ data: List[BitgetUtaPositionData]
736
+ ts: int
737
+
738
+
739
+ class BitgetWsApiArgParamsMsg(msgspec.Struct):
740
+ orderId: str | None = None
741
+ clientOid: str | None = None
742
+
743
+
744
+ class BitgetWsApiArgMsg(msgspec.Struct):
745
+ id: str
746
+ instType: str
747
+ channel: str
748
+ instId: str
749
+ params: BitgetWsApiArgParamsMsg
750
+
751
+ @property
752
+ def is_place_order(self):
753
+ return self.channel == "place-order"
754
+
755
+ @property
756
+ def is_cancel_order(self):
757
+ return self.channel == "cancel-order"
758
+
759
+
760
+ class BitgetWsApiGeneralMsg(msgspec.Struct):
761
+ event: str
762
+ code: int | str
763
+ arg: list[BitgetWsApiArgMsg] | None = None
764
+ msg: str | None = None
765
+
766
+ @property
767
+ def is_success(self):
768
+ return int(self.code) == 0
769
+
770
+ @property
771
+ def is_login_msg(self):
772
+ return self.event == "login"
773
+
774
+ @property
775
+ def is_arg_msg(self):
776
+ return self.arg is not None
777
+
778
+ @property
779
+ def is_error_msg(self):
780
+ return int(self.code) != 0
781
+
782
+ @property
783
+ def error_msg(self):
784
+ return f"code={self.code} msg={self.msg}"
785
+
786
+
787
+ class BitgetWsApiUtaArgMsg(msgspec.Struct, kw_only=True):
788
+ orderId: str
789
+ clientOid: str
790
+
791
+
792
+ class BitgetWsApiUtaGeneralMsg(msgspec.Struct, kw_only=True):
793
+ event: str
794
+ id: str | None = None
795
+ code: str | int
796
+ args: list[BitgetWsApiUtaArgMsg] | None = None
797
+ msg: str | None = None
798
+
799
+ @property
800
+ def oid(self):
801
+ if not self.id:
802
+ raise ValueError("id is None")
803
+ return self.id[1:]
804
+
805
+ @property
806
+ def is_cancel_order(self) -> bool:
807
+ if not self.id:
808
+ raise ValueError("id is None")
809
+ return self.id.startswith("c")
810
+
811
+ @property
812
+ def is_place_order(self) -> bool:
813
+ if not self.id:
814
+ raise ValueError("id is None")
815
+ return self.id.startswith("n")
816
+
817
+ @property
818
+ def is_success(self):
819
+ return int(self.code) == 0
820
+
821
+ @property
822
+ def is_id_msg(self):
823
+ return self.id is not None
824
+
825
+ @property
826
+ def is_error_msg(self):
827
+ return int(self.code) != 0
828
+
829
+ @property
830
+ def error_msg(self):
831
+ return f"code={self.code} msg={self.msg}"
832
+
833
+
834
+ class BitgetTickerResponseData(msgspec.Struct):
835
+ category: BitgetInstType
836
+ symbol: str
837
+ lastPrice: str
838
+ volume24h: str
839
+ turnover24h: str
840
+
841
+
842
+ class BitgetTickerResponse(msgspec.Struct):
843
+ code: str
844
+ msg: str
845
+ requestTime: int
846
+ data: List[BitgetTickerResponseData]
847
+
848
+
849
+ class BitgetV3PositionData(msgspec.Struct, kw_only=True):
850
+ category: str
851
+ symbol: str
852
+ marginCoin: str
853
+ holdMode: str
854
+ posSide: str
855
+ marginMode: str
856
+ positionBalance: str
857
+ available: str
858
+ frozen: str
859
+ total: str
860
+ leverage: str
861
+ curRealisedPnl: str
862
+ avgPrice: str
863
+ positionStatus: str
864
+ unrealisedPnl: str
865
+ liquidationPrice: str
866
+ mmr: str
867
+ profitRate: str
868
+ markPrice: str
869
+ breakEvenPrice: str
870
+ totalFunding: str
871
+ openFeeTotal: str
872
+ closeFeeTotal: str
873
+ createdTime: str
874
+ updatedTime: str
875
+
876
+
877
+ class BitgetV3PositionResponseData(msgspec.Struct):
878
+ list: List[BitgetV3PositionData] | None = None
879
+
880
+
881
+ class BitgetV3PositionResponse(msgspec.Struct):
882
+ code: str
883
+ msg: str
884
+ requestTime: int
885
+ data: BitgetV3PositionResponseData