deltadefi 0.0.10__py3-none-any.whl → 0.1.0__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.

Potentially problematic release.


This version of deltadefi might be problematic. Click here for more details.

deltadefi/__init__.py CHANGED
@@ -1,2 +1,2 @@
1
1
  # flake8: noqa
2
- from .clients import ApiClient
2
+ from .clients import ApiClient, WebSocketClient
deltadefi/api.py CHANGED
@@ -6,7 +6,7 @@ from deltadefi.error import ClientError, ServerError
6
6
  from deltadefi.lib.utils import clean_none_value, encoded_string
7
7
 
8
8
 
9
- class API(object):
9
+ class API:
10
10
  def __init__(self, base_url=None, api_key=None, timeout=None, **kwargs):
11
11
  self.base_url = base_url
12
12
  self.api_key = api_key
@@ -73,10 +73,10 @@ class API(object):
73
73
  if 400 <= status_code < 500:
74
74
  try:
75
75
  err = json.loads(response.text)
76
- except json.JSONDecodeError:
76
+ except json.JSONDecodeError as e:
77
77
  raise ClientError(
78
78
  status_code, None, response.text, response.headers, None
79
- )
79
+ ) from e
80
80
  error_data = None
81
81
  if "data" in err:
82
82
  error_data = err["data"]
@@ -1,16 +1,15 @@
1
1
  from dataclasses import dataclass
2
- from typing import Optional
3
2
 
4
3
 
5
4
  @dataclass
6
5
  class AuthHeaders:
7
6
  jwt: str
8
- apiKey: str
7
+ api_key: str
9
8
 
10
9
 
11
10
  class ApiHeaders:
12
11
  __annotations__ = {
13
12
  "Content-Type": str,
14
- "Authorization": Optional[str],
15
- "X-API-KEY": Optional[str],
13
+ "Authorization": str | None,
14
+ "X-API-KEY": str | None,
16
15
  }
@@ -1,2 +1,3 @@
1
1
  # flake8: noqa
2
2
  from .client import *
3
+ from .websocket import WebSocketClient
@@ -1,5 +1,4 @@
1
1
  #
2
- from typing import List
3
2
 
4
3
  from sidan_gin import Asset, UTxO
5
4
 
@@ -12,12 +11,17 @@ from deltadefi.responses import (
12
11
  CreateNewAPIKeyResponse,
13
12
  GetAccountBalanceResponse,
14
13
  GetDepositRecordsResponse,
15
- GetOrderRecordResponse,
16
14
  GetWithdrawalRecordsResponse,
17
15
  SubmitDepositTransactionResponse,
18
16
  SubmitWithdrawalTransactionResponse,
19
17
  )
20
- from deltadefi.responses.accounts import GetOperationKeyResponse
18
+ from deltadefi.responses.accounts import (
19
+ BuildTransferalTransactionResponse,
20
+ GetOperationKeyResponse,
21
+ GetOrderRecordResponse,
22
+ GetOrderRecordsResponse,
23
+ SubmitTransferalTransactionResponse,
24
+ )
21
25
 
22
26
 
23
27
  class Accounts(API):
@@ -74,7 +78,7 @@ class Accounts(API):
74
78
 
75
79
  def get_order_records(
76
80
  self, status: OrderStatusType, **kwargs
77
- ) -> GetOrderRecordResponse:
81
+ ) -> GetOrderRecordsResponse:
78
82
  """
79
83
  Get order records.
80
84
 
@@ -85,7 +89,7 @@ class Accounts(API):
85
89
  page: Optional; The page number for pagination. Defaults to 1.
86
90
 
87
91
  Returns:
88
- A GetOrderRecordResponse object containing the order records.
92
+ A GetOrderRecordsResponse object containing the order records.
89
93
  """
90
94
  check_required_parameter(status, "status")
91
95
  payload = {"status": status, **kwargs}
@@ -93,6 +97,21 @@ class Accounts(API):
93
97
  url_path = "/order-records"
94
98
  return self.send_request("GET", self.group_url_path + url_path, payload)
95
99
 
100
+ def get_order_record(self, order_id: str, **kwargs) -> GetOrderRecordResponse:
101
+ """
102
+ Get a single order record by order ID.
103
+
104
+ Args:
105
+ order_id: The ID of the order to retrieve.
106
+
107
+ Returns:
108
+ A GetOrderRecordResponse object containing the order record.
109
+ """
110
+ check_required_parameter(order_id, "order_id")
111
+
112
+ url_path = f"/order/{order_id}"
113
+ return self.send_request("GET", self.group_url_path + url_path, kwargs)
114
+
96
115
  def get_account_balance(self, **kwargs) -> GetAccountBalanceResponse:
97
116
  """
98
117
  Get account balance.
@@ -104,7 +123,7 @@ class Accounts(API):
104
123
  return self.send_request("GET", self.group_url_path + url_path, kwargs)
105
124
 
106
125
  def build_deposit_transaction(
107
- self, deposit_amount: List[Asset], input_utxos: List[UTxO], **kwargs
126
+ self, deposit_amount: list[Asset], input_utxos: list[UTxO], **kwargs
108
127
  ) -> BuildDepositTransactionResponse:
109
128
  """
110
129
  Build a deposit transaction.
@@ -129,7 +148,7 @@ class Accounts(API):
129
148
  return self.send_request("POST", self.group_url_path + url_path, payload)
130
149
 
131
150
  def build_withdrawal_transaction(
132
- self, withdrawal_amount: List[Asset], **kwargs
151
+ self, withdrawal_amount: list[Asset], **kwargs
133
152
  ) -> BuildWithdrawalTransactionResponse:
134
153
  """
135
154
  Build a withdrawal transaction.
@@ -147,6 +166,31 @@ class Accounts(API):
147
166
  url_path = "/withdrawal/build"
148
167
  return self.send_request("POST", self.group_url_path + url_path, payload)
149
168
 
169
+ def build_transferal_transaction(
170
+ self, transferal_amount: list[Asset], to_address: str, **kwargs
171
+ ) -> BuildTransferalTransactionResponse:
172
+ """
173
+ Build a transferal transaction.
174
+
175
+ Args:
176
+ data: A BuildTransferalTransactionRequest object containing the transferal transaction details.
177
+
178
+ Returns:
179
+ A BuildTransferalTransactionResponse object containing the built transferal transaction.
180
+ """
181
+
182
+ check_required_parameter(
183
+ transferal_amount, "transferal_amount", to_address, "to_address"
184
+ )
185
+ payload = {
186
+ "transferal_amount": transferal_amount,
187
+ "to_address": to_address,
188
+ **kwargs,
189
+ }
190
+
191
+ url_path = "/transferal/build"
192
+ return self.send_request("POST", self.group_url_path + url_path, payload)
193
+
150
194
  def submit_deposit_transaction(
151
195
  self, signed_tx: str, **kwargs
152
196
  ) -> SubmitDepositTransactionResponse:
@@ -184,3 +228,22 @@ class Accounts(API):
184
228
 
185
229
  url_path = "/withdrawal/submit"
186
230
  return self.send_request("POST", self.group_url_path + url_path, payload)
231
+
232
+ def submit_transferal_transaction(
233
+ self, signed_tx: str, **kwargs
234
+ ) -> SubmitTransferalTransactionResponse:
235
+ """
236
+ Submit a transferal transaction.
237
+
238
+ Args:
239
+ data: A SubmitTransferalTransactionRequest object containing the transferal transaction details.
240
+
241
+ Returns:
242
+ A SubmitTransferalTransactionResponse object containing the submitted transferal transaction.
243
+ """
244
+
245
+ check_required_parameter(signed_tx, "signed_tx")
246
+ payload = {"signed_tx": signed_tx, **kwargs}
247
+
248
+ url_path = "/transferal/submit"
249
+ return self.send_request("POST", self.group_url_path + url_path, payload)
@@ -1,10 +1,9 @@
1
- # flake8: noqa: E501
2
1
  from sidan_gin import Wallet, decrypt_with_cipher
3
2
 
4
3
  from deltadefi.clients.accounts import Accounts
5
- from deltadefi.clients.app import App
6
4
  from deltadefi.clients.markets import Market
7
5
  from deltadefi.clients.orders import Order
6
+ from deltadefi.clients.websocket import WebSocketClient
8
7
  from deltadefi.models.models import OrderSide, OrderType
9
8
  from deltadefi.responses import PostOrderResponse
10
9
 
@@ -17,9 +16,9 @@ class ApiClient:
17
16
  def __init__(
18
17
  self,
19
18
  network: str = "preprod",
20
- api_key: str = None,
21
- base_url: str = None,
22
- master_wallet: Wallet = None,
19
+ api_key: str | None = None,
20
+ base_url: str | None = None,
21
+ master_wallet: Wallet | None = None,
23
22
  ):
24
23
  """
25
24
  Initialize the ApiClient.
@@ -43,10 +42,19 @@ class ApiClient:
43
42
  self.master_wallet = master_wallet
44
43
 
45
44
  self.accounts = Accounts(base_url=self.base_url, api_key=api_key)
46
- self.app = App(base_url=self.base_url, api_key=api_key)
47
45
  self.orders = Order(base_url=self.base_url, api_key=api_key)
48
46
  self.markets = Market(base_url=self.base_url, api_key=api_key)
49
47
 
48
+ # Initialize WebSocket client with correct stream URL
49
+ if network == "mainnet":
50
+ ws_base_url = (
51
+ "wss://stream.deltadefi.io" # TODO: Update when mainnet is available
52
+ )
53
+ else:
54
+ ws_base_url = "wss://stream-staging.deltadefi.io"
55
+
56
+ self.websocket = WebSocketClient(base_url=ws_base_url, api_key=api_key)
57
+
50
58
  def load_operation_key(self, password: str):
51
59
  """
52
60
  Load the operation key from the wallet using the provided password.
@@ -1,14 +1,8 @@
1
- # flake8: noqa: E501
2
-
3
1
  from typing import Literal
4
2
 
5
3
  from deltadefi.api import API
6
4
  from deltadefi.lib.utils import check_required_parameter, check_required_parameters
7
- from deltadefi.responses import (
8
- GetAggregatedPriceResponse,
9
- GetMarketDepthResponse,
10
- GetMarketPriceResponse,
11
- )
5
+ from deltadefi.responses import GetAggregatedPriceResponse, GetMarketPriceResponse
12
6
 
13
7
 
14
8
  class Market(API):
@@ -21,23 +15,6 @@ class Market(API):
21
15
  def __init__(self, api_key=None, base_url=None, **kwargs):
22
16
  super().__init__(api_key=api_key, base_url=base_url, **kwargs)
23
17
 
24
- def get_depth(self, symbol: str, **kwargs) -> GetMarketDepthResponse:
25
- """
26
- Get market depth.
27
-
28
- Args:
29
- data: A GetMarketDepthRequest object containing the market pair.
30
-
31
- Returns:
32
- A GetMarketDepthResponse object containing the market depth.
33
- """
34
-
35
- check_required_parameter(symbol, "symbol")
36
- payload = {"symbol": symbol, **kwargs}
37
- url_path = "/depth"
38
-
39
- return self.send_request("GET", self.group_url_path + url_path, payload)
40
-
41
18
  def get_market_price(self, symbol: str, **kwargs) -> GetMarketPriceResponse:
42
19
  """
43
20
  Get market price.
@@ -78,7 +55,7 @@ class Market(API):
78
55
  [end, "end"],
79
56
  ]
80
57
  )
81
- url_path = f"/aggregated-trade/{symbol}"
58
+ url_path = f"/graph/{symbol}"
82
59
  return self.send_request(
83
60
  "GET",
84
61
  self.group_url_path + url_path,
@@ -0,0 +1,355 @@
1
+ import asyncio
2
+ from collections.abc import Callable
3
+ import json
4
+ import logging
5
+ from typing import Any
6
+
7
+ import websockets
8
+
9
+ from deltadefi.error import ClientError
10
+
11
+
12
+ class WebSocketClient:
13
+ """
14
+ WebSocket client for DeltaDeFi real-time data streams.
15
+
16
+ Supports:
17
+ - Recent trades
18
+ - Account streams
19
+ - Market price streams
20
+ - Market depth streams
21
+ """
22
+
23
+ def __init__(
24
+ self,
25
+ base_url: str = "wss://stream-staging.deltadefi.io",
26
+ api_key: str | None = None,
27
+ auto_reconnect: bool = True,
28
+ reconnect_interval: int = 5,
29
+ ping_interval: int = 20,
30
+ ping_timeout: int = 10,
31
+ ):
32
+ """
33
+ Initialize the WebSocket client.
34
+
35
+ Args:
36
+ base_url: WebSocket base URL
37
+ api_key: API key for authentication
38
+ auto_reconnect: Whether to automatically reconnect on disconnect
39
+ reconnect_interval: Seconds to wait before reconnection attempt
40
+ ping_interval: Seconds between ping frames
41
+ ping_timeout: Timeout for pong response
42
+ """
43
+ self.base_url = base_url.rstrip("/")
44
+ self.api_key = api_key
45
+ self.auto_reconnect = auto_reconnect
46
+ self.reconnect_interval = reconnect_interval
47
+ self.ping_interval = ping_interval
48
+ self.ping_timeout = ping_timeout
49
+
50
+ self.websocket: websockets.WebSocketServerProtocol | None = None
51
+ self.subscriptions: dict[str, dict[str, Any]] = {}
52
+ self.message_handlers: dict[str, Callable] = {}
53
+ self.is_connected = False
54
+ self.should_stop = False
55
+
56
+ self.logger = logging.getLogger(__name__)
57
+
58
+ async def connect(self, endpoint_path: str = "") -> None:
59
+ """
60
+ Establish WebSocket connection.
61
+
62
+ Args:
63
+ endpoint_path: Specific endpoint path for the connection
64
+ """
65
+ try:
66
+ # Build the full WebSocket URL
67
+ if endpoint_path:
68
+ url = f"{self.base_url}{endpoint_path}"
69
+ else:
70
+ url = f"{self.base_url}/ws"
71
+
72
+ # Add API key as query parameter if provided
73
+ if self.api_key:
74
+ separator = "&" if "?" in url else "?"
75
+ url = f"{url}{separator}api_key={self.api_key}"
76
+
77
+ self.websocket = await websockets.connect(
78
+ url,
79
+ ping_interval=self.ping_interval,
80
+ ping_timeout=self.ping_timeout,
81
+ )
82
+ self.is_connected = True
83
+ self.logger.info(f"WebSocket connected successfully to {url}")
84
+
85
+ # Start message listening loop
86
+ self._listen_task = asyncio.create_task(self._listen_messages())
87
+
88
+ except Exception as e:
89
+ self.logger.error(f"Failed to connect to WebSocket: {e}")
90
+ raise ClientError(0, "WS_CONNECTION_ERROR", str(e), {}, None) from e
91
+
92
+ async def disconnect(self) -> None:
93
+ """Close WebSocket connection."""
94
+ self.should_stop = True
95
+ if self.websocket:
96
+ await self.websocket.close()
97
+ self.is_connected = False
98
+ self.logger.info("WebSocket disconnected")
99
+
100
+ async def _listen_messages(self) -> None:
101
+ """Listen for incoming WebSocket messages."""
102
+ if not self.websocket:
103
+ return
104
+
105
+ try:
106
+ async for message in self.websocket:
107
+ if self.should_stop:
108
+ break
109
+
110
+ await self._handle_message(message)
111
+
112
+ except websockets.exceptions.ConnectionClosed:
113
+ self.is_connected = False
114
+ self.logger.warning("WebSocket connection closed")
115
+
116
+ if self.auto_reconnect and not self.should_stop:
117
+ await self._reconnect()
118
+
119
+ except Exception as e:
120
+ self.logger.error(f"Error in message listener: {e}")
121
+
122
+ async def _handle_message(self, message: str) -> None:
123
+ """Handle incoming WebSocket message."""
124
+ try:
125
+ data = json.loads(message)
126
+
127
+ # Determine message type based on structure
128
+ if isinstance(data, list) and len(data) > 0 and "timestamp" in data[0]:
129
+ # This is a trade stream message (array format)
130
+ if "trade" in self.message_handlers:
131
+ await self.message_handlers["trade"](data)
132
+ else:
133
+ self.logger.debug("No handler for trade stream")
134
+
135
+ elif isinstance(data, dict) and "type" in data:
136
+ # Handle typed messages (account, price, etc.)
137
+ msg_type = data.get("type", "unknown").lower()
138
+ sub_type = data.get("sub_type", "").lower()
139
+
140
+ if msg_type == "account":
141
+ # Account stream message
142
+ if "account" in self.message_handlers:
143
+ await self.message_handlers["account"](data)
144
+ else:
145
+ self.logger.debug("No handler for account stream")
146
+
147
+ elif msg_type == "market" and sub_type == "market_price":
148
+ # Price stream message
149
+ if "price" in self.message_handlers:
150
+ await self.message_handlers["price"](data)
151
+ else:
152
+ self.logger.debug("No handler for price stream")
153
+
154
+ else:
155
+ self.logger.debug(
156
+ f"Unknown message type: {msg_type}, sub_type: {sub_type}"
157
+ )
158
+
159
+ elif (
160
+ isinstance(data, dict)
161
+ and "timestamp" in data
162
+ and ("bids" in data or "asks" in data)
163
+ ):
164
+ # This is a depth stream message
165
+ if "depth" in self.message_handlers:
166
+ await self.message_handlers["depth"](data)
167
+ else:
168
+ self.logger.debug("No handler for depth stream")
169
+
170
+ else:
171
+ self.logger.debug(f"Unknown message format: {data}")
172
+
173
+ except json.JSONDecodeError:
174
+ self.logger.error(f"Failed to parse message: {message}")
175
+ except Exception as e:
176
+ self.logger.error(f"Error handling message: {e}")
177
+
178
+ async def _reconnect(self) -> None:
179
+ """Attempt to reconnect WebSocket."""
180
+ self.logger.info(
181
+ f"Attempting to reconnect in {self.reconnect_interval} seconds"
182
+ )
183
+ await asyncio.sleep(self.reconnect_interval)
184
+
185
+ try:
186
+ # For now, just reconnect to the first subscription if any exist
187
+ # In a more complex implementation, you'd want to handle multiple concurrent subscriptions
188
+ if self.subscriptions:
189
+ first_sub = next(iter(self.subscriptions.values()))
190
+ if first_sub.get("type") == "trade":
191
+ await self.connect(first_sub["endpoint"])
192
+ else:
193
+ await self.connect()
194
+ else:
195
+ await self.connect()
196
+
197
+ except Exception as e:
198
+ self.logger.error(f"Reconnection failed: {e}")
199
+ if self.auto_reconnect and not self.should_stop:
200
+ await self._reconnect()
201
+
202
+ async def _send_message(self, message: dict[str, Any]) -> None:
203
+ """Send message to WebSocket server."""
204
+ if not self.websocket or not self.is_connected:
205
+ raise ClientError(
206
+ 0, "WS_NOT_CONNECTED", "WebSocket not connected", {}, None
207
+ )
208
+
209
+ try:
210
+ await self.websocket.send(json.dumps(message))
211
+ except Exception as e:
212
+ self.logger.error(f"Failed to send message: {e}")
213
+ raise ClientError(0, "WS_SEND_ERROR", str(e), {}, None) from e
214
+
215
+ def register_handler(self, stream_type: str, handler: Callable) -> None:
216
+ """
217
+ Register a message handler for a specific stream type.
218
+
219
+ Args:
220
+ stream_type: Type of stream (e.g., 'trade', 'depth', 'price', 'account')
221
+ handler: Async function to handle messages
222
+ """
223
+ self.message_handlers[stream_type] = handler
224
+
225
+ async def subscribe_trades(self, symbol: str) -> None:
226
+ """
227
+ Subscribe to recent trades for a symbol using DeltaDeFi's specific endpoint.
228
+
229
+ Args:
230
+ symbol: Trading pair symbol (e.g., "ADAUSDM")
231
+ """
232
+ if not self.api_key:
233
+ raise ClientError(
234
+ 0, "API_KEY_REQUIRED", "API key required for trade streams", {}, None
235
+ )
236
+
237
+ # Close existing connection if any
238
+ if self.websocket:
239
+ await self.disconnect()
240
+
241
+ # Connect to the specific trades endpoint
242
+ endpoint_path = f"/market/recent-trades/{symbol}?limit=50"
243
+ await self.connect(endpoint_path)
244
+
245
+ # Store subscription info
246
+ self.subscriptions[f"trade_{symbol}"] = {
247
+ "type": "trade",
248
+ "symbol": symbol,
249
+ "endpoint": endpoint_path,
250
+ }
251
+ self.logger.info(f"Subscribed to trades for {symbol}")
252
+
253
+ async def subscribe_depth(self, symbol: str) -> None:
254
+ """
255
+ Subscribe to market depth for a symbol using DeltaDeFi's specific endpoint.
256
+
257
+ Args:
258
+ symbol: Trading pair symbol (e.g., "ADAUSDM")
259
+ """
260
+ if not self.api_key:
261
+ raise ClientError(
262
+ 0, "API_KEY_REQUIRED", "API key required for depth streams", {}, None
263
+ )
264
+
265
+ # Close existing connection if any
266
+ if self.websocket:
267
+ await self.disconnect()
268
+
269
+ # Connect to the specific depth endpoint
270
+ endpoint_path = f"/market/depth/{symbol}"
271
+ await self.connect(endpoint_path)
272
+
273
+ # Store subscription info
274
+ self.subscriptions[f"depth_{symbol}"] = {
275
+ "type": "depth",
276
+ "symbol": symbol,
277
+ "endpoint": endpoint_path,
278
+ }
279
+ self.logger.info(f"Subscribed to depth for {symbol}")
280
+
281
+ async def subscribe_price(self, symbol: str) -> None:
282
+ """
283
+ Subscribe to price streams for a symbol using DeltaDeFi's specific endpoint.
284
+
285
+ Args:
286
+ symbol: Trading pair symbol (e.g., "ADAUSDM")
287
+ """
288
+ if not self.api_key:
289
+ raise ClientError(
290
+ 0, "API_KEY_REQUIRED", "API key required for price streams", {}, None
291
+ )
292
+
293
+ # Close existing connection if any
294
+ if self.websocket:
295
+ await self.disconnect()
296
+
297
+ # Connect to the specific price endpoint
298
+ endpoint_path = f"/market/market-price/{symbol}"
299
+ await self.connect(endpoint_path)
300
+
301
+ # Store subscription info
302
+ self.subscriptions[f"price_{symbol}"] = {
303
+ "type": "price",
304
+ "symbol": symbol,
305
+ "endpoint": endpoint_path,
306
+ }
307
+ self.logger.info(f"Subscribed to price for {symbol}")
308
+
309
+ async def subscribe_account(self) -> None:
310
+ """
311
+ Subscribe to account streams using DeltaDeFi's specific endpoint.
312
+ Provides balance updates and order status updates.
313
+ """
314
+ if not self.api_key:
315
+ raise ClientError(
316
+ 0, "API_KEY_REQUIRED", "API key required for account streams", {}, None
317
+ )
318
+
319
+ # Close existing connection if any
320
+ if self.websocket:
321
+ await self.disconnect()
322
+
323
+ # Connect to the account stream endpoint
324
+ endpoint_path = "/accounts/stream"
325
+ await self.connect(endpoint_path)
326
+
327
+ # Store subscription info
328
+ self.subscriptions["account"] = {"type": "account", "endpoint": endpoint_path}
329
+ self.logger.info("Subscribed to account streams")
330
+
331
+ async def unsubscribe(self, subscription_key: str) -> None:
332
+ """
333
+ Unsubscribe from a stream.
334
+
335
+ Args:
336
+ subscription_key: Key of the subscription to cancel
337
+ """
338
+ if subscription_key not in self.subscriptions:
339
+ return
340
+
341
+ sub_data = self.subscriptions[subscription_key]
342
+ message = {
343
+ "method": "UNSUBSCRIBE",
344
+ "params": sub_data["params"],
345
+ "id": sub_data["id"],
346
+ }
347
+
348
+ await self._send_message(message)
349
+ del self.subscriptions[subscription_key]
350
+ self.logger.info(f"Unsubscribed from {subscription_key}")
351
+
352
+ async def unsubscribe_all(self) -> None:
353
+ """Unsubscribe from all streams."""
354
+ for sub_key in list(self.subscriptions.keys()):
355
+ await self.unsubscribe(sub_key)
deltadefi/error.py CHANGED
@@ -27,7 +27,7 @@ class ParameterRequiredError(Error):
27
27
  self.params = params
28
28
 
29
29
  def __str__(self):
30
- return "%s is mandatory, but received empty." % (", ".join(self.params))
30
+ return "{} is mandatory, but received empty.".format(", ".join(self.params))
31
31
 
32
32
 
33
33
  class ParameterValueError(Error):
@@ -35,7 +35,7 @@ class ParameterValueError(Error):
35
35
  self.params = params
36
36
 
37
37
  def __str__(self):
38
- return "the enum value %s is invalid." % (", ".join(self.params))
38
+ return "the enum value {} is invalid.".format(", ".join(self.params))
39
39
 
40
40
 
41
41
  class ParameterTypeError(Error):
@@ -1,5 +1,5 @@
1
1
  from dataclasses import dataclass
2
- from typing import List, Literal
2
+ from typing import Literal
3
3
 
4
4
  OrderStatusType = Literal["openOrder", "orderHistory", "tradingHistory"]
5
5
 
@@ -59,7 +59,7 @@ class OrderJSON:
59
59
  class DepositRecord:
60
60
  created_at: str
61
61
  status: TransactionStatus
62
- assets: List[AssetRecord]
62
+ assets: list[AssetRecord]
63
63
  tx_hash: str
64
64
 
65
65
 
@@ -67,7 +67,7 @@ class DepositRecord:
67
67
  class WithdrawalRecord:
68
68
  created_at: str
69
69
  status: TransactionStatus
70
- assets: List[AssetRecord]
70
+ assets: list[AssetRecord]
71
71
 
72
72
 
73
73
  @dataclass
@@ -1,5 +1,5 @@
1
1
  from dataclasses import dataclass
2
- from typing import List, TypedDict
2
+ from typing import TypedDict
3
3
 
4
4
  from deltadefi.models.models import (
5
5
  AssetBalance,
@@ -32,19 +32,31 @@ class SubmitDepositTransactionResponse(TypedDict):
32
32
 
33
33
 
34
34
  @dataclass
35
- class GetDepositRecordsResponse(List[DepositRecord]):
35
+ class GetDepositRecordsResponse(list[DepositRecord]):
36
36
  pass
37
37
 
38
38
 
39
39
  @dataclass
40
- class GetWithdrawalRecordsResponse(List[WithdrawalRecord]):
40
+ class GetWithdrawalRecordsResponse(list[WithdrawalRecord]):
41
41
  pass
42
42
 
43
43
 
44
+ @dataclass
45
+ class OrderRecordsData(TypedDict):
46
+ orders: list[OrderJSON]
47
+ order_filling_records: list[OrderFillingRecordJSON]
48
+
49
+
50
+ @dataclass
51
+ class GetOrderRecordsResponse(TypedDict):
52
+ data: list[OrderRecordsData]
53
+ total_count: int
54
+ total_page: int
55
+
56
+
44
57
  @dataclass
45
58
  class GetOrderRecordResponse(TypedDict):
46
- orders: List[OrderJSON]
47
- order_filling_records: List[OrderFillingRecordJSON]
59
+ order_json: OrderJSON
48
60
 
49
61
 
50
62
  @dataclass
@@ -52,11 +64,21 @@ class BuildWithdrawalTransactionResponse(TypedDict):
52
64
  tx_hex: str
53
65
 
54
66
 
67
+ @dataclass
68
+ class BuildTransferalTransactionResponse(TypedDict):
69
+ tx_hex: str
70
+
71
+
55
72
  @dataclass
56
73
  class SubmitWithdrawalTransactionResponse(TypedDict):
57
74
  tx_hash: str
58
75
 
59
76
 
77
+ @dataclass
78
+ class SubmitTransferalTransactionResponse(TypedDict):
79
+ tx_hash: str
80
+
81
+
60
82
  @dataclass
61
83
  class GetAccountInfoResponse(TypedDict):
62
84
  api_key: str
@@ -66,5 +88,5 @@ class GetAccountInfoResponse(TypedDict):
66
88
 
67
89
 
68
90
  @dataclass
69
- class GetAccountBalanceResponse(List[AssetBalance]):
91
+ class GetAccountBalanceResponse(list[AssetBalance]):
70
92
  pass
@@ -1,5 +1,5 @@
1
1
  from dataclasses import dataclass
2
- from typing import List, TypedDict
2
+ from typing import TypedDict
3
3
 
4
4
  from deltadefi.models import OrderJSON
5
5
 
@@ -17,8 +17,8 @@ class MarketDepth(TypedDict):
17
17
 
18
18
  @dataclass
19
19
  class GetMarketDepthResponse(TypedDict):
20
- bids: List[MarketDepth]
21
- asks: List[MarketDepth]
20
+ bids: list[MarketDepth]
21
+ asks: list[MarketDepth]
22
22
 
23
23
 
24
24
  @dataclass
@@ -38,7 +38,7 @@ class Trade(TypedDict):
38
38
 
39
39
 
40
40
  @dataclass
41
- class GetAggregatedPriceResponse(List[Trade]):
41
+ class GetAggregatedPriceResponse(list[Trade]):
42
42
  pass
43
43
 
44
44
 
@@ -1,29 +1,30 @@
1
- Metadata-Version: 2.3
1
+ Metadata-Version: 2.4
2
2
  Name: deltadefi
3
- Version: 0.0.10
3
+ Version: 0.1.0
4
4
  Summary: Python SDK for DeltaDeFi protocol.
5
- License: Apache-2.0
6
- Keywords: cardano
7
- Author: HinsonSIDAN
8
- Author-email: wongkahinhinson@gmail.com
9
- Requires-Python: >3.11,<4.0.0
5
+ Author-email: HinsonSIDAN <wongkahinhinson@gmail.com>
6
+ License-Expression: Apache-2.0
7
+ Keywords: cardano,defi,sdk,trading
8
+ Classifier: Development Status :: 3 - Alpha
10
9
  Classifier: Intended Audience :: Developers
11
10
  Classifier: License :: OSI Approved :: Apache Software License
12
11
  Classifier: Natural Language :: English
13
12
  Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.11
14
14
  Classifier: Programming Language :: Python :: 3.12
15
15
  Classifier: Programming Language :: Python :: 3.13
16
- Classifier: Programming Language :: Python :: 3.11
17
- Requires-Dist: certifi (==2024.8.30)
18
- Requires-Dist: charset-normalizer (==3.4.0)
19
- Requires-Dist: dotenv (>=0.9.9,<0.10.0)
20
- Requires-Dist: idna (==3.10)
21
- Requires-Dist: pycardano (>=0.12.3,<0.13.0)
22
- Requires-Dist: requests (>=2.25,<3.0)
23
- Requires-Dist: sidan-gin (==0.1.6)
24
- Requires-Dist: urllib3 (==2.2.3)
25
- Project-URL: Documentation, https://github.com/deltadefi-protocol/python-sdk
26
- Project-URL: Homepage, https://github.com/deltadefi-protocol/python-sdk
16
+ Classifier: Topic :: Office/Business :: Financial :: Investment
17
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
18
+ Requires-Python: <4.0.0,>3.11
19
+ Requires-Dist: certifi>=2024.8.30
20
+ Requires-Dist: charset-normalizer>=3.4.0
21
+ Requires-Dist: idna>=3.10
22
+ Requires-Dist: pycardano>=0.12.3
23
+ Requires-Dist: python-dotenv>=0.9.9
24
+ Requires-Dist: requests>=2.25.0
25
+ Requires-Dist: sidan-gin>=0.1.6
26
+ Requires-Dist: urllib3>=2.2.3
27
+ Requires-Dist: websockets>=12.0
27
28
  Description-Content-Type: text/markdown
28
29
 
29
30
  # DeltaDeFi Python SDK
@@ -56,11 +57,8 @@ from sidan_gin import HDWallet
56
57
  network="preprod",
57
58
  api_key="your_api_key",
58
59
 
59
- # Initialize HDWallet
60
- wallet = HDWallet("your_wallet_mnemonic")
61
-
62
60
  # Initialize ApiClient
63
- api = ApiClient(network=network, api_key=api_key, wallet=wallet)
61
+ api = ApiClient(network=network, api_key=api_key)
64
62
  ```
65
63
 
66
64
  ### Accounts
@@ -73,33 +71,40 @@ account_balance = api.accounts.get_account_balance()
73
71
  print(account_balance)
74
72
  ```
75
73
 
76
- ### Market
74
+ ### Markets
77
75
 
78
76
  The Market client allows you to interact with market-related endpoints.
79
77
 
80
78
  ```python
81
79
  # Get market depth
82
- market_depth = api.market.get_depth("ADAUSDM")
80
+ market_depth = api.markets.get_depth("ADAUSDM")
83
81
  print(market_depth_response)
84
82
 
85
83
  # Get market price
86
- market_price_response = api.market.get_market_price("ADAUSDM")
84
+ market_price_response = api.markets.get_market_price("ADAUSDM")
87
85
  print(market_price_response)
88
86
  ```
89
87
 
90
- ### Order
88
+ ### Orders
91
89
 
92
90
  The Order client allows you to interact with order-related endpoints.
93
91
 
94
92
  ```python
95
- # Build place order transaction
96
- place_order_request = BuildPlaceOrderTransactionRequest(pair="BTC/USD", amount=1, price=50000)
97
- place_order_response = api.order.build_place_order_transaction(symbol="ADAUSDM", amount=50, price=0.75, type="limit")
98
- print(place_order_response)
99
-
100
- # Submit place order transaction
101
- submit_order_response = api.order.submit_place_order_transaction(signed_tx="<signed_tx>", order_id="<order_id>")
102
- print(submit_order_response)
93
+ api_key = os.environ.get("DELTADEFI_API_KEY")
94
+ password = os.environ.get("TRADING_PASSWORD")
95
+
96
+ api = ApiClient(api_key=api_key)
97
+ api.load_operation_key(password)
98
+
99
+ res = api.post_order(
100
+ symbol="ADAUSDM",
101
+ side="sell",
102
+ type="limit",
103
+ quantity=51,
104
+ price=15,
105
+ )
106
+
107
+ print("Order submitted successfully.", res)
103
108
  ```
104
109
 
105
110
  ## Development
@@ -115,4 +120,3 @@ DELTADEFI_API_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx make test
115
120
  ## License
116
121
 
117
122
  Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at <http://www.apache.org/licenses/LICENSE-2.0>
118
-
@@ -0,0 +1,22 @@
1
+ deltadefi/__init__.py,sha256=pKZHfRdXT3f3kncxAKamtk5V3EDQB8Ocy8xBmjhsJ4A,63
2
+ deltadefi/api.py,sha256=g5N7O_xzrl5hsQuw-ZhJ9lQi5rKzgr3_-C9FViRlOuw,2724
3
+ deltadefi/error.py,sha256=zDMx5ukb5zs0AOeGAHjXiIMDZ0LbEcaGyVi45WFJfmI,1658
4
+ deltadefi/api_resources/__init__.py,sha256=_SGHTpaQTIBvh9Rm868IT5pXpvvGBPqz3bxkY6YapZ4,61
5
+ deltadefi/api_resources/auth.py,sha256=4QCEI4P4UlQPQYctqY9Oat4hn7lsI95QihHTD_0PZKg,245
6
+ deltadefi/api_resources/validation.py,sha256=vz-hovpLy9SMOIFGcBHC8vWZH8CJRlQP8rcbbTSM-PM,1375
7
+ deltadefi/clients/__init__.py,sha256=4hyPuk6_bcJGXUElOvkgZ7ARlQ6QwKLp-nFgCXTbFVI,76
8
+ deltadefi/clients/accounts.py,sha256=3bOHKYIBJYsOgb97rw57u9aJV9VyHb1U8l_rGXBOwp4,8411
9
+ deltadefi/clients/client.py,sha256=2hLOsxqBc8eu_6ovuYLRoK2popdI1_t3pGcEP8Keu9A,4619
10
+ deltadefi/clients/markets.py,sha256=JQUj3duj1dLEA36NW4Rk44_ALAMLrlK37ylxnu5kTCc,1989
11
+ deltadefi/clients/orders.py,sha256=gnh8AcXWI1QQK9riJtsu_1BqzuOml5OGf4bFP6yfy9g,3890
12
+ deltadefi/clients/websocket.py,sha256=0454RunoE9eHqmQ0wrywEwxqrie1qEXq2ObxyKXopck,12424
13
+ deltadefi/constants/__init__.py,sha256=7LkrzfLTJsCCUl5IgZYrl-AbY_cf1fftcLklgnBYDTs,40
14
+ deltadefi/constants/constants.py,sha256=4bkY4kfNcsgoCe1xU8n2We7w-vxZXyzVw5rQvAsx4j8,168
15
+ deltadefi/models/__init__.py,sha256=oDJj6Y4gXN6C7Oz_t2fq8hej-D0G9OqfXjL4Jaeq8z8,37
16
+ deltadefi/models/models.py,sha256=kiRpCdzUh3WmyuFOaxlZ1rjsQ2cxLWjVFBCqsHXMtBc,1633
17
+ deltadefi/responses/__init__.py,sha256=JKSIUQu6qI_XhbAR2mVMCKNvR6x_vFZdyLGOuQTVrVY,64
18
+ deltadefi/responses/accounts.py,sha256=o-It4vyNsiDeCmHa-XQl77KuCVtJi7qlPdn059fgwcI,1590
19
+ deltadefi/responses/responses.py,sha256=Kz5PtDnx_AgKrV7NhZqrSMnS1wPlLbu13J2BKNzN0ME,1012
20
+ deltadefi-0.1.0.dist-info/METADATA,sha256=lkvqD6KUiekc--8-QROKHZ7G7HKCah8cwJfanmMJjo4,3075
21
+ deltadefi-0.1.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
22
+ deltadefi-0.1.0.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: poetry-core 2.1.3
2
+ Generator: hatchling 1.27.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
deltadefi/clients/app.py DELETED
@@ -1,23 +0,0 @@
1
- from deltadefi.api import API
2
- from deltadefi.responses import GetTermsAndConditionResponse
3
-
4
-
5
- class App(API):
6
- """
7
- App client for interacting with the DeltaDeFi API.
8
- """
9
-
10
- group_url_path = "/app"
11
-
12
- def __init__(self, api_key=None, base_url=None, **kwargs):
13
- super().__init__(api_key=api_key, base_url=base_url, **kwargs)
14
-
15
- def get_terms_and_condition(self, **kwargs) -> GetTermsAndConditionResponse:
16
- """
17
- Get terms and conditions.
18
-
19
- Returns:
20
- A GetTermsAndConditionResponse object containing the terms and conditions.
21
- """
22
- url_path = "/terms-and-conditions"
23
- return self.send_request("GET", self.group_url_path + url_path, kwargs)
deltadefi/lib/__init__.py DELETED
File without changes
deltadefi/lib/utils.py DELETED
@@ -1,46 +0,0 @@
1
- from urllib.parse import urlencode
2
-
3
- from deltadefi.error import (
4
- ParameterRequiredError,
5
- ParameterTypeError,
6
- ParameterValueError,
7
- )
8
-
9
-
10
- def clean_none_value(d) -> dict:
11
- out = {}
12
- for k in d.keys():
13
- if d[k] is not None:
14
- out[k] = d[k]
15
- return out
16
-
17
-
18
- def check_required_parameter(value, name):
19
- if not value and value != 0:
20
- raise ParameterRequiredError([name])
21
-
22
-
23
- def check_required_parameters(params):
24
- """Validate multiple parameters
25
- params = [
26
- ['btcusdt', 'symbol'],
27
- [10, 'price']
28
- ]
29
-
30
- """
31
- for p in params:
32
- check_required_parameter(p[0], p[1])
33
-
34
-
35
- def check_enum_parameter(value, enum_class):
36
- if value not in set(item.value for item in enum_class):
37
- raise ParameterValueError([value])
38
-
39
-
40
- def check_type_parameter(value, name, data_type):
41
- if value is not None and not isinstance(value, data_type):
42
- raise ParameterTypeError([name, data_type])
43
-
44
-
45
- def encoded_string(query):
46
- return urlencode(query, True).replace("%40", "@")
@@ -1,24 +0,0 @@
1
- deltadefi/__init__.py,sha256=_dbB-toNXZvwZxj5DnEY0nW5noDnDpF4QsJNEwGO_IA,46
2
- deltadefi/api.py,sha256=XSdOFwq9s2HFxKxiv7ljaCgUhwXVAkkq19dPSRhwlek,2720
3
- deltadefi/api_resources/__init__.py,sha256=_SGHTpaQTIBvh9Rm868IT5pXpvvGBPqz3bxkY6YapZ4,61
4
- deltadefi/api_resources/auth.py,sha256=Mpl4Dbh_d_gGhwLo2CtBSKxZ21DC74x-qjVhlczZCDE,278
5
- deltadefi/api_resources/validation.py,sha256=vz-hovpLy9SMOIFGcBHC8vWZH8CJRlQP8rcbbTSM-PM,1375
6
- deltadefi/clients/__init__.py,sha256=GEEsW2Sl-fPq0ilDsNyztoCDO7JSed14uMN2gOurIOI,37
7
- deltadefi/clients/accounts.py,sha256=ZuzPjobGk-bk4SPC8mqDAxChCfv5vj7y96k38G84uj0,6302
8
- deltadefi/clients/app.py,sha256=TOgRlP83p91r7oS4ez8Gfm8soQzFHrJAmOHZJoGZ4SM,712
9
- deltadefi/clients/client.py,sha256=khtgJYE4m6VFPLylVUe5a52SWu6kzdtHdse7XXy0LoE,4284
10
- deltadefi/clients/markets.py,sha256=v8hK06oXC73qS3IjvWDempHq_-9T6OW2pckIcDR7P2M,2580
11
- deltadefi/clients/orders.py,sha256=gnh8AcXWI1QQK9riJtsu_1BqzuOml5OGf4bFP6yfy9g,3890
12
- deltadefi/constants/__init__.py,sha256=7LkrzfLTJsCCUl5IgZYrl-AbY_cf1fftcLklgnBYDTs,40
13
- deltadefi/constants/constants.py,sha256=4bkY4kfNcsgoCe1xU8n2We7w-vxZXyzVw5rQvAsx4j8,168
14
- deltadefi/error.py,sha256=Pq55p7FQbVn1GTih7NQBI7ZcVUUrlkaFKn-SwZUxBA8,1650
15
- deltadefi/lib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
- deltadefi/lib/utils.py,sha256=zuQFAKQphbGxDdPzBURw4A2n3AkRSbzmjMLHPLm9Ed4,1035
17
- deltadefi/models/__init__.py,sha256=oDJj6Y4gXN6C7Oz_t2fq8hej-D0G9OqfXjL4Jaeq8z8,37
18
- deltadefi/models/models.py,sha256=Fgk3W6Ps1tibnE3cJTaBt5OPfVKl70nIDxDFsu1m5bk,1639
19
- deltadefi/responses/__init__.py,sha256=JKSIUQu6qI_XhbAR2mVMCKNvR6x_vFZdyLGOuQTVrVY,64
20
- deltadefi/responses/accounts.py,sha256=tDjJPb_Xk0_-aEX8pNHINrhurCljEZQfI-TikCIO_D4,1227
21
- deltadefi/responses/responses.py,sha256=JZrnBWZZGM_yyulrcgYNdJyw-8bOhlsmMTK3xZbuBKM,1018
22
- deltadefi-0.0.10.dist-info/METADATA,sha256=s434ECRVm3WNTikx0lNU5LfkNiU8OVfev3HO7YjbRwo,3235
23
- deltadefi-0.0.10.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
24
- deltadefi-0.0.10.dist-info/RECORD,,