hotstuff-python-sdk 0.0.1b1__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.
- hotstuff/__init__.py +53 -0
- hotstuff/apis/__init__.py +10 -0
- hotstuff/apis/exchange.py +510 -0
- hotstuff/apis/info.py +291 -0
- hotstuff/apis/subscription.py +278 -0
- hotstuff/methods/__init__.py +10 -0
- hotstuff/methods/exchange/__init__.py +14 -0
- hotstuff/methods/exchange/account.py +120 -0
- hotstuff/methods/exchange/collateral.py +94 -0
- hotstuff/methods/exchange/op_codes.py +28 -0
- hotstuff/methods/exchange/trading.py +117 -0
- hotstuff/methods/exchange/vault.py +59 -0
- hotstuff/methods/info/__init__.py +14 -0
- hotstuff/methods/info/account.py +371 -0
- hotstuff/methods/info/explorer.py +57 -0
- hotstuff/methods/info/global.py +249 -0
- hotstuff/methods/info/vault.py +86 -0
- hotstuff/methods/subscription/__init__.py +8 -0
- hotstuff/methods/subscription/global.py +200 -0
- hotstuff/transports/__init__.py +9 -0
- hotstuff/transports/http.py +142 -0
- hotstuff/transports/websocket.py +401 -0
- hotstuff/types/__init__.py +62 -0
- hotstuff/types/clients.py +34 -0
- hotstuff/types/exchange.py +88 -0
- hotstuff/types/transports.py +110 -0
- hotstuff/utils/__init__.py +13 -0
- hotstuff/utils/address.py +37 -0
- hotstuff/utils/endpoints.py +15 -0
- hotstuff/utils/nonce.py +25 -0
- hotstuff/utils/signing.py +76 -0
- hotstuff_python_sdk-0.0.1b1.dist-info/LICENSE +21 -0
- hotstuff_python_sdk-0.0.1b1.dist-info/METADATA +985 -0
- hotstuff_python_sdk-0.0.1b1.dist-info/RECORD +35 -0
- hotstuff_python_sdk-0.0.1b1.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
"""Account info method types."""
|
|
2
|
+
from typing import List, Literal, Optional, Annotated
|
|
3
|
+
from pydantic import BaseModel, Field, ConfigDict, field_validator, RootModel
|
|
4
|
+
from eth_utils import is_address, to_checksum_address
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def validate_ethereum_address(value: str) -> str:
|
|
8
|
+
"""
|
|
9
|
+
Validate and normalize an Ethereum address.
|
|
10
|
+
|
|
11
|
+
Args:
|
|
12
|
+
value: The address string to validate
|
|
13
|
+
|
|
14
|
+
Returns:
|
|
15
|
+
Checksummed address string
|
|
16
|
+
|
|
17
|
+
Raises:
|
|
18
|
+
ValueError: If the address is invalid
|
|
19
|
+
"""
|
|
20
|
+
if not isinstance(value, str):
|
|
21
|
+
raise ValueError(f"Address must be a string, got {type(value)}")
|
|
22
|
+
|
|
23
|
+
if not is_address(value):
|
|
24
|
+
raise ValueError(f"Invalid Ethereum address: {value}")
|
|
25
|
+
|
|
26
|
+
# Return checksummed address (EIP-55)
|
|
27
|
+
return to_checksum_address(value)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
# Type alias for validated Ethereum addresses (similar to viem's Address type)
|
|
31
|
+
EthereumAddress = Annotated[
|
|
32
|
+
str,
|
|
33
|
+
Field(
|
|
34
|
+
...,
|
|
35
|
+
description="Ethereum address (validated and checksummed)",
|
|
36
|
+
examples=["0x1234567890123456789012345678901234567890"],
|
|
37
|
+
),
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
# Open Orders Method
|
|
42
|
+
class OpenOrdersParams(BaseModel):
|
|
43
|
+
"""Parameters for open orders query."""
|
|
44
|
+
user: str = Field(..., description="User address")
|
|
45
|
+
page: Optional[int] = Field(None, description="Page number")
|
|
46
|
+
limit: Optional[int] = Field(None, description="Number of orders per page")
|
|
47
|
+
|
|
48
|
+
@field_validator('user', mode='before')
|
|
49
|
+
@classmethod
|
|
50
|
+
def validate_user_address(cls, v: str) -> str:
|
|
51
|
+
"""Validate and checksum the user address."""
|
|
52
|
+
return validate_ethereum_address(v)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class OpenOrder(BaseModel):
|
|
56
|
+
"""Open order information."""
|
|
57
|
+
order_id: int
|
|
58
|
+
user: str
|
|
59
|
+
instrument_id: int
|
|
60
|
+
instrument: str
|
|
61
|
+
side: Literal["s", "b"]
|
|
62
|
+
limit_price: str
|
|
63
|
+
size: str
|
|
64
|
+
unfilled: str
|
|
65
|
+
state: Literal["open", "filled", "cancelled", "triggered"]
|
|
66
|
+
cloid: str
|
|
67
|
+
tif: Literal["GTC", "IOC", "FOK"]
|
|
68
|
+
tpsl: Literal["tp", "sl", ""]
|
|
69
|
+
trigger_px: str
|
|
70
|
+
trigger_price: Optional[str] = None
|
|
71
|
+
post_only: bool
|
|
72
|
+
reduce_only: bool
|
|
73
|
+
timestamp: str
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class OpenOrdersResponse(BaseModel):
|
|
77
|
+
"""Open orders response."""
|
|
78
|
+
orders: List[OpenOrder] = Field(..., description="List of open orders")
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
# Positions Method
|
|
82
|
+
class PositionsParams(BaseModel):
|
|
83
|
+
"""Parameters for positions query."""
|
|
84
|
+
user: str = Field(..., description="User address")
|
|
85
|
+
instrument: Optional[str] = Field(None, description="Filter by instrument")
|
|
86
|
+
|
|
87
|
+
@field_validator('user', mode='before')
|
|
88
|
+
@classmethod
|
|
89
|
+
def validate_user_address(cls, v: str) -> str:
|
|
90
|
+
"""Validate and checksum the user address."""
|
|
91
|
+
return validate_ethereum_address(v)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
class PositionsResponse(BaseModel):
|
|
95
|
+
"""Positions response."""
|
|
96
|
+
pass
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
# Account Summary Method
|
|
100
|
+
class AccountSummaryParams(BaseModel):
|
|
101
|
+
"""Parameters for account summary query."""
|
|
102
|
+
user: str = Field(..., description="User address")
|
|
103
|
+
|
|
104
|
+
@field_validator('user', mode='before')
|
|
105
|
+
@classmethod
|
|
106
|
+
def validate_user_address(cls, v: str) -> str:
|
|
107
|
+
"""Validate and checksum the user address."""
|
|
108
|
+
return validate_ethereum_address(v)
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
class AccountSummaryResponse(BaseModel):
|
|
112
|
+
"""Account summary response."""
|
|
113
|
+
total_balance: str
|
|
114
|
+
total_equity: str
|
|
115
|
+
total_free: str
|
|
116
|
+
total_margin: str
|
|
117
|
+
total_profit_loss: str
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
# Referral Summary Method
|
|
121
|
+
class ReferralSummaryParams(BaseModel):
|
|
122
|
+
"""Parameters for referral summary query."""
|
|
123
|
+
user: str = Field(..., description="User address")
|
|
124
|
+
|
|
125
|
+
@field_validator('user', mode='before')
|
|
126
|
+
@classmethod
|
|
127
|
+
def validate_user_address(cls, v: str) -> str:
|
|
128
|
+
"""Validate and checksum the user address."""
|
|
129
|
+
return validate_ethereum_address(v)
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
class ReferralSummaryResponse(BaseModel):
|
|
133
|
+
"""Referral summary response."""
|
|
134
|
+
pass
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
# User Fee Info Method
|
|
138
|
+
class UserFeeInfoParams(BaseModel):
|
|
139
|
+
"""Parameters for user fee info query."""
|
|
140
|
+
user: str = Field(..., description="User address")
|
|
141
|
+
|
|
142
|
+
@field_validator('user', mode='before')
|
|
143
|
+
@classmethod
|
|
144
|
+
def validate_user_address(cls, v: str) -> str:
|
|
145
|
+
"""Validate and checksum the user address."""
|
|
146
|
+
return validate_ethereum_address(v)
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
class UserFeeInfoResponse(BaseModel):
|
|
150
|
+
"""User fee info response."""
|
|
151
|
+
pass
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
# Account History Method
|
|
155
|
+
class AccountHistoryParams(BaseModel):
|
|
156
|
+
"""Parameters for account history query."""
|
|
157
|
+
user: str = Field(..., description="User address")
|
|
158
|
+
|
|
159
|
+
@field_validator('user', mode='before')
|
|
160
|
+
@classmethod
|
|
161
|
+
def validate_user_address(cls, v: str) -> str:
|
|
162
|
+
"""Validate and checksum the user address."""
|
|
163
|
+
return validate_ethereum_address(v)
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
class AccountHistoryResponse(BaseModel):
|
|
167
|
+
"""Account history response."""
|
|
168
|
+
pass
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
# Order History Method
|
|
172
|
+
class OrderHistoryParams(BaseModel):
|
|
173
|
+
"""Parameters for order history query."""
|
|
174
|
+
model_config = ConfigDict(populate_by_name=True)
|
|
175
|
+
|
|
176
|
+
user: str = Field(..., description="User address")
|
|
177
|
+
instrument_id: Optional[str] = Field(None, alias="instrumentId", description="Filter by instrument ID")
|
|
178
|
+
limit: Optional[int] = Field(None, description="Number of orders to return")
|
|
179
|
+
|
|
180
|
+
@field_validator('user', mode='before')
|
|
181
|
+
@classmethod
|
|
182
|
+
def validate_user_address(cls, v: str) -> str:
|
|
183
|
+
"""Validate and checksum the user address."""
|
|
184
|
+
return validate_ethereum_address(v)
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
class OrderHistoryResponse(BaseModel):
|
|
188
|
+
"""Order history response."""
|
|
189
|
+
pass
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
# Trade History Method
|
|
193
|
+
class TradeHistoryParams(BaseModel):
|
|
194
|
+
"""Parameters for trade history query."""
|
|
195
|
+
model_config = ConfigDict(populate_by_name=True)
|
|
196
|
+
|
|
197
|
+
user: str = Field(..., description="User address")
|
|
198
|
+
instrument_id: Optional[str] = Field(None, alias="instrumentId", description="Filter by instrument ID")
|
|
199
|
+
limit: Optional[int] = Field(None, description="Number of trades to return")
|
|
200
|
+
|
|
201
|
+
@field_validator('user', mode='before')
|
|
202
|
+
@classmethod
|
|
203
|
+
def validate_user_address(cls, v: str) -> str:
|
|
204
|
+
"""Validate and checksum the user address."""
|
|
205
|
+
return validate_ethereum_address(v)
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
class TradeHistoryResponse(BaseModel):
|
|
209
|
+
"""Trade history response."""
|
|
210
|
+
pass
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
# Funding History Method
|
|
214
|
+
class FundingHistoryParams(BaseModel):
|
|
215
|
+
"""Parameters for funding history query."""
|
|
216
|
+
user: str = Field(..., description="User address")
|
|
217
|
+
|
|
218
|
+
@field_validator('user', mode='before')
|
|
219
|
+
@classmethod
|
|
220
|
+
def validate_user_address(cls, v: str) -> str:
|
|
221
|
+
"""Validate and checksum the user address."""
|
|
222
|
+
return validate_ethereum_address(v)
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
class FundingHistoryResponse(BaseModel):
|
|
226
|
+
"""Funding history response."""
|
|
227
|
+
pass
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
# Transfer History Method
|
|
231
|
+
class TransferHistoryParams(BaseModel):
|
|
232
|
+
"""Parameters for transfer history query."""
|
|
233
|
+
user: str = Field(..., description="User address")
|
|
234
|
+
|
|
235
|
+
@field_validator('user', mode='before')
|
|
236
|
+
@classmethod
|
|
237
|
+
def validate_user_address(cls, v: str) -> str:
|
|
238
|
+
"""Validate and checksum the user address."""
|
|
239
|
+
return validate_ethereum_address(v)
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
class TransferHistoryResponse(BaseModel):
|
|
243
|
+
"""Transfer history response."""
|
|
244
|
+
pass
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
# Instrument Leverage Method
|
|
248
|
+
class InstrumentLeverageParams(BaseModel):
|
|
249
|
+
"""Parameters for instrument leverage query."""
|
|
250
|
+
user: str = Field(..., description="User address")
|
|
251
|
+
symbol: str = Field(..., description="Instrument symbol")
|
|
252
|
+
|
|
253
|
+
@field_validator('user', mode='before')
|
|
254
|
+
@classmethod
|
|
255
|
+
def validate_user_address(cls, v: str) -> str:
|
|
256
|
+
"""Validate and checksum the user address."""
|
|
257
|
+
return validate_ethereum_address(v)
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
class InstrumentLeverageResponse(BaseModel):
|
|
261
|
+
"""Instrument leverage response."""
|
|
262
|
+
pass
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
# Referral Info Method
|
|
266
|
+
class ReferralInfoParams(BaseModel):
|
|
267
|
+
"""Parameters for referral info query."""
|
|
268
|
+
user: str = Field(..., description="User address")
|
|
269
|
+
|
|
270
|
+
@field_validator('user', mode='before')
|
|
271
|
+
@classmethod
|
|
272
|
+
def validate_user_address(cls, v: str) -> str:
|
|
273
|
+
"""Validate and checksum the user address."""
|
|
274
|
+
return validate_ethereum_address(v)
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
class ReferralInfoResponse(BaseModel):
|
|
278
|
+
"""Referral info response."""
|
|
279
|
+
pass
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
# Sub Accounts List Method
|
|
283
|
+
class SubAccountsListParams(BaseModel):
|
|
284
|
+
"""Parameters for sub accounts list query."""
|
|
285
|
+
user: str = Field(..., description="User address")
|
|
286
|
+
|
|
287
|
+
@field_validator('user', mode='before')
|
|
288
|
+
@classmethod
|
|
289
|
+
def validate_user_address(cls, v: str) -> str:
|
|
290
|
+
"""Validate and checksum the user address."""
|
|
291
|
+
return validate_ethereum_address(v)
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
class SubAccountsListResponse(BaseModel):
|
|
295
|
+
"""Sub accounts list response."""
|
|
296
|
+
pass
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
# Agents Method
|
|
300
|
+
class AgentsParams(BaseModel):
|
|
301
|
+
"""Parameters for agents query."""
|
|
302
|
+
user: str = Field(..., description="User address")
|
|
303
|
+
|
|
304
|
+
@field_validator('user', mode='before')
|
|
305
|
+
@classmethod
|
|
306
|
+
def validate_user_address(cls, v: str) -> str:
|
|
307
|
+
"""Validate and checksum the user address."""
|
|
308
|
+
return validate_ethereum_address(v)
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
class Agent(BaseModel):
|
|
312
|
+
"""Agent information."""
|
|
313
|
+
user: str = Field(..., description="User address")
|
|
314
|
+
agent_address: Optional[str] = Field(None, description="Agent address")
|
|
315
|
+
agent_name: Optional[str] = Field(None, description="Agent name")
|
|
316
|
+
created_at_block_timestamp: Optional[int] = Field(None, description="Creation timestamp")
|
|
317
|
+
valid_until_timestamp: Optional[int] = Field(None, description="Validity expiration timestamp")
|
|
318
|
+
|
|
319
|
+
model_config = ConfigDict(populate_by_name=True)
|
|
320
|
+
|
|
321
|
+
@field_validator('user', 'agent_address', mode='before')
|
|
322
|
+
@classmethod
|
|
323
|
+
def validate_addresses(cls, v: Optional[str]) -> Optional[str]:
|
|
324
|
+
"""Validate and checksum Ethereum addresses."""
|
|
325
|
+
if v is None or v == "":
|
|
326
|
+
return v
|
|
327
|
+
return validate_ethereum_address(v)
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
class AgentsResponse(BaseModel):
|
|
331
|
+
"""Agents response."""
|
|
332
|
+
pass
|
|
333
|
+
|
|
334
|
+
|
|
335
|
+
# User Balance Info Method
|
|
336
|
+
class UserBalanceInfoParams(BaseModel):
|
|
337
|
+
"""Parameters for user balance info query."""
|
|
338
|
+
user: str = Field(..., description="User address")
|
|
339
|
+
type: Literal["all", "spot", "derivative"] = Field(..., description="Balance type")
|
|
340
|
+
|
|
341
|
+
@field_validator('user', mode='before')
|
|
342
|
+
@classmethod
|
|
343
|
+
def validate_user_address(cls, v: str) -> str:
|
|
344
|
+
"""Validate and checksum the user address."""
|
|
345
|
+
return validate_ethereum_address(v)
|
|
346
|
+
|
|
347
|
+
|
|
348
|
+
class UserBalanceInfoResponse(BaseModel):
|
|
349
|
+
"""User balance info response."""
|
|
350
|
+
pass
|
|
351
|
+
|
|
352
|
+
|
|
353
|
+
# Account Info Method
|
|
354
|
+
class AccountInfoParams(BaseModel):
|
|
355
|
+
"""Parameters for account info query."""
|
|
356
|
+
model_config = ConfigDict(populate_by_name=True)
|
|
357
|
+
|
|
358
|
+
user: str = Field(..., description="User address")
|
|
359
|
+
collateral_id: Optional[int] = Field(None, alias="collateralID", description="Collateral ID")
|
|
360
|
+
include_history: Optional[bool] = Field(None, alias="includeHistory", description="Include history")
|
|
361
|
+
|
|
362
|
+
@field_validator('user', mode='before')
|
|
363
|
+
@classmethod
|
|
364
|
+
def validate_user_address(cls, v: str) -> str:
|
|
365
|
+
"""Validate and checksum the user address."""
|
|
366
|
+
return validate_ethereum_address(v)
|
|
367
|
+
|
|
368
|
+
|
|
369
|
+
class AccountInfoResponse(BaseModel):
|
|
370
|
+
"""Account info response."""
|
|
371
|
+
pass
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"""Explorer info method types."""
|
|
2
|
+
from typing import Optional
|
|
3
|
+
from pydantic import BaseModel, Field
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
# Blocks Method
|
|
7
|
+
class BlocksParams(BaseModel):
|
|
8
|
+
"""Parameters for blocks query."""
|
|
9
|
+
offset: int = Field(..., description="Offset for pagination")
|
|
10
|
+
limit: int = Field(..., description="Number of blocks to return")
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class BlocksResponse(BaseModel):
|
|
14
|
+
"""Blocks response."""
|
|
15
|
+
pass
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
# Block Details Method
|
|
19
|
+
class BlockDetailsParams(BaseModel):
|
|
20
|
+
"""Parameters for block details query."""
|
|
21
|
+
block_hash: Optional[str] = Field(None, description="Block hash")
|
|
22
|
+
block_height: Optional[int] = Field(None, description="Block height")
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class BlockDetailsResponse(BaseModel):
|
|
26
|
+
"""Block details response."""
|
|
27
|
+
pass
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
# Transactions Method
|
|
31
|
+
class TransactionFilter(BaseModel):
|
|
32
|
+
"""Transaction filter."""
|
|
33
|
+
account: Optional[str] = Field(None, description="Filter by account")
|
|
34
|
+
tx_type: Optional[int] = Field(None, description="Filter by transaction type")
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class TransactionsParams(BaseModel):
|
|
38
|
+
"""Parameters for transactions query."""
|
|
39
|
+
offset: Optional[int] = Field(None, description="Offset for pagination")
|
|
40
|
+
limit: Optional[int] = Field(None, description="Number of transactions to return")
|
|
41
|
+
filter: Optional[TransactionFilter] = Field(None, description="Transaction filter")
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class TransactionsResponse(BaseModel):
|
|
45
|
+
"""Transactions response."""
|
|
46
|
+
pass
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
# Transaction Details Method
|
|
50
|
+
class TransactionDetailsParams(BaseModel):
|
|
51
|
+
"""Parameters for transaction details query."""
|
|
52
|
+
tx_hash: str = Field(..., description="Transaction hash")
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class TransactionDetailsResponse(BaseModel):
|
|
56
|
+
"""Transaction details response."""
|
|
57
|
+
pass
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
"""Global info method types."""
|
|
2
|
+
from typing import List, Literal, Optional, Union
|
|
3
|
+
from pydantic import BaseModel, Field, ConfigDict, field_validator
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
# Oracle Method
|
|
7
|
+
class OracleParams(BaseModel):
|
|
8
|
+
"""Parameters for oracle price query."""
|
|
9
|
+
symbol: str = Field(..., description="Symbol to get oracle price for")
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class OracleResponse(BaseModel):
|
|
13
|
+
"""Oracle price response."""
|
|
14
|
+
symbol: str
|
|
15
|
+
index_price: str
|
|
16
|
+
ext_mark_price: str
|
|
17
|
+
updated_at: int
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
# Supported Collateral Method
|
|
21
|
+
class SupportedCollateralParams(BaseModel):
|
|
22
|
+
"""Parameters for supported collateral query."""
|
|
23
|
+
pass
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class BridgeByChain(BaseModel):
|
|
27
|
+
"""Bridge chain configuration."""
|
|
28
|
+
bridge_chain_type: int
|
|
29
|
+
bridge_chain_id: int
|
|
30
|
+
token_address: str
|
|
31
|
+
bridge_contract_address: str
|
|
32
|
+
enabled: bool
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class WeightTier(BaseModel):
|
|
36
|
+
"""Weight tier configuration."""
|
|
37
|
+
amount: int
|
|
38
|
+
weight: int
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class CollRisk(BaseModel):
|
|
42
|
+
"""Collateral risk configuration."""
|
|
43
|
+
weight_tiers: List[WeightTier]
|
|
44
|
+
max_margin_cap: int
|
|
45
|
+
stale_price_guard_weight: int
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class SupportedCollateral(BaseModel):
|
|
49
|
+
"""Supported collateral information."""
|
|
50
|
+
id: int
|
|
51
|
+
symbol: str
|
|
52
|
+
name: str
|
|
53
|
+
decimals: int
|
|
54
|
+
default_coll_weight: int
|
|
55
|
+
price_index: str
|
|
56
|
+
type: int
|
|
57
|
+
bridge_by_chain: List[BridgeByChain]
|
|
58
|
+
coll_risk: List[CollRisk]
|
|
59
|
+
withdrawal_fee: int
|
|
60
|
+
added_at_block: int
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
# Instruments Method
|
|
64
|
+
class InstrumentsParams(BaseModel):
|
|
65
|
+
"""Parameters for instruments query."""
|
|
66
|
+
type: Literal["perps", "spot", "all"] = Field(..., description="Instrument type filter")
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class MarginTier(BaseModel):
|
|
70
|
+
"""Margin tier configuration."""
|
|
71
|
+
notional_usd_threshold: str
|
|
72
|
+
max_leverage: int
|
|
73
|
+
mmr: float # Can be fractional
|
|
74
|
+
mmd: int
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
class PerpInstrument(BaseModel):
|
|
78
|
+
"""Perpetual instrument information."""
|
|
79
|
+
id: int
|
|
80
|
+
name: str
|
|
81
|
+
price_index: str
|
|
82
|
+
lot_size: float # Can be fractional (e.g., 1e-05)
|
|
83
|
+
tick_size: float # Can be fractional (e.g., 0.1, 1e-06)
|
|
84
|
+
settlement_currency: int
|
|
85
|
+
only_isolated: bool
|
|
86
|
+
max_leverage: int
|
|
87
|
+
delisted: bool
|
|
88
|
+
min_notional_usd: int
|
|
89
|
+
margin_tiers: List[MarginTier]
|
|
90
|
+
listed_at_block_timestamp: int
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
class SpotInstrument(BaseModel):
|
|
94
|
+
"""Spot instrument information."""
|
|
95
|
+
id: int
|
|
96
|
+
name: str
|
|
97
|
+
price_index: str
|
|
98
|
+
lot_size: int
|
|
99
|
+
tick_size: float # Can be fractional (e.g., 0.0001)
|
|
100
|
+
base_asset: int
|
|
101
|
+
quote_asset: int
|
|
102
|
+
stable_pair: bool
|
|
103
|
+
min_size_in_quote_asset: int
|
|
104
|
+
listed_at_block_timestamp: int
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
class InstrumentsResponse(BaseModel):
|
|
108
|
+
"""Instruments response."""
|
|
109
|
+
perps: List[PerpInstrument]
|
|
110
|
+
spot: List[SpotInstrument]
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
# Ticker Method
|
|
114
|
+
class TickerParams(BaseModel):
|
|
115
|
+
"""Parameters for ticker query."""
|
|
116
|
+
symbol: str = Field(..., description="Trading pair symbol")
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
class Ticker(BaseModel):
|
|
120
|
+
"""Ticker information."""
|
|
121
|
+
type: Literal["perp", "spot"]
|
|
122
|
+
symbol: str
|
|
123
|
+
mark_price: str
|
|
124
|
+
mid_price: str
|
|
125
|
+
index_price: str
|
|
126
|
+
best_bid_price: str
|
|
127
|
+
best_ask_price: str
|
|
128
|
+
best_bid_size: str
|
|
129
|
+
best_ask_size: str
|
|
130
|
+
funding_rate: str
|
|
131
|
+
open_interest: str
|
|
132
|
+
volume_24h: str
|
|
133
|
+
change_24h: str
|
|
134
|
+
max_trading_price: str
|
|
135
|
+
min_trading_price: str
|
|
136
|
+
last_updated: int
|
|
137
|
+
last_price: str
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
# Orderbook Method
|
|
141
|
+
class OrderbookParams(BaseModel):
|
|
142
|
+
"""Parameters for orderbook query."""
|
|
143
|
+
symbol: str = Field(..., description="Trading pair symbol")
|
|
144
|
+
depth: Optional[int] = Field(None, description="Orderbook depth")
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
class OrderbookLevel(BaseModel):
|
|
148
|
+
"""Orderbook level (bid/ask)."""
|
|
149
|
+
price: str # API may return int/float, but we store as string for precision
|
|
150
|
+
size: str # API may return int/float, but we store as string for precision
|
|
151
|
+
|
|
152
|
+
@field_validator('price', mode='before')
|
|
153
|
+
@classmethod
|
|
154
|
+
def convert_price_to_string(cls, v: Union[str, int, float]) -> str:
|
|
155
|
+
"""Convert numeric price to string."""
|
|
156
|
+
if not isinstance(v, str):
|
|
157
|
+
return str(v)
|
|
158
|
+
return v
|
|
159
|
+
|
|
160
|
+
@field_validator('size', mode='before')
|
|
161
|
+
@classmethod
|
|
162
|
+
def convert_size_to_string(cls, v: Union[str, int, float]) -> str:
|
|
163
|
+
"""Convert numeric size to string."""
|
|
164
|
+
if not isinstance(v, str):
|
|
165
|
+
return str(v)
|
|
166
|
+
return v
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
class OrderbookResponse(BaseModel):
|
|
170
|
+
"""Orderbook response."""
|
|
171
|
+
bids: List[OrderbookLevel]
|
|
172
|
+
asks: List[OrderbookLevel]
|
|
173
|
+
instrument_name: str
|
|
174
|
+
timestamp: int
|
|
175
|
+
sequence_number: int
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
# Trades Method
|
|
179
|
+
class TradesParams(BaseModel):
|
|
180
|
+
"""Parameters for trades query."""
|
|
181
|
+
symbol: str = Field(..., description="Trading pair symbol")
|
|
182
|
+
limit: Optional[int] = Field(None, description="Number of trades to return")
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
class Trade(BaseModel):
|
|
186
|
+
"""Trade information."""
|
|
187
|
+
instrument_id: int
|
|
188
|
+
instrument: str
|
|
189
|
+
trade_id: int
|
|
190
|
+
tx_hash: str
|
|
191
|
+
side: Literal["b", "s"]
|
|
192
|
+
price: str
|
|
193
|
+
size: str
|
|
194
|
+
maker: str
|
|
195
|
+
taker: str
|
|
196
|
+
timestamp: str
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
# Mids Method
|
|
200
|
+
class MidsParams(BaseModel):
|
|
201
|
+
"""Parameters for mids query."""
|
|
202
|
+
pass
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
class Mid(BaseModel):
|
|
206
|
+
"""Mid price information."""
|
|
207
|
+
symbol: str
|
|
208
|
+
mid_price: str
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
# BBO Method
|
|
212
|
+
class BBOParams(BaseModel):
|
|
213
|
+
"""Parameters for best bid/offer query."""
|
|
214
|
+
symbol: str = Field(..., description="Trading pair symbol")
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
class BBO(BaseModel):
|
|
218
|
+
"""Best bid/offer information."""
|
|
219
|
+
symbol: str
|
|
220
|
+
best_bid_price: str
|
|
221
|
+
best_ask_price: str
|
|
222
|
+
best_bid_size: str
|
|
223
|
+
best_ask_size: str
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
# Chart Method
|
|
227
|
+
SupportedChartResolutions = Literal["1", "5", "15", "60", "240", "1D", "1W"]
|
|
228
|
+
SupportedChartTypes = Literal["mark", "ltp", "index"]
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
class ChartParams(BaseModel):
|
|
232
|
+
"""Parameters for chart data query."""
|
|
233
|
+
model_config = ConfigDict(populate_by_name=True)
|
|
234
|
+
|
|
235
|
+
symbol: str = Field(..., description="Trading pair symbol")
|
|
236
|
+
resolution: SupportedChartResolutions = Field(..., description="Chart resolution")
|
|
237
|
+
from_: int = Field(..., alias="from", description="Start timestamp")
|
|
238
|
+
to: int = Field(..., description="End timestamp")
|
|
239
|
+
chart_type: SupportedChartTypes = Field(..., description="Chart type")
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
class ChartPoint(BaseModel):
|
|
243
|
+
"""Chart data point."""
|
|
244
|
+
open: float
|
|
245
|
+
high: float
|
|
246
|
+
low: float
|
|
247
|
+
close: float
|
|
248
|
+
volume: float
|
|
249
|
+
time: int
|