ddx-python 1.0.5__cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.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.
- ddx/.gitignore +1 -0
- ddx/__init__.py +58 -0
- ddx/_rust/__init__.pyi +2009 -0
- ddx/_rust/common/__init__.pyi +17 -0
- ddx/_rust/common/accounting.pyi +6 -0
- ddx/_rust/common/enums.pyi +3 -0
- ddx/_rust/common/requests/__init__.pyi +21 -0
- ddx/_rust/common/requests/intents.pyi +19 -0
- ddx/_rust/common/specs.pyi +17 -0
- ddx/_rust/common/state/__init__.pyi +41 -0
- ddx/_rust/common/state/keys.pyi +29 -0
- ddx/_rust/common/transactions.pyi +7 -0
- ddx/_rust/decimal.pyi +3 -0
- ddx/_rust/h256.pyi +3 -0
- ddx/_rust.abi3.so +0 -0
- ddx/app_config/ethereum/addresses.json +541 -0
- ddx/auditor/README.md +32 -0
- ddx/auditor/__init__.py +0 -0
- ddx/auditor/auditor_driver.py +1034 -0
- ddx/auditor/websocket_message.py +54 -0
- ddx/common/__init__.py +0 -0
- ddx/common/epoch_params.py +28 -0
- ddx/common/fill_context.py +144 -0
- ddx/common/item_utils.py +38 -0
- ddx/common/logging.py +184 -0
- ddx/common/market_specs.py +64 -0
- ddx/common/trade_mining_params.py +19 -0
- ddx/common/transaction_utils.py +85 -0
- ddx/common/transactions/__init__.py +0 -0
- ddx/common/transactions/advance_epoch.py +91 -0
- ddx/common/transactions/advance_settlement_epoch.py +63 -0
- ddx/common/transactions/all_price_checkpoints.py +84 -0
- ddx/common/transactions/cancel.py +76 -0
- ddx/common/transactions/cancel_all.py +88 -0
- ddx/common/transactions/complete_fill.py +103 -0
- ddx/common/transactions/disaster_recovery.py +97 -0
- ddx/common/transactions/event.py +48 -0
- ddx/common/transactions/fee_distribution.py +119 -0
- ddx/common/transactions/funding.py +294 -0
- ddx/common/transactions/futures_expiry.py +123 -0
- ddx/common/transactions/genesis.py +108 -0
- ddx/common/transactions/inner/__init__.py +0 -0
- ddx/common/transactions/inner/adl_outcome.py +25 -0
- ddx/common/transactions/inner/fill.py +227 -0
- ddx/common/transactions/inner/liquidated_position.py +41 -0
- ddx/common/transactions/inner/liquidation_entry.py +41 -0
- ddx/common/transactions/inner/liquidation_fill.py +118 -0
- ddx/common/transactions/inner/outcome.py +32 -0
- ddx/common/transactions/inner/trade_fill.py +125 -0
- ddx/common/transactions/insurance_fund_update.py +142 -0
- ddx/common/transactions/insurance_fund_withdraw.py +99 -0
- ddx/common/transactions/liquidation.py +357 -0
- ddx/common/transactions/partial_fill.py +125 -0
- ddx/common/transactions/pnl_realization.py +122 -0
- ddx/common/transactions/post.py +72 -0
- ddx/common/transactions/post_order.py +95 -0
- ddx/common/transactions/price_checkpoint.py +96 -0
- ddx/common/transactions/signer_registered.py +62 -0
- ddx/common/transactions/specs_update.py +61 -0
- ddx/common/transactions/strategy_update.py +156 -0
- ddx/common/transactions/tradable_product_update.py +98 -0
- ddx/common/transactions/trade_mining.py +147 -0
- ddx/common/transactions/trader_update.py +105 -0
- ddx/common/transactions/withdraw.py +91 -0
- ddx/common/transactions/withdraw_ddx.py +74 -0
- ddx/common/utils.py +176 -0
- ddx/config.py +17 -0
- ddx/derivadex_client.py +254 -0
- ddx/py.typed +0 -0
- ddx/realtime_client/__init__.py +2 -0
- ddx/realtime_client/config.py +2 -0
- ddx/realtime_client/logs/pytest.log +0 -0
- ddx/realtime_client/models/__init__.py +683 -0
- ddx/realtime_client/realtime_client.py +567 -0
- ddx/rest_client/__init__.py +0 -0
- ddx/rest_client/clients/__init__.py +0 -0
- ddx/rest_client/clients/base_client.py +60 -0
- ddx/rest_client/clients/market_client.py +1241 -0
- ddx/rest_client/clients/on_chain_client.py +432 -0
- ddx/rest_client/clients/signed_client.py +301 -0
- ddx/rest_client/clients/system_client.py +843 -0
- ddx/rest_client/clients/trade_client.py +335 -0
- ddx/rest_client/constants/__init__.py +0 -0
- ddx/rest_client/constants/endpoints.py +67 -0
- ddx/rest_client/contracts/__init__.py +0 -0
- ddx/rest_client/contracts/checkpoint/__init__.py +560 -0
- ddx/rest_client/contracts/ddx/__init__.py +1949 -0
- ddx/rest_client/contracts/dummy_token/__init__.py +1014 -0
- ddx/rest_client/contracts/i_collateral/__init__.py +1414 -0
- ddx/rest_client/contracts/i_stake/__init__.py +696 -0
- ddx/rest_client/exceptions/__init__.py +0 -0
- ddx/rest_client/exceptions/exceptions.py +32 -0
- ddx/rest_client/http/__init__.py +0 -0
- ddx/rest_client/http/http_client.py +305 -0
- ddx/rest_client/models/__init__.py +0 -0
- ddx/rest_client/models/market.py +683 -0
- ddx/rest_client/models/signed.py +60 -0
- ddx/rest_client/models/system.py +390 -0
- ddx/rest_client/models/trade.py +140 -0
- ddx/rest_client/utils/__init__.py +0 -0
- ddx/rest_client/utils/encryption_utils.py +26 -0
- ddx_python-1.0.5.dist-info/METADATA +63 -0
- ddx_python-1.0.5.dist-info/RECORD +104 -0
- ddx_python-1.0.5.dist-info/WHEEL +4 -0
|
File without changes
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
from typing import Optional, Dict, Any
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class HTTPClientError(Exception):
|
|
5
|
+
"""Base exception for HTTP client errors."""
|
|
6
|
+
|
|
7
|
+
def __init__(
|
|
8
|
+
self,
|
|
9
|
+
request: str,
|
|
10
|
+
message: str,
|
|
11
|
+
status_code: int,
|
|
12
|
+
time: str,
|
|
13
|
+
response: Optional[Dict[str, Any]] = None,
|
|
14
|
+
):
|
|
15
|
+
self.request = request
|
|
16
|
+
self.message = message
|
|
17
|
+
self.status_code = status_code
|
|
18
|
+
self.time = time
|
|
19
|
+
self.response = response
|
|
20
|
+
super().__init__(f"{message} (Status: {status_code}, Time: {time})")
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class InvalidRequestError(HTTPClientError):
|
|
24
|
+
"""Exception raised for API-specific errors."""
|
|
25
|
+
|
|
26
|
+
pass
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class FailedRequestError(HTTPClientError):
|
|
30
|
+
"""Exception raised for HTTP request failures."""
|
|
31
|
+
|
|
32
|
+
pass
|
|
File without changes
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import json
|
|
3
|
+
from datetime import datetime
|
|
4
|
+
from typing import Optional, Dict, Any
|
|
5
|
+
import logging
|
|
6
|
+
from httpx import AsyncClient, RequestError
|
|
7
|
+
|
|
8
|
+
from ddx.rest_client.exceptions.exceptions import (
|
|
9
|
+
InvalidRequestError,
|
|
10
|
+
FailedRequestError,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class HTTPClient:
|
|
15
|
+
"""
|
|
16
|
+
HTTP client for DerivaDEX API.
|
|
17
|
+
|
|
18
|
+
Handles request preparation and response processing.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
def __init__(
|
|
22
|
+
self,
|
|
23
|
+
timeout: int = 10,
|
|
24
|
+
max_retries: int = 3,
|
|
25
|
+
retry_delay: int = 1,
|
|
26
|
+
logger: Optional[logging.Logger] = None,
|
|
27
|
+
):
|
|
28
|
+
"""
|
|
29
|
+
Initialize the HTTP client.
|
|
30
|
+
|
|
31
|
+
Parameters
|
|
32
|
+
----------
|
|
33
|
+
timeout : int
|
|
34
|
+
Request timeout in seconds
|
|
35
|
+
max_retries : int
|
|
36
|
+
Maximum number of retry attempts
|
|
37
|
+
retry_delay : int
|
|
38
|
+
Delay between retries in seconds
|
|
39
|
+
logger : Optional[logging.Logger]
|
|
40
|
+
Logger instance
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
self.timeout = timeout
|
|
44
|
+
self.max_retries = max_retries
|
|
45
|
+
self.retry_delay = retry_delay
|
|
46
|
+
|
|
47
|
+
# Setup logging
|
|
48
|
+
self.logger = logger or logging.getLogger(__name__)
|
|
49
|
+
|
|
50
|
+
# Initialize client to None - will be created in __aenter__
|
|
51
|
+
self.client: Optional[AsyncClient] = None
|
|
52
|
+
|
|
53
|
+
# Define retry status codes
|
|
54
|
+
self.retry_codes = {408, 429, 500, 502, 503, 504}
|
|
55
|
+
|
|
56
|
+
async def __aenter__(self):
|
|
57
|
+
"""
|
|
58
|
+
Context manager entry point. Initializes the HTTP client.
|
|
59
|
+
|
|
60
|
+
Returns
|
|
61
|
+
-------
|
|
62
|
+
BaseHTTPClient
|
|
63
|
+
The client instance
|
|
64
|
+
"""
|
|
65
|
+
|
|
66
|
+
self.client = AsyncClient(
|
|
67
|
+
timeout=self.timeout,
|
|
68
|
+
follow_redirects=True,
|
|
69
|
+
headers={"Content-Type": "application/json"},
|
|
70
|
+
)
|
|
71
|
+
self.logger.debug("HTTP client initialized")
|
|
72
|
+
|
|
73
|
+
return self
|
|
74
|
+
|
|
75
|
+
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
|
76
|
+
"""
|
|
77
|
+
Context manager exit point. Ensures proper cleanup of resources.
|
|
78
|
+
|
|
79
|
+
Parameters
|
|
80
|
+
----------
|
|
81
|
+
exc_type : Type[Exception], optional
|
|
82
|
+
The exception type if an exception was raised
|
|
83
|
+
exc_val : Exception, optional
|
|
84
|
+
The exception value if an exception was raised
|
|
85
|
+
exc_tb : TracebackType, optional
|
|
86
|
+
The traceback if an exception was raised
|
|
87
|
+
"""
|
|
88
|
+
|
|
89
|
+
if self.client:
|
|
90
|
+
await self.client.aclose()
|
|
91
|
+
self.client = None
|
|
92
|
+
self.logger.debug("HTTP client closed")
|
|
93
|
+
|
|
94
|
+
async def get(
|
|
95
|
+
self,
|
|
96
|
+
url: str,
|
|
97
|
+
params: Optional[Dict[str, Any]] = None,
|
|
98
|
+
headers: Optional[Dict[str, str]] = None,
|
|
99
|
+
) -> Dict[str, Any]:
|
|
100
|
+
"""
|
|
101
|
+
Send a GET request.
|
|
102
|
+
|
|
103
|
+
Parameters
|
|
104
|
+
----------
|
|
105
|
+
url : str
|
|
106
|
+
The URL to send the request to
|
|
107
|
+
params : Optional[Dict[str, Any]]
|
|
108
|
+
Query parameters
|
|
109
|
+
headers : Optional[Dict[str, str]]
|
|
110
|
+
Additional headers
|
|
111
|
+
|
|
112
|
+
Returns
|
|
113
|
+
-------
|
|
114
|
+
Dict[str, Any]
|
|
115
|
+
The response data
|
|
116
|
+
|
|
117
|
+
Raises
|
|
118
|
+
------
|
|
119
|
+
FailedRequestError
|
|
120
|
+
If the request fails after retries
|
|
121
|
+
InvalidRequestError
|
|
122
|
+
If the API returns an error response
|
|
123
|
+
"""
|
|
124
|
+
|
|
125
|
+
return await self._request("GET", url, params=params, headers=headers)
|
|
126
|
+
|
|
127
|
+
async def post(
|
|
128
|
+
self,
|
|
129
|
+
url: str,
|
|
130
|
+
data: Any = None,
|
|
131
|
+
json_data: Optional[Dict[str, Any]] = None,
|
|
132
|
+
headers: Optional[Dict[str, str]] = None,
|
|
133
|
+
) -> Dict[str, Any]:
|
|
134
|
+
"""
|
|
135
|
+
Send a POST request.
|
|
136
|
+
|
|
137
|
+
Parameters
|
|
138
|
+
----------
|
|
139
|
+
url : str
|
|
140
|
+
The URL to send the request to
|
|
141
|
+
data : Any
|
|
142
|
+
Raw request body
|
|
143
|
+
json_data : Optional[Dict[str, Any]]
|
|
144
|
+
JSON data to serialize
|
|
145
|
+
headers : Optional[Dict[str, str]]
|
|
146
|
+
Additional headers
|
|
147
|
+
|
|
148
|
+
Returns
|
|
149
|
+
-------
|
|
150
|
+
Dict[str, Any]
|
|
151
|
+
The response data
|
|
152
|
+
|
|
153
|
+
Raises
|
|
154
|
+
------
|
|
155
|
+
FailedRequestError
|
|
156
|
+
If the request fails after retries
|
|
157
|
+
InvalidRequestError
|
|
158
|
+
If the API returns an error response
|
|
159
|
+
"""
|
|
160
|
+
|
|
161
|
+
return await self._request(
|
|
162
|
+
"POST", url, data=data, json_data=json_data, headers=headers
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
async def _request(
|
|
166
|
+
self,
|
|
167
|
+
method: str,
|
|
168
|
+
url: str,
|
|
169
|
+
params: Optional[Dict[str, Any]] = None,
|
|
170
|
+
data: Any = None,
|
|
171
|
+
json_data: Optional[Dict[str, Any]] = None,
|
|
172
|
+
headers: Optional[Dict[str, str]] = None,
|
|
173
|
+
) -> Dict[str, Any]:
|
|
174
|
+
"""
|
|
175
|
+
Execute HTTP request with retries and error handling.
|
|
176
|
+
|
|
177
|
+
Parameters
|
|
178
|
+
----------
|
|
179
|
+
method : str
|
|
180
|
+
HTTP method (GET, POST, etc.)
|
|
181
|
+
url : str
|
|
182
|
+
The URL to send the request to
|
|
183
|
+
params : Optional[Dict[str, Any]]
|
|
184
|
+
Query parameters
|
|
185
|
+
data : Any
|
|
186
|
+
Raw request body
|
|
187
|
+
json_data : Optional[Dict[str, Any]]
|
|
188
|
+
JSON data to serialize
|
|
189
|
+
headers : Optional[Dict[str, str]]
|
|
190
|
+
Additional headers
|
|
191
|
+
|
|
192
|
+
Returns
|
|
193
|
+
-------
|
|
194
|
+
Dict[str, Any]
|
|
195
|
+
The response data
|
|
196
|
+
|
|
197
|
+
Raises
|
|
198
|
+
------
|
|
199
|
+
FailedRequestError
|
|
200
|
+
If the request fails after retries
|
|
201
|
+
InvalidRequestError
|
|
202
|
+
If the API returns an error response
|
|
203
|
+
RuntimeError
|
|
204
|
+
If the client is not initialized
|
|
205
|
+
"""
|
|
206
|
+
|
|
207
|
+
if self.client is None:
|
|
208
|
+
raise RuntimeError(
|
|
209
|
+
"HTTP client not initialized. Use 'async with' context manager."
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
request_info = (
|
|
213
|
+
f"{method} {url}; params: {params}; json: {json_data}; data: {data}"
|
|
214
|
+
)
|
|
215
|
+
|
|
216
|
+
self.logger.debug(f"Request: {request_info}")
|
|
217
|
+
|
|
218
|
+
retries = 0
|
|
219
|
+
while retries <= self.max_retries:
|
|
220
|
+
try:
|
|
221
|
+
response = await self.client.request(
|
|
222
|
+
method=method,
|
|
223
|
+
url=url,
|
|
224
|
+
params=params,
|
|
225
|
+
content=data,
|
|
226
|
+
json=json_data,
|
|
227
|
+
headers=headers,
|
|
228
|
+
)
|
|
229
|
+
|
|
230
|
+
# Log response status
|
|
231
|
+
self.logger.debug(f"Response status: {response.status_code}")
|
|
232
|
+
|
|
233
|
+
# Check if the request was successful
|
|
234
|
+
if response.status_code == 200:
|
|
235
|
+
try:
|
|
236
|
+
response_data = response.json()
|
|
237
|
+
|
|
238
|
+
# Check for API-specific errors in the response
|
|
239
|
+
if isinstance(response_data, dict) and not response_data.get(
|
|
240
|
+
"success", True
|
|
241
|
+
):
|
|
242
|
+
error_msg = response_data.get(
|
|
243
|
+
"errorMsg", "Unknown API error"
|
|
244
|
+
)
|
|
245
|
+
raise InvalidRequestError(
|
|
246
|
+
request=request_info,
|
|
247
|
+
message=error_msg,
|
|
248
|
+
status_code=response.status_code,
|
|
249
|
+
time=datetime.now().strftime("%H:%M:%S"),
|
|
250
|
+
response=response_data,
|
|
251
|
+
)
|
|
252
|
+
|
|
253
|
+
return response_data
|
|
254
|
+
except json.JSONDecodeError:
|
|
255
|
+
# Failed to parse JSON response
|
|
256
|
+
raise FailedRequestError(
|
|
257
|
+
request=request_info,
|
|
258
|
+
message="Failed to parse JSON response",
|
|
259
|
+
status_code=response.status_code,
|
|
260
|
+
time=datetime.now().strftime("%H:%M:%S"),
|
|
261
|
+
response={"text": response.text},
|
|
262
|
+
)
|
|
263
|
+
|
|
264
|
+
# Handle retry-able status codes
|
|
265
|
+
if (
|
|
266
|
+
response.status_code in self.retry_codes
|
|
267
|
+
and retries < self.max_retries
|
|
268
|
+
):
|
|
269
|
+
wait_time = self.retry_delay * (2**retries)
|
|
270
|
+
self.logger.warning(
|
|
271
|
+
f"Request failed with status {response.status_code}. "
|
|
272
|
+
f"Retrying in {wait_time}s ({retries+1}/{self.max_retries})"
|
|
273
|
+
)
|
|
274
|
+
await asyncio.sleep(wait_time)
|
|
275
|
+
retries += 1
|
|
276
|
+
continue
|
|
277
|
+
|
|
278
|
+
# Non-retryable error or max retries reached
|
|
279
|
+
raise FailedRequestError(
|
|
280
|
+
request=request_info,
|
|
281
|
+
message=f"Request failed with status {response.status_code}",
|
|
282
|
+
status_code=response.status_code,
|
|
283
|
+
time=datetime.now().strftime("%H:%M:%S"),
|
|
284
|
+
response={"text": response.text},
|
|
285
|
+
)
|
|
286
|
+
|
|
287
|
+
except RequestError as e:
|
|
288
|
+
# Network-related errors
|
|
289
|
+
if retries < self.max_retries:
|
|
290
|
+
wait_time = self.retry_delay * (2**retries)
|
|
291
|
+
self.logger.warning(
|
|
292
|
+
f"Request error: {str(e)}. "
|
|
293
|
+
f"Retrying in {wait_time}s ({retries+1}/{self.max_retries})"
|
|
294
|
+
)
|
|
295
|
+
await asyncio.sleep(wait_time)
|
|
296
|
+
retries += 1
|
|
297
|
+
continue
|
|
298
|
+
|
|
299
|
+
raise FailedRequestError(
|
|
300
|
+
request=request_info,
|
|
301
|
+
message=f"Request error: {str(e)}",
|
|
302
|
+
status_code=0,
|
|
303
|
+
time=datetime.now().strftime("%H:%M:%S"),
|
|
304
|
+
response=None,
|
|
305
|
+
)
|
|
File without changes
|