ccxt 4.4.35__py2.py3-none-any.whl → 4.4.37__py2.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 (55) hide show
  1. ccxt/__init__.py +5 -3
  2. ccxt/abstract/bitfinex.py +136 -65
  3. ccxt/abstract/bitfinex1.py +69 -0
  4. ccxt/abstract/bitopro.py +1 -0
  5. ccxt/abstract/bybit.py +15 -0
  6. ccxt/abstract/defx.py +69 -0
  7. ccxt/abstract/deribit.py +1 -0
  8. ccxt/abstract/gate.py +14 -0
  9. ccxt/abstract/gateio.py +14 -0
  10. ccxt/async_support/__init__.py +5 -3
  11. ccxt/async_support/base/exchange.py +1 -1
  12. ccxt/async_support/bitfinex.py +3005 -1084
  13. ccxt/async_support/bitfinex1.py +1704 -0
  14. ccxt/async_support/bitfinex2.py +18 -13
  15. ccxt/async_support/bitmex.py +103 -1
  16. ccxt/async_support/bitopro.py +21 -4
  17. ccxt/async_support/bitso.py +2 -1
  18. ccxt/async_support/bybit.py +21 -1
  19. ccxt/async_support/coinbase.py +86 -0
  20. ccxt/async_support/defx.py +1981 -0
  21. ccxt/async_support/deribit.py +27 -12
  22. ccxt/async_support/gate.py +15 -1
  23. ccxt/async_support/htx.py +11 -2
  24. ccxt/async_support/hyperliquid.py +124 -14
  25. ccxt/async_support/kraken.py +39 -41
  26. ccxt/async_support/paradex.py +2 -2
  27. ccxt/base/exchange.py +6 -2
  28. ccxt/bitfinex.py +3005 -1084
  29. ccxt/bitfinex1.py +1703 -0
  30. ccxt/bitfinex2.py +18 -13
  31. ccxt/bitmex.py +103 -1
  32. ccxt/bitopro.py +21 -4
  33. ccxt/bitso.py +2 -1
  34. ccxt/bybit.py +21 -1
  35. ccxt/coinbase.py +86 -0
  36. ccxt/defx.py +1980 -0
  37. ccxt/deribit.py +27 -12
  38. ccxt/gate.py +15 -1
  39. ccxt/htx.py +11 -2
  40. ccxt/hyperliquid.py +124 -14
  41. ccxt/kraken.py +39 -41
  42. ccxt/paradex.py +2 -2
  43. ccxt/pro/__init__.py +5 -3
  44. ccxt/pro/bitfinex.py +725 -274
  45. ccxt/pro/bitfinex1.py +635 -0
  46. ccxt/pro/defx.py +832 -0
  47. ccxt/pro/probit.py +1 -0
  48. ccxt/test/tests_async.py +15 -1
  49. ccxt/test/tests_sync.py +15 -1
  50. {ccxt-4.4.35.dist-info → ccxt-4.4.37.dist-info}/METADATA +11 -10
  51. {ccxt-4.4.35.dist-info → ccxt-4.4.37.dist-info}/RECORD +54 -47
  52. ccxt/abstract/bitfinex2.py +0 -140
  53. {ccxt-4.4.35.dist-info → ccxt-4.4.37.dist-info}/LICENSE.txt +0 -0
  54. {ccxt-4.4.35.dist-info → ccxt-4.4.37.dist-info}/WHEEL +0 -0
  55. {ccxt-4.4.35.dist-info → ccxt-4.4.37.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,1981 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ # PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
4
+ # https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
5
+
6
+ from ccxt.async_support.base.exchange import Exchange
7
+ from ccxt.abstract.defx import ImplicitAPI
8
+ import asyncio
9
+ import hashlib
10
+ from ccxt.base.types import Balances, Currency, Int, LedgerEntry, Leverage, Market, Num, Order, OrderBook, OrderSide, OrderType, Position, Str, Strings, Ticker, Tickers, FundingRate, Trade, Transaction
11
+ from typing import List
12
+ from ccxt.base.errors import ExchangeError
13
+ from ccxt.base.errors import AuthenticationError
14
+ from ccxt.base.errors import ArgumentsRequired
15
+ from ccxt.base.errors import BadRequest
16
+ from ccxt.base.errors import InvalidOrder
17
+ from ccxt.base.errors import NotSupported
18
+ from ccxt.base.decimal_to_precision import TICK_SIZE
19
+ from ccxt.base.precise import Precise
20
+
21
+
22
+ class defx(Exchange, ImplicitAPI):
23
+
24
+ def describe(self):
25
+ return self.deep_extend(super(defx, self).describe(), {
26
+ 'id': 'defx',
27
+ 'name': 'Defx X',
28
+ # 'countries': [''],
29
+ 'rateLimit': 100,
30
+ 'version': 'v1',
31
+ 'certified': False,
32
+ 'pro': False,
33
+ 'hostname': 'defx.com',
34
+ 'dex': True,
35
+ 'has': {
36
+ 'CORS': None,
37
+ 'spot': False,
38
+ 'margin': False,
39
+ 'swap': True,
40
+ 'future': False,
41
+ 'option': False,
42
+ 'addMargin': True,
43
+ 'cancelAllOrders': True,
44
+ 'cancelAllOrdersAfter': False,
45
+ 'cancelOrder': True,
46
+ 'cancelWithdraw': False,
47
+ 'closeAllPositions': True,
48
+ 'closePosition': True,
49
+ 'createConvertTrade': False,
50
+ 'createDepositAddress': False,
51
+ 'createMarketBuyOrderWithCost': False,
52
+ 'createMarketOrder': False,
53
+ 'createMarketOrderWithCost': False,
54
+ 'createMarketSellOrderWithCost': False,
55
+ 'createOrder': True,
56
+ 'createOrderWithTakeProfitAndStopLoss': True,
57
+ 'createReduceOnlyOrder': True,
58
+ 'createStopLimitOrder': False,
59
+ 'createStopLossOrder': False,
60
+ 'createStopMarketOrder': False,
61
+ 'createStopOrder': False,
62
+ 'createTakeProfitOrder': True,
63
+ 'createTrailingAmountOrder': False,
64
+ 'createTrailingPercentOrder': False,
65
+ 'createTriggerOrder': True,
66
+ 'fetchAccounts': False,
67
+ 'fetchBalance': True,
68
+ 'fetchCanceledOrders': True,
69
+ 'fetchClosedOrder': False,
70
+ 'fetchClosedOrders': True,
71
+ 'fetchConvertCurrencies': False,
72
+ 'fetchConvertQuote': False,
73
+ 'fetchConvertTrade': False,
74
+ 'fetchConvertTradeHistory': False,
75
+ 'fetchCurrencies': False,
76
+ 'fetchDepositAddress': False,
77
+ 'fetchDepositAddresses': False,
78
+ 'fetchDepositAddressesByNetwork': False,
79
+ 'fetchDeposits': False,
80
+ 'fetchDepositsWithdrawals': False,
81
+ 'fetchFundingHistory': False,
82
+ 'fetchFundingInterval': False,
83
+ 'fetchFundingIntervals': False,
84
+ 'fetchFundingRate': True,
85
+ 'fetchFundingRateHistory': False,
86
+ 'fetchFundingRates': False,
87
+ 'fetchIndexOHLCV': False,
88
+ 'fetchLedger': True,
89
+ 'fetchLeverage': False,
90
+ 'fetchMarginAdjustmentHistory': False,
91
+ 'fetchMarginMode': False,
92
+ 'fetchMarkets': True,
93
+ 'fetchMarkOHLCV': False,
94
+ 'fetchMarkPrice': False,
95
+ 'fetchMarkPrices': False,
96
+ 'fetchMyTrades': True,
97
+ 'fetchOHLCV': True,
98
+ 'fetchOpenInterestHistory': False,
99
+ 'fetchOpenOrder': False,
100
+ 'fetchOpenOrders': True,
101
+ 'fetchOrder': True,
102
+ 'fetchOrderBook': True,
103
+ 'fetchOrders': True,
104
+ 'fetchOrderTrades': False,
105
+ 'fetchPosition': True,
106
+ 'fetchPositionHistory': False,
107
+ 'fetchPositionMode': False,
108
+ 'fetchPositions': True,
109
+ 'fetchPositionsHistory': False,
110
+ 'fetchPremiumIndexOHLCV': False,
111
+ 'fetchStatus': True,
112
+ 'fetchTicker': True,
113
+ 'fetchTickers': True,
114
+ 'fetchTime': True,
115
+ 'fetchTrades': True,
116
+ 'fetchTradingFee': False,
117
+ 'fetchTradingFees': False,
118
+ 'fetchTransactions': False,
119
+ 'fetchTransfers': False,
120
+ 'fetchWithdrawals': False,
121
+ 'reduceMargin': False,
122
+ 'sandbox': True,
123
+ 'setLeverage': True,
124
+ 'setMargin': False,
125
+ 'setPositionMode': False,
126
+ 'transfer': False,
127
+ 'withdraw': True,
128
+ },
129
+ 'timeframes': {
130
+ '1m': '1m',
131
+ '3m': '3m',
132
+ '5m': '5m',
133
+ '15m': '15m',
134
+ '30m': '30m',
135
+ '1h': '1h',
136
+ '2h': '2h',
137
+ '4h': '4h',
138
+ '12h': '12h',
139
+ '1d': '1d',
140
+ '1w': '1w',
141
+ '1M': '1M',
142
+ },
143
+ 'urls': {
144
+ 'logo': 'https://github.com/user-attachments/assets/4e92bace-d7a9-45ea-92be-122168dc87e4',
145
+ 'api': {
146
+ 'public': 'https://api.{hostname}',
147
+ 'private': 'https://api.{hostname}',
148
+ },
149
+ 'test': {
150
+ 'public': 'https://api.testnet.{hostname}',
151
+ 'private': 'https://api.testnet.{hostname}',
152
+ },
153
+ 'www': 'https://defx.com/home',
154
+ 'doc': [
155
+ 'https://docs.defx.com/docs',
156
+ 'https://api-docs.defx.com/',
157
+ ],
158
+ 'fees': [
159
+ '',
160
+ ],
161
+ 'referral': {
162
+ 'url': 'https://app.defx.com/join/6I2CZ7',
163
+ },
164
+ },
165
+ 'api': {
166
+ 'v1': {
167
+ 'public': {
168
+ 'get': {
169
+ 'healthcheck/ping': 1,
170
+ 'symbols/{symbol}/ohlc': 1,
171
+ 'symbols/{symbol}/trades': 1,
172
+ 'symbols/{symbol}/prices': 1,
173
+ 'symbols/{symbol}/ticker/24hr': 1,
174
+ 'symbols/{symbol}/depth/{level}/{slab}': 1,
175
+ 'ticker/24HrAgg': 1,
176
+ 'c/markets': 1,
177
+ 'c/markets/metadata': 1,
178
+ 'analytics/market/stats/newUsers': 1,
179
+ 'analytics/market/stats/tvl': 1,
180
+ 'analytics/market/stats/volumeByInstrument': 1,
181
+ 'analytics/market/stats/liquidation': 1,
182
+ 'analytics/market/stats/totalVolume': 1,
183
+ 'analytics/market/stats/openInterest': 1,
184
+ 'analytics/market/stats/totalTrades': 1,
185
+ 'analytics/market/stats/basis': 1,
186
+ 'analytics/market/stats/insuranceFund': 1,
187
+ 'analytics/market/stats/longAndShortRatio': 1,
188
+ 'analytics/market/stats/fundingRate': 1,
189
+ 'analytics/market/overview': 1,
190
+ 'explorer/search': 1,
191
+ 'explorer/transactions': 1,
192
+ 'explorer/blocks': 1,
193
+ },
194
+ },
195
+ 'private': {
196
+ 'get': {
197
+ 'api/order/{orderId}': 1,
198
+ 'api/orders': 1,
199
+ 'api/orders/oco/{parentOrderId}': 1,
200
+ 'api/trades': 1,
201
+ 'api/position/active': 1,
202
+ 'api/users/metadata/leverage': 1,
203
+ 'api/users/metadata/feeMultiplier': 1,
204
+ 'api/users/metadata/slippage': 1,
205
+ 'api/users/referral': 1,
206
+ 'api/users/apikeys': 1,
207
+ 'connection-signature-message/evm': 1,
208
+ 'api/users/profile/wallets': 1,
209
+ 'api/notifications': 1,
210
+ 'api/wallet/balance': 1,
211
+ 'api/wallet/transactions': 1,
212
+ 'api/analytics/user/overview': 1,
213
+ 'api/analytics/user/pnl': 1,
214
+ 'api/analytics/points/overview': 1,
215
+ 'api/analytics/points/history': 1,
216
+ },
217
+ 'post': {
218
+ 'api/order': 1,
219
+ 'api/position/oco': 1,
220
+ 'api/users/socket/listenKeys': 1,
221
+ 'api/users/metadata/leverage': 1,
222
+ 'api/users/metadata/feeMultiplier': 1,
223
+ 'api/users/metadata/slippage': 1,
224
+ 'api/users/referral/recordReferralSignup': 1,
225
+ 'api/users/apikeys': 1,
226
+ 'api/users/profile/wallets': 1,
227
+ 'api/transfers/withdrawal': 1,
228
+ 'api/transfers/bridge/withdrawal': 1,
229
+ },
230
+ 'put': {
231
+ 'api/position/updatePositionMargin': 1,
232
+ 'api/users/socket/listenKeys/{listenKey}': 1,
233
+ 'api/users/apikeys/{accessKey}/status': 1,
234
+ 'api/users/referral': 1,
235
+ },
236
+ 'patch': {
237
+ 'api/users/apikeys/{accessKey}': 1,
238
+ },
239
+ 'delete': {
240
+ 'api/orders/allOpen': 1,
241
+ 'api/order/{orderId}': 1,
242
+ 'api/position/{positionId}': 1,
243
+ 'api/position/all': 1,
244
+ 'api/users/socket/listenKeys/{listenKey}': 1,
245
+ 'api/users/apikeys/{accessKey}': 1,
246
+ },
247
+ },
248
+ },
249
+ },
250
+ 'fees': {
251
+ 'trading': {
252
+ 'tierBased': True,
253
+ 'percentage': True,
254
+ 'maker': self.parse_number('0.0002'),
255
+ 'taker': self.parse_number('0.0005'),
256
+ },
257
+ },
258
+ 'options': {
259
+ 'sandboxMode': False,
260
+ },
261
+ 'commonCurrencies': {},
262
+ 'exceptions': {
263
+ 'exact': {
264
+ '404': BadRequest, # {"errorCode":404,"errorMessage":"Not Found"}
265
+ 'missing_auth_signature': AuthenticationError, # {"msg":"Missing auth signature","code":"missing_auth_signature"}
266
+ 'order_rejected': InvalidOrder, # {"success":false,"err":{"msg":"Order has already been rejected","code":"order_rejected"}}
267
+ 'invalid_order_id': InvalidOrder, # {"success":false,"err":{"msg":"Invalid order id","code":"invalid_order_id"}}
268
+ 'filter_lotsize_maxqty': InvalidOrder, # {"errorCode":"filter_lotsize_maxqty","errorMessage":"LOT_SIZE filter failed, quantity more than maxQty","errorData":{"maxQty":"5000.00"}}
269
+ 'filter_notional_min': InvalidOrder, # {"errorCode":"filter_notional_min","errorMessage":"NOTIONAL filter failed, Notional value of quote asset less than minNotional","errorData":{"minNotional":"100.00000000"}}
270
+ 'failed_index_price_up_multiplier_filter': InvalidOrder, # {"errorCode":"failed_index_price_up_multiplier_filter","errorMessage":"failed_index_price_up_multiplier_filter","errorData":{"maxPrice":"307.81241042"}}
271
+ 'no_open_orders': InvalidOrder, # {"errorMessage":"No open orders found","errorCode":"no_open_orders"}
272
+ 'active_position_not_found': InvalidOrder, # {"errorCode":"active_position_not_found","errorMessage":"Active position not found"}
273
+ 'position_inactive': InvalidOrder, # {"errorCode":"position_inactive","errorMessage":"Position is already inactive"}
274
+ 'invalid_position_id': InvalidOrder, # {"errorCode":"invalid_position_id","errorMessage":"Position id is invalid"}
275
+ 'Internal server error': ExchangeError, # {"msg":"Internal server error","code":"internal_server_error"}
276
+ },
277
+ 'broad': {
278
+ 'Bad Request': BadRequest, # {"errorMessage":"Bad Request","data":[{"param":"symbol","message":"\"symbol\" must be one of [ETH_USDC, BTC_USDC, BNB_USDC, SOL_USDC, DOGE_USDC, TON_USDC, AVAX_USDC, WIF_USDC, KPEPE_USDC, KSHIB_USDC, KBONK_USDC, MOODENG_USDC, POPCAT_USDC, MOTHER_USDC]"}]}
279
+ },
280
+ },
281
+ 'precisionMode': TICK_SIZE,
282
+ })
283
+
284
+ async def fetch_status(self, params={}):
285
+ """
286
+ the latest known information on the availability of the exchange API
287
+
288
+ https://api-docs.defx.com/#4b03bb3b-a0fa-4dfb-b96c-237bde0ce9e6
289
+
290
+ :param dict [params]: extra parameters specific to the exchange API endpoint
291
+ :returns dict: a `status structure <https://docs.ccxt.com/#/?id=exchange-status-structure>`
292
+ """
293
+ response = await self.v1PublicGetHealthcheckPing(params)
294
+ #
295
+ # {
296
+ # "success": True,
297
+ # "t": 1709705048323,
298
+ # "v": "0.0.7",
299
+ # "msg": "A programmer’s wife tells him, “While you’re at the grocery store, buy some eggs.” He never comes back."
300
+ # }
301
+ #
302
+ status = None
303
+ success = self.safe_bool(response, 'success')
304
+ if success:
305
+ status = 'ok'
306
+ else:
307
+ status = 'error'
308
+ return {
309
+ 'status': status,
310
+ 'updated': None,
311
+ 'eta': None,
312
+ 'url': None,
313
+ 'info': response,
314
+ }
315
+
316
+ async def fetch_time(self, params={}):
317
+ """
318
+ fetches the current integer timestamp in milliseconds from the exchange server
319
+
320
+ https://api-docs.defx.com/#4b03bb3b-a0fa-4dfb-b96c-237bde0ce9e6
321
+
322
+ :param dict [params]: extra parameters specific to the exchange API endpoint
323
+ :returns int: the current integer timestamp in milliseconds from the exchange server
324
+ """
325
+ response = await self.v1PublicGetHealthcheckPing(params)
326
+ #
327
+ # {
328
+ # "success": True,
329
+ # "t": 1709705048323,
330
+ # "v": "0.0.7",
331
+ # "msg": "A programmer’s wife tells him, “While you’re at the grocery store, buy some eggs.” He never comes back."
332
+ # }
333
+ #
334
+ return self.safe_integer(response, 't')
335
+
336
+ async def fetch_markets(self, params={}) -> List[Market]:
337
+ """
338
+ retrieves data on all markets for defx
339
+
340
+ https://api-docs.defx.com/#73cce0c8-f842-4891-9145-01bb6d61324d
341
+ https://api-docs.defx.com/#24fd4e5b-840e-451e-99e0-7fea47c7f371
342
+
343
+ :param dict [params]: extra parameters specific to the exchange API endpoint
344
+ :returns dict[]: an array of objects representing market data
345
+ """
346
+ request = {
347
+ 'type': 'perps',
348
+ }
349
+ promises = [
350
+ self.v1PublicGetCMarkets(self.extend(request, params)),
351
+ self.v1PublicGetCMarketsMetadata(self.extend(request, params)),
352
+ ]
353
+ responses = await asyncio.gather(*promises)
354
+ #
355
+ # {
356
+ # "data": [
357
+ # {
358
+ # "market": "DOGE_USDC",
359
+ # "candleWindows": [
360
+ # "1m",
361
+ # "3m",
362
+ # "5m",
363
+ # "15m",
364
+ # "30m",
365
+ # "1h",
366
+ # "2h",
367
+ # "4h",
368
+ # "12h",
369
+ # "1d",
370
+ # "1w",
371
+ # "1M"
372
+ # ],
373
+ # "depthSlabs": [
374
+ # "0.00001",
375
+ # "0.00005",
376
+ # "0.0001",
377
+ # "0.001",
378
+ # "0.01"
379
+ # ],
380
+ # "filters": [
381
+ # {
382
+ # "filterType": "LOT_SIZE",
383
+ # "minQty": "1.00000",
384
+ # "maxQty": "1500000.00000",
385
+ # "stepSize": "1.00000"
386
+ # },
387
+ # {
388
+ # "filterType": "MARKET_LOT_SIZE",
389
+ # "minQty": "1.00000",
390
+ # "maxQty": "750000.00000",
391
+ # "stepSize": "1.00000"
392
+ # },
393
+ # {
394
+ # "filterType": "PRICE_FILTER",
395
+ # "minPrice": "0.00244000",
396
+ # "maxPrice": "30.00000000",
397
+ # "tickSize": "0.00001"
398
+ # },
399
+ # {
400
+ # "filterType": "NOTIONAL",
401
+ # "minNotional": "100.00000000"
402
+ # },
403
+ # {
404
+ # "filterType": "PERCENT_PRICE_BY_SIDE",
405
+ # "bidMultiplierUp": "1.5",
406
+ # "bidMultiplierDown": "0.5",
407
+ # "askMultiplierUp": "1.5",
408
+ # "askMultiplierDown": "0.5"
409
+ # },
410
+ # {
411
+ # "filterType": "INDEX_PRICE_FILTER",
412
+ # "multiplierUp": "1.3",
413
+ # "multiplierDown": "0.7"
414
+ # }
415
+ # ],
416
+ # "cappedLeverage": "25",
417
+ # "maintenanceMarginTiers": [
418
+ # {
419
+ # "tier": "1",
420
+ # "minMaintenanceMargin": "0",
421
+ # "maxMaintenanceMargin": "2500",
422
+ # "leverage": "25"
423
+ # },
424
+ # {
425
+ # "tier": "2",
426
+ # "minMaintenanceMargin": "2500",
427
+ # "maxMaintenanceMargin": "12500",
428
+ # "leverage": "20"
429
+ # },
430
+ # {
431
+ # "tier": "3",
432
+ # "minMaintenanceMargin": "12500",
433
+ # "maxMaintenanceMargin": "25000",
434
+ # "leverage": "15"
435
+ # },
436
+ # {
437
+ # "tier": "4",
438
+ # "minMaintenanceMargin": "25000",
439
+ # "maxMaintenanceMargin": "50000",
440
+ # "leverage": "10"
441
+ # },
442
+ # {
443
+ # "tier": "5",
444
+ # "minMaintenanceMargin": "50000",
445
+ # "maxMaintenanceMargin": "75000",
446
+ # "leverage": "8"
447
+ # },
448
+ # {
449
+ # "tier": "6",
450
+ # "minMaintenanceMargin": "75000",
451
+ # "maxMaintenanceMargin": "125000",
452
+ # "leverage": "7"
453
+ # },
454
+ # {
455
+ # "tier": "7",
456
+ # "minMaintenanceMargin": "125000",
457
+ # "maxMaintenanceMargin": "187500",
458
+ # "leverage": "5"
459
+ # },
460
+ # {
461
+ # "tier": "8",
462
+ # "minMaintenanceMargin": "187500",
463
+ # "maxMaintenanceMargin": "250000",
464
+ # "leverage": "3"
465
+ # },
466
+ # {
467
+ # "tier": "9",
468
+ # "minMaintenanceMargin": "250000",
469
+ # "maxMaintenanceMargin": "375000",
470
+ # "leverage": "2"
471
+ # },
472
+ # {
473
+ # "tier": "10",
474
+ # "minMaintenanceMargin": "375000",
475
+ # "maxMaintenanceMargin": "500000",
476
+ # "leverage": "1"
477
+ # }
478
+ # ],
479
+ # "fees": {
480
+ # "maker": "0.08",
481
+ # "taker": "0.1"
482
+ # }
483
+ # },
484
+ # ]
485
+ # }
486
+ #
487
+ activeMarkets = self.safe_list(responses[0], 'data')
488
+ activeMarketsByType = self.index_by(activeMarkets, 'market')
489
+ marketMetadatas = self.safe_list(responses[1], 'data')
490
+ for i in range(0, len(marketMetadatas)):
491
+ marketId = marketMetadatas[i]['market']
492
+ status = None
493
+ if marketId in activeMarketsByType:
494
+ status = activeMarketsByType[marketId]['status']
495
+ marketMetadatas[i]['status'] = status
496
+ return self.parse_markets(marketMetadatas)
497
+
498
+ def parse_market(self, market: dict) -> Market:
499
+ marketId = self.safe_string(market, 'market')
500
+ parts = marketId.split('_')
501
+ baseId = self.safe_string(parts, 0)
502
+ quoteId = self.safe_string(parts, 1)
503
+ base = self.safe_currency_code(baseId)
504
+ quote = self.safe_currency_code(quoteId)
505
+ symbol = base + '/' + quote + ':' + quote
506
+ filters = self.safe_list(market, 'filters', [])
507
+ fees = self.safe_dict(market, 'fees', {})
508
+ filtersByType = self.index_by(filters, 'filterType')
509
+ priceFilter = self.safe_dict(filtersByType, 'PRICE_FILTER', {})
510
+ lotFilter = self.safe_dict(filtersByType, 'LOT_SIZE', {})
511
+ marketLotFilter = self.safe_dict(filtersByType, 'MARKET_LOT_SIZE', {})
512
+ notionalFilter = self.safe_dict(filtersByType, 'NOTIONAL', {})
513
+ return {
514
+ 'id': marketId,
515
+ 'symbol': symbol,
516
+ 'base': base,
517
+ 'quote': quote,
518
+ 'settle': quote,
519
+ 'baseId': baseId,
520
+ 'quoteId': quoteId,
521
+ 'settleId': quoteId,
522
+ 'type': 'swap',
523
+ 'spot': False,
524
+ 'margin': False,
525
+ 'swap': True,
526
+ 'future': False,
527
+ 'option': False,
528
+ 'active': self.safe_string(market, 'status', '') == 'active',
529
+ 'contract': True,
530
+ 'linear': True,
531
+ 'inverse': None,
532
+ 'taker': self.safe_number(fees, 'taker'),
533
+ 'maker': self.safe_number(fees, 'maker'),
534
+ 'contractSize': self.parse_number('1'),
535
+ 'expiry': None,
536
+ 'expiryDatetime': None,
537
+ 'strike': None,
538
+ 'optionType': None,
539
+ 'precision': {
540
+ 'amount': self.safe_number(lotFilter, 'stepSize'),
541
+ 'price': self.safe_number(priceFilter, 'tickSize'),
542
+ },
543
+ 'limits': {
544
+ 'leverage': {
545
+ 'min': None,
546
+ 'max': self.safe_number(market, 'cappedLeverage'),
547
+ },
548
+ 'amount': {
549
+ 'min': self.safe_number(lotFilter, 'minQty'),
550
+ 'max': self.safe_number(lotFilter, 'maxQty'),
551
+ },
552
+ 'price': {
553
+ 'min': self.safe_number(priceFilter, 'minPrice'),
554
+ 'max': self.safe_number(priceFilter, 'maxPrice'),
555
+ },
556
+ 'cost': {
557
+ 'min': self.safe_number(notionalFilter, 'minNotional'),
558
+ 'max': None,
559
+ },
560
+ 'market': {
561
+ 'min': self.safe_number(marketLotFilter, 'minQty'),
562
+ 'max': self.safe_number(marketLotFilter, 'maxQty'),
563
+ },
564
+ },
565
+ 'created': None,
566
+ 'info': market,
567
+ }
568
+
569
+ async def fetch_ticker(self, symbol: str, params={}) -> Ticker:
570
+ """
571
+ fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
572
+
573
+ https://api-docs.defx.com/#fe6f81d0-2f3a-4eee-976f-c8fc8f4c5d56
574
+
575
+ :param str symbol: unified symbol of the market to fetch the ticker for
576
+ :param dict [params]: extra parameters specific to the exchange API endpoint
577
+ :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
578
+ """
579
+ await self.load_markets()
580
+ market = self.market(symbol)
581
+ request: dict = {
582
+ 'symbol': market['id'],
583
+ }
584
+ response = await self.v1PublicGetSymbolsSymbolTicker24hr(self.extend(request, params))
585
+ #
586
+ # {
587
+ # "symbol": "BTC_USDC",
588
+ # "priceChange": "0",
589
+ # "priceChangePercent": "0",
590
+ # "weightedAvgPrice": "0",
591
+ # "lastPrice": "2.00",
592
+ # "lastQty": "10.000",
593
+ # "bestBidPrice": "1646.00",
594
+ # "bestBidQty": "10.000",
595
+ # "bestAskPrice": "1646.00",
596
+ # "bestAskQty": "10.000",
597
+ # "openPrice": "0.00",
598
+ # "highPrice": "0.00",
599
+ # "lowPrice": "0.00",
600
+ # "volume": "0.000",
601
+ # "quoteVolume": "0.00",
602
+ # "openTime": 1700142658697,
603
+ # "closeTime": 1700142658697,
604
+ # "openInterestBase": "1.000",
605
+ # "openInterestQuote": "0.43112300"
606
+ # }
607
+ #
608
+ return self.parse_ticker(response, market)
609
+
610
+ async def fetch_tickers(self, symbols: Strings = None, params={}) -> Tickers:
611
+ """
612
+ fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market
613
+
614
+ https://api-docs.defx.com/#8c61cfbd-40d9-410e-b014-f5b36eba51d1
615
+
616
+ :param str[]|None symbols: unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
617
+ :param dict [params]: extra parameters specific to the exchange API endpoint
618
+ :returns dict: a dictionary of `ticker structures <https://docs.ccxt.com/#/?id=ticker-structure>`
619
+ """
620
+ await self.load_markets()
621
+ market = None
622
+ if symbols is not None:
623
+ symbols = self.market_symbols(symbols)
624
+ firstSymbol = self.safe_string(symbols, 0)
625
+ if firstSymbol is not None:
626
+ market = self.market(firstSymbol)
627
+ type = None
628
+ type, params = self.handle_market_type_and_params('fetchTickers', market, params)
629
+ if type == 'spot':
630
+ raise NotSupported(self.id + ' fetchTickers() is not supported for ' + type + ' markets')
631
+ response = await self.v1PublicGetTicker24HrAgg(params)
632
+ #
633
+ # {
634
+ # "ETH_USDC": {
635
+ # "priceChange": "0",
636
+ # "priceChangePercent": "0",
637
+ # "openPrice": "1646.15",
638
+ # "highPrice": "1646.15",
639
+ # "lowPrice": "1646.15",
640
+ # "lastPrice": "1646.15",
641
+ # "quoteVolume": "13.17",
642
+ # "volume": "0.008",
643
+ # "markPrice": "1645.15"
644
+ # }
645
+ # }
646
+ #
647
+ return self.parse_tickers(response, symbols)
648
+
649
+ def parse_ticker(self, ticker: dict, market: Market = None) -> Ticker:
650
+ #
651
+ # fetchTicker
652
+ #
653
+ # {
654
+ # "symbol": "BTC_USDC",
655
+ # "priceChange": "0",
656
+ # "priceChangePercent": "0",
657
+ # "weightedAvgPrice": "0",
658
+ # "lastPrice": "2.00",
659
+ # "lastQty": "10.000",
660
+ # "bestBidPrice": "1646.00",
661
+ # "bestBidQty": "10.000",
662
+ # "bestAskPrice": "1646.00",
663
+ # "bestAskQty": "10.000",
664
+ # "openPrice": "0.00",
665
+ # "highPrice": "0.00",
666
+ # "lowPrice": "0.00",
667
+ # "volume": "0.000",
668
+ # "quoteVolume": "0.00",
669
+ # "openTime": 1700142658697,
670
+ # "closeTime": 1700142658697,
671
+ # "openInterestBase": "1.000",
672
+ # "openInterestQuote": "0.43112300"
673
+ # }
674
+ #
675
+ # fetchTickers
676
+ #
677
+ # "ETH_USDC": {
678
+ # "priceChange": "0",
679
+ # "priceChangePercent": "0",
680
+ # "openPrice": "1646.15",
681
+ # "highPrice": "1646.15",
682
+ # "lowPrice": "1646.15",
683
+ # "lastPrice": "1646.15",
684
+ # "quoteVolume": "13.17",
685
+ # "volume": "0.008",
686
+ # "markPrice": "1645.15"
687
+ # }
688
+ #
689
+ # fetchMarkPrice
690
+ #
691
+ # {
692
+ # "markPrice": "100.00",
693
+ # "indexPrice": "100.00",
694
+ # "ltp": "101.34",
695
+ # "movingFundingRate": "0.08",
696
+ # "payoutFundingRate": "-0.03",
697
+ # "nextFundingPayout": 1711555532146
698
+ # }
699
+ #
700
+ marketId = self.safe_string(ticker, 'symbol')
701
+ if marketId is not None:
702
+ market = self.market(marketId)
703
+ symbol = market['symbol']
704
+ open = self.safe_string(ticker, 'openPrice')
705
+ high = self.safe_string(ticker, 'highPrice')
706
+ low = self.safe_string(ticker, 'lowPrice')
707
+ close = self.safe_string(ticker, 'lastPrice')
708
+ quoteVolume = self.safe_string(ticker, 'quoteVolume')
709
+ baseVolume = self.safe_string(ticker, 'volume')
710
+ percentage = self.safe_string(ticker, 'priceChangePercent')
711
+ change = self.safe_string(ticker, 'priceChange')
712
+ ts = self.safe_integer(ticker, 'closeTime')
713
+ if ts == 0:
714
+ ts = None
715
+ datetime = self.iso8601(ts)
716
+ bid = self.safe_string(ticker, 'bestBidPrice')
717
+ bidVolume = self.safe_string(ticker, 'bestBidQty')
718
+ ask = self.safe_string(ticker, 'bestAskPrice')
719
+ askVolume = self.safe_string(ticker, 'bestAskQty')
720
+ return self.safe_ticker({
721
+ 'symbol': symbol,
722
+ 'timestamp': ts,
723
+ 'datetime': datetime,
724
+ 'high': high,
725
+ 'low': low,
726
+ 'bid': bid,
727
+ 'bidVolume': bidVolume,
728
+ 'ask': ask,
729
+ 'askVolume': askVolume,
730
+ 'vwap': None,
731
+ 'open': open,
732
+ 'close': close,
733
+ 'last': None,
734
+ 'previousClose': None,
735
+ 'change': change,
736
+ 'percentage': percentage,
737
+ 'average': None,
738
+ 'baseVolume': baseVolume,
739
+ 'quoteVolume': quoteVolume,
740
+ 'markPrice': self.safe_string(ticker, 'markPrice'),
741
+ 'indexPrice': self.safe_string(ticker, 'indexPrice'),
742
+ 'info': ticker,
743
+ }, market)
744
+
745
+ async def fetch_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}) -> List[list]:
746
+ """
747
+
748
+ https://api-docs.defx.com/#54b71951-1472-4670-b5af-4c2dc41e73d0
749
+
750
+ fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
751
+ :param str symbol: unified symbol of the market to fetch OHLCV data for
752
+ :param str timeframe: the length of time each candle represents
753
+ :param int [since]: timestamp in ms of the earliest candle to fetch
754
+ :param int [limit]: max=1000, max=100 when since is defined and is less than(now - (999 * (timeframe in ms)))
755
+ :param dict [params]: extra parameters specific to the exchange API endpoint
756
+ :param int [params.until]: the latest time in ms to fetch orders for
757
+ :returns int[][]: A list of candles ordered, open, high, low, close, volume
758
+ """
759
+ await self.load_markets()
760
+ market = self.market(symbol)
761
+ maxLimit = 1000
762
+ if limit is None:
763
+ limit = maxLimit
764
+ limit = min(maxLimit, limit)
765
+ request: dict = {
766
+ 'symbol': market['id'],
767
+ 'interval': self.safe_string(self.timeframes, timeframe, timeframe),
768
+ 'limit': limit,
769
+ }
770
+ until = self.safe_integer_2(params, 'until', 'till')
771
+ params = self.omit(params, ['until', 'till'])
772
+ request['endTime'] = self.milliseconds() if (until is None) else until
773
+ if since is None:
774
+ request['startTime'] = 0
775
+ else:
776
+ request['startTime'] = since
777
+ if until is None:
778
+ timeframeInSeconds = self.parse_timeframe(timeframe)
779
+ timeframeInMilliseconds = timeframeInSeconds * 1000
780
+ totalTimeframeInMilliseconds = limit * timeframeInMilliseconds
781
+ request['endTime'] = self.sum(since, totalTimeframeInMilliseconds)
782
+ response = await self.v1PublicGetSymbolsSymbolOhlc(self.extend(request, params))
783
+ #
784
+ # [
785
+ # {
786
+ # "symbol": "BTC_USDC",
787
+ # "open": "0.00",
788
+ # "high": "0.00",
789
+ # "low": "0.00",
790
+ # "close": "0.00",
791
+ # "volume": "0.000",
792
+ # "quoteAssetVolume": "0.00",
793
+ # "takerBuyAssetVolume": "0.000",
794
+ # "takerBuyQuoteAssetVolume": "0.00",
795
+ # "numberOfTrades": 0,
796
+ # "start": 1702453663894,
797
+ # "end": 1702453663894,
798
+ # "isClosed": True
799
+ # }
800
+ # ]
801
+ #
802
+ return self.parse_ohlcvs(response, market, timeframe, since, limit)
803
+
804
+ def parse_ohlcv(self, ohlcv, market: Market = None) -> list:
805
+ # example response in fetchOHLCV
806
+ return [
807
+ self.safe_integer(ohlcv, 'start'),
808
+ self.safe_number(ohlcv, 'open'),
809
+ self.safe_number(ohlcv, 'high'),
810
+ self.safe_number(ohlcv, 'low'),
811
+ self.safe_number(ohlcv, 'close'),
812
+ self.safe_number(ohlcv, 'volume'),
813
+ ]
814
+
815
+ async def fetch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
816
+ """
817
+ get the list of most recent trades for a particular symbol
818
+
819
+ https://api-docs.defx.com/#5865452f-ea32-4f13-bfbc-03af5f5574fd
820
+
821
+ :param str symbol: unified symbol of the market to fetch trades for
822
+ :param int [since]: timestamp in ms of the earliest trade to fetch
823
+ :param int [limit]: the maximum amount of trades to fetch
824
+ :param dict [params]: extra parameters specific to the exchange API endpoint
825
+ :returns Trade[]: a list of `trade structures <https://docs.ccxt.com/#/?id=public-trades>`
826
+ """
827
+ await self.load_markets()
828
+ market = self.market(symbol)
829
+ maxLimit = 50
830
+ if limit is None:
831
+ limit = maxLimit
832
+ limit = min(maxLimit, limit)
833
+ request: dict = {
834
+ 'symbol': market['id'],
835
+ 'limit': limit,
836
+ }
837
+ response = await self.v1PublicGetSymbolsSymbolTrades(self.extend(request, params))
838
+ #
839
+ # [
840
+ # {
841
+ # "buyerMaker": "false",
842
+ # "price": "2.0000",
843
+ # "qty": "10.0000",
844
+ # "symbol": "BTC_USDC",
845
+ # "timestamp": "1702453663894"
846
+ # }
847
+ # ]
848
+ #
849
+ return self.parse_trades(response, market, since, limit)
850
+
851
+ async def fetch_my_trades(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
852
+ """
853
+ fetch all trades made by the user
854
+
855
+ https://api-docs.defx.com/#06b5b33c-2fc6-48de-896c-fc316f5871a7
856
+
857
+ :param str symbol: unified symbol of the market to fetch trades for
858
+ :param int [since]: timestamp in ms of the earliest trade to fetch
859
+ :param int [limit]: the maximum amount of trades to fetch
860
+ :param dict [params]: extra parameters specific to the exchange API endpoint
861
+ :returns Trade[]: a list of `trade structures <https://docs.ccxt.com/#/?id=public-trades>`
862
+ """
863
+ await self.load_markets()
864
+ request: dict = {}
865
+ if symbol is not None:
866
+ market = self.market(symbol)
867
+ request['symbols'] = market['id']
868
+ if limit is not None:
869
+ maxLimit = 100
870
+ limit = min(maxLimit, limit)
871
+ request['pageSize'] = limit
872
+ response = await self.v1PrivateGetApiTrades(self.extend(request, params))
873
+ #
874
+ # {
875
+ # "data": [
876
+ # {
877
+ # "id": "0192f665-c05b-7ba0-a080-8b6c99083489",
878
+ # "orderId": "757730811259651728",
879
+ # "time": "2024-11-04T08:58:36.474Z",
880
+ # "symbol": "SOL_USDC",
881
+ # "side": "SELL",
882
+ # "price": "160.43600000",
883
+ # "qty": "1.00",
884
+ # "fee": "0.08823980",
885
+ # "role": "TAKER",
886
+ # "pnl": "0.00000000"
887
+ # }
888
+ # ]
889
+ # }
890
+ #
891
+ data = self.safe_list(response, 'data', [])
892
+ return self.parse_trades(data, None, since, limit)
893
+
894
+ def parse_trade(self, trade: dict, market: Market = None) -> Trade:
895
+ #
896
+ # fetchTrades
897
+ # {
898
+ # "buyerMaker": "false",
899
+ # "price": "2.0000",
900
+ # "qty": "10.0000",
901
+ # "symbol": "BTC_USDC",
902
+ # "timestamp": "1702453663894"
903
+ # }
904
+ #
905
+ # fetchMyTrades
906
+ # {
907
+ # "id": "0192f665-c05b-7ba0-a080-8b6c99083489",
908
+ # "orderId": "757730811259651728",
909
+ # "time": "2024-11-04T08:58:36.474Z",
910
+ # "symbol": "SOL_USDC",
911
+ # "side": "SELL",
912
+ # "price": "160.43600000",
913
+ # "qty": "1.00",
914
+ # "fee": "0.08823980",
915
+ # "role": "TAKER",
916
+ # "pnl": "0.00000000"
917
+ # }
918
+ #
919
+ time = self.safe_string(trade, 'time')
920
+ timestamp = self.safe_integer(trade, 'timestamp', self.parse8601(time))
921
+ marketId = self.safe_string(trade, 'symbol')
922
+ market = self.safe_market(marketId, market)
923
+ symbol = market['symbol']
924
+ price = self.safe_string(trade, 'price')
925
+ amount = self.safe_string(trade, 'qty')
926
+ id = self.safe_string(trade, 'id')
927
+ oid = self.safe_string(trade, 'orderId')
928
+ takerOrMaker = self.safe_string_lower(trade, 'role')
929
+ buyerMaker = self.safe_string(trade, 'buyerMaker')
930
+ side = self.safe_string_lower(trade, 'side')
931
+ if buyerMaker is not None:
932
+ if buyerMaker == 'true':
933
+ side = 'sell'
934
+ else:
935
+ side = 'buy'
936
+ return self.safe_trade({
937
+ 'id': id,
938
+ 'timestamp': timestamp,
939
+ 'datetime': self.iso8601(timestamp),
940
+ 'symbol': symbol,
941
+ 'side': side,
942
+ 'price': price,
943
+ 'amount': amount,
944
+ 'cost': None,
945
+ 'order': oid,
946
+ 'takerOrMaker': takerOrMaker,
947
+ 'type': None,
948
+ 'fee': {
949
+ 'cost': self.safe_string(trade, 'fee'),
950
+ 'currency': 'USDC',
951
+ },
952
+ 'info': trade,
953
+ }, market)
954
+
955
+ async def fetch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook:
956
+ """
957
+ fetches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
958
+
959
+ https://api-docs.defx.com/#6c1a2971-8325-4e7d-9962-e0bfcaacf9c4
960
+
961
+ :param str symbol: unified symbol of the market to fetch the order book for
962
+ :param int [limit]: the maximum amount of order book entries to return
963
+ :param dict [params]: extra parameters specific to the exchange API endpoint
964
+ :param str [params.slab]: slab from market.info.depthSlabs
965
+ :returns dict: A dictionary of `order book structures <https://docs.ccxt.com/#/?id=order-book-structure>` indexed by market symbols
966
+ """
967
+ await self.load_markets()
968
+ market = self.market(symbol)
969
+ if limit is None:
970
+ limit = 10 # limit must be one of [5, 10, 20]
971
+ marketInfo = self.safe_dict(market, 'info', {})
972
+ slab = self.safe_list(marketInfo, 'depthSlabs', [])
973
+ request: dict = {
974
+ 'symbol': market['id'],
975
+ 'level': limit,
976
+ 'slab': self.safe_string(slab, 0),
977
+ }
978
+ response = await self.v1PublicGetSymbolsSymbolDepthLevelSlab(self.extend(request, params))
979
+ #
980
+ # {
981
+ # "symbol": "ETH_USDC",
982
+ # "level": "5",
983
+ # "slab": "1",
984
+ # "lastTradeTimestamp": "1708313446812",
985
+ # "timestamp": "1708313446812",
986
+ # "bids": [
987
+ # {
988
+ # "price": "1646.16",
989
+ # "qty": "0.001"
990
+ # }
991
+ # ],
992
+ # "asks": [
993
+ # {
994
+ # "price": "1646.16",
995
+ # "qty": "0.001"
996
+ # }
997
+ # ]
998
+ # }
999
+ #
1000
+ timestamp = self.safe_integer(response, 'timestamp')
1001
+ return self.parse_order_book(response, symbol, timestamp, 'bids', 'asks', 'price', 'qty')
1002
+
1003
+ async def fetch_mark_price(self, symbol: str, params={}) -> Ticker:
1004
+ """
1005
+ fetches mark price for the market
1006
+
1007
+ https://api-docs.defx.com/#12168192-4e7b-4458-a001-e8b80961f0b7
1008
+
1009
+ :param str symbol: unified symbol of the market to fetch the ticker for
1010
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1011
+ :param str [params.subType]: "linear" or "inverse"
1012
+ :returns dict: a dictionary of `ticker structures <https://docs.ccxt.com/#/?id=ticker-structure>`
1013
+ """
1014
+ await self.load_markets()
1015
+ market = self.market(symbol)
1016
+ request = {
1017
+ 'symbol': market['id'],
1018
+ }
1019
+ response = await self.v1PublicGetSymbolsSymbolPrices(self.extend(request, params))
1020
+ #
1021
+ # {
1022
+ # "markPrice": "100.00",
1023
+ # "indexPrice": "100.00",
1024
+ # "ltp": "101.34",
1025
+ # "movingFundingRate": "0.08",
1026
+ # "payoutFundingRate": "-0.03",
1027
+ # "nextFundingPayout": 1711555532146
1028
+ # }
1029
+ #
1030
+ return self.parse_ticker(response, market)
1031
+
1032
+ async def fetch_funding_rate(self, symbol: str, params={}) -> FundingRate:
1033
+ """
1034
+ fetch the current funding rate
1035
+
1036
+ https://api-docs.defx.com/#12168192-4e7b-4458-a001-e8b80961f0b7
1037
+
1038
+ :param str symbol: unified market symbol
1039
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1040
+ :returns dict: a `funding rate structure <https://docs.ccxt.com/#/?id=funding-rate-structure>`
1041
+ """
1042
+ await self.load_markets()
1043
+ market = self.market(symbol)
1044
+ request = {
1045
+ 'symbol': market['id'],
1046
+ }
1047
+ response = await self.v1PublicGetSymbolsSymbolPrices(self.extend(request, params))
1048
+ #
1049
+ # {
1050
+ # "markPrice": "100.00",
1051
+ # "indexPrice": "100.00",
1052
+ # "ltp": "101.34",
1053
+ # "movingFundingRate": "0.08",
1054
+ # "payoutFundingRate": "-0.03",
1055
+ # "nextFundingPayout": 1711555532146
1056
+ # }
1057
+ #
1058
+ return self.parse_funding_rate(response, market)
1059
+
1060
+ def parse_funding_rate(self, contract, market: Market = None) -> FundingRate:
1061
+ #
1062
+ # {
1063
+ # "markPrice": "100.00",
1064
+ # "indexPrice": "100.00",
1065
+ # "ltp": "101.34",
1066
+ # "movingFundingRate": "0.08",
1067
+ # "payoutFundingRate": "-0.03",
1068
+ # "nextFundingPayout": 1711555532146
1069
+ # }
1070
+ #
1071
+ markPrice = self.safe_number(contract, 'markPrice')
1072
+ indexPrice = self.safe_number(contract, 'indexPrice')
1073
+ fundingRate = self.safe_number(contract, 'payoutFundingRate')
1074
+ fundingTime = self.safe_integer(contract, 'nextFundingPayout')
1075
+ return {
1076
+ 'info': contract,
1077
+ 'symbol': market['symbol'],
1078
+ 'markPrice': markPrice,
1079
+ 'indexPrice': indexPrice,
1080
+ 'interestRate': None,
1081
+ 'estimatedSettlePrice': None,
1082
+ 'timestamp': None,
1083
+ 'datetime': None,
1084
+ 'fundingRate': fundingRate,
1085
+ 'fundingTimestamp': fundingTime,
1086
+ 'fundingDatetime': self.iso8601(fundingTime),
1087
+ 'nextFundingRate': None,
1088
+ 'nextFundingTimestamp': None,
1089
+ 'nextFundingDatetime': None,
1090
+ 'previousFundingRate': None,
1091
+ 'previousFundingTimestamp': None,
1092
+ 'previousFundingDatetime': None,
1093
+ 'interval': None,
1094
+ }
1095
+
1096
+ async def fetch_balance(self, params={}) -> Balances:
1097
+ """
1098
+ query for balance and get the amount of funds available for trading or funds locked in orders
1099
+
1100
+ https://api-docs.defx.com/#26414338-14f7-40a1-b246-f8ea8571493f
1101
+
1102
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1103
+ :returns dict: a `balance structure <https://docs.ccxt.com/#/?id=balance-structure>`
1104
+ """
1105
+ await self.load_markets()
1106
+ response = await self.v1PrivateGetApiWalletBalance(params)
1107
+ #
1108
+ # {
1109
+ # "assets": [
1110
+ # {
1111
+ # "asset": "USDC",
1112
+ # "balance": "0.000"
1113
+ # }
1114
+ # ]
1115
+ # }
1116
+ #
1117
+ data = self.safe_list(response, 'assets')
1118
+ return self.parse_balance(data)
1119
+
1120
+ def parse_balance(self, balances) -> Balances:
1121
+ result: dict = {
1122
+ 'info': balances,
1123
+ }
1124
+ for i in range(0, len(balances)):
1125
+ balance = balances[i]
1126
+ code = self.safe_currency_code(self.safe_string(balance, 'asset'))
1127
+ account = self.account()
1128
+ account['total'] = self.safe_string(balance, 'balance')
1129
+ result[code] = account
1130
+ return self.safe_balance(result)
1131
+
1132
+ async def create_order(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
1133
+ """
1134
+ create a trade order
1135
+
1136
+ https://api-docs.defx.com/#ba222d88-8856-4d3c-87a9-7cec07bb2622
1137
+
1138
+ :param str symbol: unified symbol of the market to create an order in
1139
+ :param str type: 'market' or 'limit'
1140
+ :param str side: 'buy' or 'sell'
1141
+ :param float amount: how much of currency you want to trade in units of base currency
1142
+ :param float [price]: the price at which the order is to be fulfilled, in units of the quote currency, ignored in market orders
1143
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1144
+ :param float [params.triggerPrice]: The price a trigger order is triggered at
1145
+ :param str [params.reduceOnly]: for swap and future reduceOnly is a string 'true' or 'false' that cant be sent with close position set to True or in hedge mode. For spot margin and option reduceOnly is a boolean.
1146
+ :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1147
+ """
1148
+ await self.load_markets()
1149
+ market = self.market(symbol)
1150
+ reduceOnly = self.safe_bool_2(params, 'reduceOnly', 'reduce_only')
1151
+ params = self.omit(params, ['reduceOnly', 'reduce_only'])
1152
+ orderType = type.upper()
1153
+ orderSide = side.upper()
1154
+ request: dict = {
1155
+ 'symbol': market['id'],
1156
+ 'side': orderSide,
1157
+ 'type': orderType,
1158
+ }
1159
+ takeProfitPrice = self.safe_string(params, 'takeProfitPrice')
1160
+ stopPrice = self.safe_string_2(params, 'stopPrice', 'triggerPrice')
1161
+ isMarket = orderType == 'MARKET'
1162
+ isLimit = orderType == 'LIMIT'
1163
+ timeInForce = self.safe_string_upper(params, 'timeInForce')
1164
+ if timeInForce is not None:
1165
+ # GTC, IOC, FOK, AON
1166
+ request['timeInForce'] = timeInForce
1167
+ else:
1168
+ if isLimit:
1169
+ request['timeInForce'] = 'GTC'
1170
+ if reduceOnly:
1171
+ request['reduceOnly'] = reduceOnly
1172
+ clientOrderId = self.safe_string(params, 'clientOrderId')
1173
+ if clientOrderId is not None:
1174
+ request['newClientOrderId'] = clientOrderId
1175
+ if stopPrice is not None or takeProfitPrice is not None:
1176
+ request['workingType'] = 'MARK_PRICE'
1177
+ if takeProfitPrice is not None:
1178
+ request['stopPrice'] = self.price_to_precision(symbol, takeProfitPrice)
1179
+ if isMarket:
1180
+ request['type'] = 'TAKE_PROFIT_MARKET'
1181
+ else:
1182
+ request['type'] = 'TAKE_PROFIT_LIMIT'
1183
+ else:
1184
+ request['stopPrice'] = self.price_to_precision(symbol, stopPrice)
1185
+ if isMarket:
1186
+ request['type'] = 'STOP_MARKET'
1187
+ else:
1188
+ request['type'] = 'STOP_LIMIT'
1189
+ if isLimit and price is not None:
1190
+ request['price'] = self.price_to_precision(symbol, price)
1191
+ request['quantity'] = self.amount_to_precision(symbol, amount)
1192
+ params = self.omit(params, ['clOrdID', 'clientOrderId', 'client_order_id', 'postOnly', 'timeInForce', 'stopPrice', 'triggerPrice', 'takeProfitPrice'])
1193
+ response = await self.v1PrivatePostApiOrder(self.extend(request, params))
1194
+ #
1195
+ # {
1196
+ # "success": True,
1197
+ # "data": {
1198
+ # "orderId": "",
1199
+ # "clientOrderId": "",
1200
+ # "cumulativeQty": "",
1201
+ # "cumulativeQuote": "",
1202
+ # "executedQty": "",
1203
+ # "avgPrice": "",
1204
+ # "origQty": "",
1205
+ # "price": "",
1206
+ # "reduceOnly": True,
1207
+ # "side": "",
1208
+ # "status": "",
1209
+ # "symbol": "",
1210
+ # "timeInForce": "",
1211
+ # "type": "",
1212
+ # "workingType": ""
1213
+ # }
1214
+ # }
1215
+ #
1216
+ data = self.safe_dict(response, 'data')
1217
+ return self.parse_order(data, market)
1218
+
1219
+ def parse_order_status(self, status: Str):
1220
+ if status is not None:
1221
+ statuses: dict = {
1222
+ 'NEW': 'open',
1223
+ 'OPEN': 'open',
1224
+ 'CANCELLED': 'canceled',
1225
+ 'REJECTED': 'rejected',
1226
+ 'FILLED': 'closed',
1227
+ }
1228
+ return self.safe_string(statuses, status, status)
1229
+ return status
1230
+
1231
+ def parse_order(self, order: dict, market: Market = None) -> Order:
1232
+ #
1233
+ # {
1234
+ # "orderId": "746472647227344528",
1235
+ # "createdAt": "2024-10-25T16:49:31.077Z",
1236
+ # "updatedAt": "2024-10-25T16:49:31.378Z",
1237
+ # "clientOrderId": "0192c495-49c3-71ee-b3d3-7442a2090807",
1238
+ # "reduceOnly": False,
1239
+ # "side": "SELL",
1240
+ # "status": "FILLED",
1241
+ # "symbol": "SOL_USDC",
1242
+ # "timeInForce": "GTC",
1243
+ # "type": "MARKET",
1244
+ # "origQty": "0.80",
1245
+ # "executedQty": "0.80",
1246
+ # "cumulativeQuote": "137.87440000",
1247
+ # "avgPrice": "172.34300000",
1248
+ # "totalPnL": "0.00000000",
1249
+ # "totalFee": "0.07583092",
1250
+ # "workingType": null,
1251
+ # "postOnly": False,
1252
+ # "linkedOrderParentType": null,
1253
+ # "isTriggered": False,
1254
+ # "slippagePercentage": "5"
1255
+ # }
1256
+ #
1257
+ orderId = self.safe_string(order, 'orderId')
1258
+ clientOrderId = self.safe_string(order, 'clientOrderId')
1259
+ marketId = self.safe_string(order, 'symbol')
1260
+ market = self.safe_market(marketId, market)
1261
+ symbol = market['symbol']
1262
+ price = self.safe_string(order, 'price')
1263
+ amount = self.safe_string(order, 'origQty')
1264
+ orderType = self.safe_string_lower(order, 'type')
1265
+ status = self.safe_string(order, 'status')
1266
+ side = self.safe_string_lower(order, 'side')
1267
+ filled = self.omit_zero(self.safe_string(order, 'executedQty'))
1268
+ average = self.omit_zero(self.safe_string(order, 'avgPrice'))
1269
+ timeInForce = self.safe_string_lower(order, 'timeInForce')
1270
+ takeProfitPrice: Str = None
1271
+ stopPrice: Str = None
1272
+ if orderType is not None:
1273
+ if orderType.find('take_profit') >= 0:
1274
+ takeProfitPrice = self.safe_string(order, 'stopPrice')
1275
+ else:
1276
+ stopPrice = self.safe_string(order, 'stopPrice')
1277
+ timestamp = self.parse8601(self.safe_string(order, 'createdAt'))
1278
+ lastTradeTimestamp = self.parse8601(self.safe_string(order, 'updatedAt'))
1279
+ return self.safe_order({
1280
+ 'id': orderId,
1281
+ 'clientOrderId': clientOrderId,
1282
+ 'timestamp': timestamp,
1283
+ 'datetime': self.iso8601(timestamp),
1284
+ 'lastTradeTimestamp': lastTradeTimestamp,
1285
+ 'lastUpdateTimestamp': lastTradeTimestamp,
1286
+ 'status': self.parse_order_status(status),
1287
+ 'symbol': symbol,
1288
+ 'type': orderType,
1289
+ 'timeInForce': timeInForce,
1290
+ 'postOnly': self.safe_bool(order, 'postOnly'),
1291
+ 'reduceOnly': self.safe_bool(order, 'reduceOnly'),
1292
+ 'side': side,
1293
+ 'price': price,
1294
+ 'stopPrice': stopPrice,
1295
+ 'triggerPrice': stopPrice,
1296
+ 'takeProfitPrice': takeProfitPrice,
1297
+ 'stopLossPrice': None,
1298
+ 'average': average,
1299
+ 'amount': amount,
1300
+ 'filled': filled,
1301
+ 'remaining': None,
1302
+ 'cost': None,
1303
+ 'trades': None,
1304
+ 'fee': {
1305
+ 'cost': self.safe_string(order, 'totalFee'),
1306
+ 'currency': 'USDC',
1307
+ },
1308
+ 'info': order,
1309
+ }, market)
1310
+
1311
+ async def cancel_order(self, id: str, symbol: Str = None, params={}):
1312
+ """
1313
+
1314
+ https://api-docs.defx.com/#09186f23-f8d1-4993-acf4-9974d8a6ddb0
1315
+
1316
+ cancels an open order
1317
+ :param str id: order id
1318
+ :param str symbol: unified symbol of the market the order was made in
1319
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1320
+ :param boolean [params.stop]: whether the order is a stop/algo order
1321
+ :returns dict: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1322
+ """
1323
+ await self.load_markets()
1324
+ request: dict = {
1325
+ 'orderId': id,
1326
+ 'idType': 'orderId',
1327
+ }
1328
+ clientOrderId = self.safe_string_n(params, ['clOrdID', 'clientOrderId', 'client_order_id'])
1329
+ isByClientOrder = clientOrderId is not None
1330
+ if isByClientOrder:
1331
+ if symbol is None:
1332
+ raise ArgumentsRequired(self.id + ' cancelOrder() requires a symbol argument')
1333
+ market = self.market(symbol)
1334
+ request['orderId'] = clientOrderId
1335
+ request['idType'] = 'clientOrderId'
1336
+ request['symbol'] = market['id']
1337
+ params = self.omit(params, ['clOrdID', 'clientOrderId', 'client_order_id'])
1338
+ response = await self.v1PrivateDeleteApiOrderOrderId(self.extend(request, params))
1339
+ #
1340
+ # {
1341
+ # "success": True
1342
+ # }
1343
+ #
1344
+ extendParams: dict = {'symbol': symbol}
1345
+ if isByClientOrder:
1346
+ extendParams['clientOrderId'] = clientOrderId
1347
+ else:
1348
+ extendParams['id'] = id
1349
+ return self.extend(self.parse_order(response), extendParams)
1350
+
1351
+ async def cancel_all_orders(self, symbol: Str = None, params={}):
1352
+ """
1353
+ cancel all open orders
1354
+
1355
+ https://api-docs.defx.com/#db5531da-3692-4a53-841f-6ad6495f823a
1356
+
1357
+ :param str symbol: unified market symbol, only orders in the market of self symbol are cancelled when symbol is not None
1358
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1359
+ :returns dict[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
1360
+ """
1361
+ await self.load_markets()
1362
+ market = self.market(symbol)
1363
+ request: dict = {
1364
+ 'symbols': [market['id']],
1365
+ }
1366
+ response = await self.v1PrivateDeleteApiOrdersAllOpen(self.extend(request, params))
1367
+ #
1368
+ # {
1369
+ # "data": {
1370
+ # "msg": "The operation of cancel all open order is done."
1371
+ # }
1372
+ # }
1373
+ #
1374
+ return response
1375
+
1376
+ async def fetch_position(self, symbol: str, params={}):
1377
+ """
1378
+ fetch data on a single open contract trade position
1379
+
1380
+ https://api-docs.defx.com/#d89dbb86-9aba-4f59-ac5d-a97ff25ea80e
1381
+
1382
+ :param str symbol: unified market symbol of the market the position is held in, default is None
1383
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1384
+ :returns dict: a `position structure <https://docs.ccxt.com/#/?id=position-structure>`
1385
+ """
1386
+ if symbol is None:
1387
+ raise ArgumentsRequired(self.id + ' fetchPosition() requires a symbol argument')
1388
+ await self.load_markets()
1389
+ market = self.market(symbol)
1390
+ request: dict = {
1391
+ 'symbol': market['id'],
1392
+ }
1393
+ response = await self.v1PrivateGetApiPositionActive(self.extend(request, params))
1394
+ #
1395
+ # {
1396
+ # "data": [
1397
+ # {
1398
+ # "positionId": "0192c495-4a68-70ee-9081-9d368bd16dfc",
1399
+ # "symbol": "SOL_USDC",
1400
+ # "positionSide": "SHORT",
1401
+ # "entryPrice": "172.34300000",
1402
+ # "quantity": "0.80",
1403
+ # "marginAmount": "20.11561173",
1404
+ # "marginAsset": "USDC",
1405
+ # "pnl": "0.00000000"
1406
+ # }
1407
+ # ]
1408
+ # }
1409
+ #
1410
+ data = self.safe_list(response, 'data', [])
1411
+ first = self.safe_dict(data, 0, {})
1412
+ return self.parse_position(first, market)
1413
+
1414
+ async def fetch_positions(self, symbols: Strings = None, params={}):
1415
+ """
1416
+ fetch all open positions
1417
+
1418
+ https://api-docs.defx.com/#d89dbb86-9aba-4f59-ac5d-a97ff25ea80e
1419
+
1420
+ :param str[] [symbols]: list of unified market symbols
1421
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1422
+ :returns dict[]: a list of `position structure <https://docs.ccxt.com/#/?id=position-structure>`
1423
+ """
1424
+ await self.load_markets()
1425
+ response = await self.v1PrivateGetApiPositionActive(params)
1426
+ #
1427
+ # {
1428
+ # "data": [
1429
+ # {
1430
+ # "positionId": "0192c495-4a68-70ee-9081-9d368bd16dfc",
1431
+ # "symbol": "SOL_USDC",
1432
+ # "positionSide": "SHORT",
1433
+ # "entryPrice": "172.34300000",
1434
+ # "quantity": "0.80",
1435
+ # "marginAmount": "20.11561173",
1436
+ # "marginAsset": "USDC",
1437
+ # "pnl": "0.00000000"
1438
+ # }
1439
+ # ]
1440
+ # }
1441
+ #
1442
+ positions = self.safe_list(response, 'data', [])
1443
+ return self.parse_positions(positions, symbols)
1444
+
1445
+ def parse_position(self, position: dict, market: Market = None):
1446
+ #
1447
+ # {
1448
+ # "positionId": "0192c495-4a68-70ee-9081-9d368bd16dfc",
1449
+ # "symbol": "SOL_USDC",
1450
+ # "positionSide": "SHORT",
1451
+ # "entryPrice": "172.34300000",
1452
+ # "quantity": "0.80",
1453
+ # "marginAmount": "20.11561173",
1454
+ # "marginAsset": "USDC",
1455
+ # "pnl": "0.00000000"
1456
+ # }
1457
+ #
1458
+ marketId = self.safe_string(position, 'symbol')
1459
+ market = self.safe_market(marketId, market)
1460
+ size = Precise.string_abs(self.safe_string(position, 'quantity'))
1461
+ side = self.safe_string_lower(position, 'positionSide')
1462
+ unrealisedPnl = self.omit_zero(self.safe_string(position, 'pnl'))
1463
+ entryPrice = self.omit_zero(self.safe_string(position, 'entryPrice'))
1464
+ initialMargin = self.safe_string(position, 'marginAmount')
1465
+ return self.safe_position({
1466
+ 'info': position,
1467
+ 'id': self.safe_string(position, 'positionId'),
1468
+ 'symbol': market['symbol'],
1469
+ 'timestamp': None,
1470
+ 'datetime': None,
1471
+ 'lastUpdateTimestamp': None,
1472
+ 'initialMargin': self.parse_number(initialMargin),
1473
+ 'initialMarginPercentage': None,
1474
+ 'maintenanceMargin': None,
1475
+ 'maintenanceMarginPercentage': None,
1476
+ 'entryPrice': self.parse_number(entryPrice),
1477
+ 'notional': None,
1478
+ 'leverage': None,
1479
+ 'unrealizedPnl': self.parse_number(unrealisedPnl),
1480
+ 'realizedPnl': None,
1481
+ 'contracts': self.parse_number(size),
1482
+ 'contractSize': self.safe_number(market, 'contractSize'),
1483
+ 'marginRatio': None,
1484
+ 'liquidationPrice': None,
1485
+ 'markPrice': None,
1486
+ 'lastPrice': None,
1487
+ 'collateral': None,
1488
+ 'marginMode': None,
1489
+ 'side': side,
1490
+ 'percentage': None,
1491
+ 'stopLossPrice': None,
1492
+ 'takeProfitPrice': None,
1493
+ 'hedged': None,
1494
+ })
1495
+
1496
+ async def fetch_order(self, id: str, symbol: Str = None, params={}):
1497
+ """
1498
+ fetches information on an order made by the user
1499
+
1500
+ https://api-docs.defx.com/#44f82dd5-26b3-4e1f-b4aa-88ceddd65237
1501
+
1502
+ :param str id: the order id
1503
+ :param str symbol: unified symbol of the market the order was made in
1504
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1505
+ :returns dict: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1506
+ """
1507
+ await self.load_markets()
1508
+ request: dict = {
1509
+ 'orderId': id,
1510
+ 'idType': 'orderId',
1511
+ }
1512
+ clientOrderId = self.safe_string_n(params, ['clOrdID', 'clientOrderId', 'client_order_id'])
1513
+ params = self.omit(params, ['clOrdID', 'clientOrderId', 'client_order_id'])
1514
+ if clientOrderId is not None:
1515
+ if symbol is None:
1516
+ raise ArgumentsRequired(self.id + ' fetchOrder() requires a symbol argument')
1517
+ market = self.market(symbol)
1518
+ request['orderId'] = clientOrderId
1519
+ request['idType'] = 'clientOrderId'
1520
+ request['symbol'] = market['id']
1521
+ response = await self.v1PrivateGetApiOrderOrderId(self.extend(request, params))
1522
+ #
1523
+ # {
1524
+ # "success": True,
1525
+ # "data": {
1526
+ # "orderId": "555068654076559792",
1527
+ # "createdAt": "2024-05-08T05:45:42.148Z",
1528
+ # "updatedAt": "2024-05-08T05:45:42.166Z",
1529
+ # "clientOrderId": "dummyClientOrderId",
1530
+ # "reduceOnly": False,
1531
+ # "side": "SELL",
1532
+ # "status": "REJECTED",
1533
+ # "symbol": "BTC_USDC",
1534
+ # "timeInForce": "GTC",
1535
+ # "type": "TAKE_PROFIT_MARKET",
1536
+ # "origQty": "1.000",
1537
+ # "executedQty": "0.000",
1538
+ # "cumulativeQuote": "0.00",
1539
+ # "avgPrice": "0.00",
1540
+ # "stopPrice": "65000.00",
1541
+ # "totalPnL": "0.00",
1542
+ # "workingType": "MARK_PRICE",
1543
+ # "postOnly": False
1544
+ # }
1545
+ # }
1546
+ #
1547
+ data = self.safe_dict(response, 'data')
1548
+ return self.parse_order(data)
1549
+
1550
+ async def fetch_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
1551
+ """
1552
+ fetches information on multiple orders made by the user
1553
+
1554
+ https://api-docs.defx.com/#ab200038-8acb-4170-b05e-4fcb4cc13751
1555
+
1556
+ :param str symbol: unified market symbol
1557
+ :param int [since]: the earliest time in ms to fetch open orders for
1558
+ :param int [limit]: the maximum number of open order structures to retrieve
1559
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1560
+ :param int [params.until]: the latest time in ms to fetch orders for
1561
+ :returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
1562
+ """
1563
+ await self.load_markets()
1564
+ request: dict = {}
1565
+ if symbol is not None:
1566
+ market = self.market(symbol)
1567
+ request['symbols'] = market['id']
1568
+ until = self.safe_integer(params, 'until')
1569
+ if until is not None:
1570
+ params = self.omit(params, 'until')
1571
+ request['end'] = self.iso8601(until)
1572
+ if since is not None:
1573
+ request['start'] = self.iso8601(since)
1574
+ if limit is not None:
1575
+ maxLimit = 100
1576
+ limit = min(maxLimit, limit)
1577
+ request['pageSize'] = limit
1578
+ response = await self.v1PrivateGetApiOrders(self.extend(request, params))
1579
+ #
1580
+ # {
1581
+ # "data": [
1582
+ # {
1583
+ # "orderId": "746472647227344528",
1584
+ # "createdAt": "2024-10-25T16:49:31.077Z",
1585
+ # "updatedAt": "2024-10-25T16:49:31.378Z",
1586
+ # "clientOrderId": "0192c495-49c3-71ee-b3d3-7442a2090807",
1587
+ # "reduceOnly": False,
1588
+ # "side": "SELL",
1589
+ # "status": "FILLED",
1590
+ # "symbol": "SOL_USDC",
1591
+ # "timeInForce": "GTC",
1592
+ # "type": "MARKET",
1593
+ # "origQty": "0.80",
1594
+ # "executedQty": "0.80",
1595
+ # "cumulativeQuote": "137.87440000",
1596
+ # "avgPrice": "172.34300000",
1597
+ # "totalPnL": "0.00000000",
1598
+ # "totalFee": "0.07583092",
1599
+ # "workingType": null,
1600
+ # "postOnly": False,
1601
+ # "linkedOrderParentType": null,
1602
+ # "isTriggered": False,
1603
+ # "slippagePercentage": 5
1604
+ # }
1605
+ # ]
1606
+ # }
1607
+ #
1608
+ data = self.safe_list(response, 'data', [])
1609
+ return self.parse_orders(data, None, since, limit)
1610
+
1611
+ async def fetch_open_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
1612
+ """
1613
+ fetch all unfilled currently open orders
1614
+
1615
+ https://api-docs.defx.com/#ab200038-8acb-4170-b05e-4fcb4cc13751
1616
+
1617
+ :param str symbol: unified market symbol
1618
+ :param int [since]: the earliest time in ms to fetch open orders for
1619
+ :param int [limit]: the maximum number of open order structures to retrieve
1620
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1621
+ :param int [params.until]: the latest time in ms to fetch orders for
1622
+ :returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
1623
+ """
1624
+ params['statuses'] = 'OPEN'
1625
+ return await self.fetch_orders(symbol, since, limit, params)
1626
+
1627
+ async def fetch_closed_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
1628
+ """
1629
+ fetches information on multiple closed orders made by the user
1630
+
1631
+ https://api-docs.defx.com/#ab200038-8acb-4170-b05e-4fcb4cc13751
1632
+
1633
+ :param str symbol: unified market symbol
1634
+ :param int [since]: the earliest time in ms to fetch open orders for
1635
+ :param int [limit]: the maximum number of open order structures to retrieve
1636
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1637
+ :param int [params.until]: the latest time in ms to fetch orders for
1638
+ :returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
1639
+ """
1640
+ params['statuses'] = 'FILLED'
1641
+ return await self.fetch_orders(symbol, since, limit, params)
1642
+
1643
+ async def fetch_canceled_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
1644
+ """
1645
+ fetches information on multiple canceled orders made by the user
1646
+
1647
+ https://api-docs.defx.com/#ab200038-8acb-4170-b05e-4fcb4cc13751
1648
+
1649
+ :param str symbol: unified market symbol
1650
+ :param int [since]: the earliest time in ms to fetch open orders for
1651
+ :param int [limit]: the maximum number of open order structures to retrieve
1652
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1653
+ :param int [params.until]: the latest time in ms to fetch orders for
1654
+ :returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
1655
+ """
1656
+ params['statuses'] = 'CANCELED'
1657
+ return await self.fetch_orders(symbol, since, limit, params)
1658
+
1659
+ async def close_position(self, symbol: str, side: OrderSide = None, params={}) -> Order:
1660
+ """
1661
+ closes an open position for a market
1662
+
1663
+ https://api-docs.defx.com/#b2c08074-c4d9-4e50-b637-0d6c498fa29e
1664
+
1665
+ :param str symbol: unified CCXT market symbol
1666
+ :param str [side]: one-way mode: 'buy' or 'sell', hedge-mode: 'long' or 'short'
1667
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1668
+ :param str [params.positionId]: the position id you want to close
1669
+ :param str [params.type]: 'MARKET' or 'LIMIT'
1670
+ :param str [params.quantity]: how much of currency you want to trade in units of base currency
1671
+ :param str [params.price]: the price at which the order is to be fulfilled, in units of the quote currency, ignored in market orders
1672
+ :returns dict: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1673
+ """
1674
+ await self.load_markets()
1675
+ positionId = self.safe_string(params, 'positionId')
1676
+ if positionId is None:
1677
+ raise ArgumentsRequired(self.id + ' closePosition() requires a positionId')
1678
+ type = self.safe_string_upper(params, 'type')
1679
+ if type is None:
1680
+ raise ArgumentsRequired(self.id + ' closePosition() requires a type')
1681
+ quantity = self.safe_string(params, 'quantity')
1682
+ if quantity is None:
1683
+ raise ArgumentsRequired(self.id + ' closePosition() requires a quantity')
1684
+ request: dict = {
1685
+ 'positionId': positionId,
1686
+ 'type': type,
1687
+ 'quantity': quantity,
1688
+ }
1689
+ if type != 'MARKET':
1690
+ price = self.safe_string(params, 'price')
1691
+ if price is None:
1692
+ raise ArgumentsRequired(self.id + ' closePosition() requires a price')
1693
+ request['price'] = price
1694
+ params = self.omit(params, ['positionId', 'type', 'quantity', 'price'])
1695
+ response = await self.v1PrivateDeleteApiPositionPositionId(self.extend(request, params))
1696
+ #
1697
+ # {}
1698
+ #
1699
+ return response
1700
+
1701
+ async def close_all_positions(self, params={}) -> List[Position]:
1702
+ """
1703
+ closes all open positions for a market type
1704
+
1705
+ https://api-docs.defx.com/#d6f63b43-100e-47a9-998c-8b6c0c72d204
1706
+
1707
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1708
+ :returns dict[]: A list of `position structures <https://docs.ccxt.com/#/?id=position-structure>`
1709
+ """
1710
+ await self.load_markets()
1711
+ response = await self.v1PrivateDeleteApiPositionAll(params)
1712
+ #
1713
+ # {
1714
+ # "data": [
1715
+ # {
1716
+ # "positionId": "d6ca1a27-28ad-47ae-b244-0bda5ac37b2b",
1717
+ # "success": True
1718
+ # }
1719
+ # ]
1720
+ # }
1721
+ #
1722
+ data = self.safe_list(response, 'data', [])
1723
+ return self.parse_positions(data, None, params)
1724
+
1725
+ async def fetch_ledger(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[LedgerEntry]:
1726
+ """
1727
+ fetch the history of changes, actions done by the user or operations that altered the balance of the user
1728
+
1729
+ https://api-docs.defx.com/#38cc8974-794f-48c0-b959-db045a0ee565
1730
+
1731
+ :param str [code]: unified currency code
1732
+ :param int [since]: timestamp in ms of the earliest ledger entry
1733
+ :param int [limit]: max number of ledger entries to return
1734
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1735
+ :param int [params.until]: timestamp in ms of the latest ledger entry
1736
+ :param boolean [params.paginate]: default False, when True will automatically paginate by calling self endpoint multiple times. See in the docs all the [available parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
1737
+ :returns dict: a `ledger structure <https://docs.ccxt.com/#/?id=ledger-structure>`
1738
+ """
1739
+ await self.load_markets()
1740
+ paginate = False
1741
+ paginate, params = self.handle_option_and_params(params, 'fetchLedger', 'paginate')
1742
+ if paginate:
1743
+ return await self.fetch_paginated_call_dynamic('fetchLedger', code, since, limit, params)
1744
+ request: dict = {}
1745
+ if since is not None:
1746
+ request['start'] = since
1747
+ else:
1748
+ request['start'] = 0
1749
+ until = self.safe_integer(params, 'until')
1750
+ if until is not None:
1751
+ params = self.omit(params, 'until')
1752
+ request['end'] = until
1753
+ else:
1754
+ request['end'] = self.milliseconds()
1755
+ response = await self.v1PrivateGetApiWalletTransactions(self.extend(request, params))
1756
+ data = self.safe_list(response, 'transactions', [])
1757
+ return self.parse_ledger(data, None, since, limit)
1758
+
1759
+ def parse_ledger_entry(self, item: dict, currency: Currency = None) -> LedgerEntry:
1760
+ #
1761
+ # {
1762
+ # "id": "01JCSZS6H5VQND3GF5P98SJ29C",
1763
+ # "timestamp": 1731744012054,
1764
+ # "type": "FundingFee",
1765
+ # "amount": "0.02189287",
1766
+ # "asset": "USDC",
1767
+ # "operation": "CREDIT"
1768
+ # }
1769
+ #
1770
+ amount = self.safe_string(item, 'amount')
1771
+ currencyId = self.safe_string(item, 'asset')
1772
+ code = self.safe_currency_code(currencyId, currency)
1773
+ currency = self.safe_currency(currencyId, currency)
1774
+ timestamp = self.safe_integer(item, 'timestamp')
1775
+ type = self.safe_string(item, 'type')
1776
+ return self.safe_ledger_entry({
1777
+ 'info': item,
1778
+ 'id': self.safe_string(item, 'id'),
1779
+ 'direction': None,
1780
+ 'account': None,
1781
+ 'referenceAccount': None,
1782
+ 'referenceId': None,
1783
+ 'type': self.parse_ledger_entry_type(type),
1784
+ 'currency': code,
1785
+ 'amount': self.parse_number(amount),
1786
+ 'timestamp': timestamp,
1787
+ 'datetime': self.iso8601(timestamp),
1788
+ 'before': None,
1789
+ 'after': None,
1790
+ 'status': None,
1791
+ 'fee': None,
1792
+ }, currency)
1793
+
1794
+ def parse_ledger_entry_type(self, type):
1795
+ ledgerType: dict = {
1796
+ 'FundingFee': 'fee',
1797
+ 'FeeRebate': 'fee',
1798
+ 'FeeKickback': 'fee',
1799
+ 'RealizedPnl': 'trade',
1800
+ 'LiquidationClearance': 'trade',
1801
+ 'Transfer': 'transfer',
1802
+ 'ReferralPayout': 'referral',
1803
+ 'Commission': 'commission',
1804
+ }
1805
+ return self.safe_string(ledgerType, type, type)
1806
+
1807
+ async def withdraw(self, code: str, amount: float, address: str, tag=None, params={}):
1808
+ """
1809
+ make a withdrawal
1810
+
1811
+ https://api-docs.defx.com/#2600f503-63ed-4672-b8f6-69ea5f03203b
1812
+
1813
+ :param str code: unified currency code
1814
+ :param float amount: the amount to withdraw
1815
+ :param str address: the address to withdraw to
1816
+ :param str tag:
1817
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1818
+ :returns dict: a `transaction structure <https://docs.ccxt.com/#/?id=transaction-structure>`
1819
+ """
1820
+ await self.load_markets()
1821
+ currency = self.currency(code)
1822
+ request: dict = {
1823
+ 'amount': self.currency_to_precision(code, amount),
1824
+ 'asset': currency['id'],
1825
+ # 'network': 'ARB_SEPOLIA',
1826
+ # 'chainId': '421614',
1827
+ }
1828
+ response = await self.v1PrivatePostApiTransfersBridgeWithdrawal(self.extend(request, params))
1829
+ #
1830
+ # {
1831
+ # "transactionId": "0x301e5851e5aefa733abfbc8b30817ca3b61601e0ddf1df8c59656fb888b0bc9c"
1832
+ # }
1833
+ #
1834
+ return self.parse_transaction(response, currency)
1835
+
1836
+ def parse_transaction(self, transaction: dict, currency: Currency = None) -> Transaction:
1837
+ #
1838
+ # withdraw
1839
+ #
1840
+ # {
1841
+ # "transactionId": "0x301e5851e5aefa733abfbc8b30817ca3b61601e0ddf1df8c59656fb888b0bc9c"
1842
+ # }
1843
+ #
1844
+ txid = self.safe_string(transaction, 'transactionId')
1845
+ return {
1846
+ 'info': transaction,
1847
+ 'id': None,
1848
+ 'txid': txid,
1849
+ 'timestamp': None,
1850
+ 'datetime': None,
1851
+ 'network': None,
1852
+ 'address': None,
1853
+ 'addressTo': None,
1854
+ 'addressFrom': None,
1855
+ 'tag': None,
1856
+ 'tagTo': None,
1857
+ 'tagFrom': None,
1858
+ 'type': None,
1859
+ 'amount': None,
1860
+ 'currency': self.safe_currency_code(None, currency),
1861
+ 'status': None,
1862
+ 'updated': None,
1863
+ 'internal': None,
1864
+ 'comment': None,
1865
+ 'fee': None,
1866
+ }
1867
+
1868
+ async def set_leverage(self, leverage: Int, symbol: Str = None, params={}):
1869
+ """
1870
+ set the level of leverage for a market
1871
+
1872
+ https://api-docs.defx.com/#4cb4ecc4-6c61-4194-8353-be67faaf7ca7
1873
+
1874
+ :param float leverage: the rate of leverage
1875
+ :param str symbol: unified market symbol
1876
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1877
+ :returns dict: response from the exchange
1878
+ """
1879
+ if symbol is None:
1880
+ raise ArgumentsRequired(self.id + ' setLeverage() requires a symbol argument')
1881
+ await self.load_markets()
1882
+ request: dict = {
1883
+ 'leverage': self.number_to_string(leverage),
1884
+ }
1885
+ market = self.market(symbol)
1886
+ request['symbol'] = market['id']
1887
+ response = await self.v1PrivatePostApiUsersMetadataLeverage(self.extend(request, params))
1888
+ #
1889
+ # {
1890
+ # "success": True,
1891
+ # "data": {
1892
+ # "leverage": "11",
1893
+ # "symbol": "BTC_USDC"
1894
+ # }
1895
+ # }
1896
+ #
1897
+ data = self.safe_dict(response, 'data', {})
1898
+ return self.parse_leverage(data, market)
1899
+
1900
+ def parse_leverage(self, leverage: dict, market: Market = None) -> Leverage:
1901
+ #
1902
+ # "data": {
1903
+ # "leverage": "11",
1904
+ # "symbol": "BTC_USDC"
1905
+ # }
1906
+ #
1907
+ marketId = self.safe_string(leverage, 'symbol')
1908
+ leverageValue = self.safe_integer(leverage, 'leverage')
1909
+ return {
1910
+ 'info': leverage,
1911
+ 'symbol': self.safe_symbol(marketId, market),
1912
+ 'marginMode': None,
1913
+ 'longLeverage': leverageValue,
1914
+ 'shortLeverage': leverageValue,
1915
+ }
1916
+
1917
+ def nonce(self):
1918
+ return self.milliseconds()
1919
+
1920
+ def sign(self, path, section='public', method='GET', params={}, headers=None, body=None):
1921
+ version = section[0]
1922
+ access = section[1]
1923
+ pathWithParams = self.implode_params(path, params)
1924
+ url = self.implode_hostname(self.urls['api'][access])
1925
+ url += '/' + version + '/'
1926
+ params = self.omit(params, self.extract_params(path))
1927
+ params = self.keysort(params)
1928
+ if access == 'public':
1929
+ url += 'open/' + pathWithParams
1930
+ if params:
1931
+ url += '?' + self.rawencode(params)
1932
+ else:
1933
+ self.check_required_credentials()
1934
+ headers = {'X-DEFX-SOURCE': 'ccxt'}
1935
+ url += 'auth/' + pathWithParams
1936
+ nonce = str(self.milliseconds())
1937
+ payload = nonce
1938
+ if method == 'GET' or path == 'api/order/{orderId}':
1939
+ payload += self.rawencode(params)
1940
+ if params:
1941
+ url += '?' + self.rawencode(params)
1942
+ else:
1943
+ if params is not None:
1944
+ body = self.json(params)
1945
+ payload += body
1946
+ headers['Content-Type'] = 'application/json'
1947
+ signature = self.hmac(self.encode(payload), self.encode(self.secret), hashlib.sha256)
1948
+ headers['X-DEFX-APIKEY'] = self.apiKey
1949
+ headers['X-DEFX-TIMESTAMP'] = nonce
1950
+ headers['X-DEFX-SIGNATURE'] = signature
1951
+ return {'url': url, 'method': method, 'body': body, 'headers': headers}
1952
+
1953
+ def handle_errors(self, httpCode: int, reason: str, url: str, method: str, headers: dict, body: str, response, requestHeaders, requestBody):
1954
+ if not response:
1955
+ return None # fallback to default error handler
1956
+ # {"errorCode":404,"errorMessage":"Not Found"}
1957
+ # {"msg":"Missing auth signature","code":"missing_auth_signature"}
1958
+ # {"success":false,"err":{"msg":"Invalid order id","code":"invalid_order_id"}}
1959
+ success = self.safe_bool(response, 'success')
1960
+ err = self.safe_dict(response, 'err', response)
1961
+ errorCode = self.safe_string_2(err, 'errorCode', 'code')
1962
+ if not success:
1963
+ feedback = self.id + ' ' + self.json(response)
1964
+ self.throw_broadly_matched_exception(self.exceptions['broad'], body, feedback)
1965
+ self.throw_exactly_matched_exception(self.exceptions['exact'], errorCode, feedback)
1966
+ return None
1967
+
1968
+ def default_network_code_for_currency(self, code):
1969
+ currencyItem = self.currency(code)
1970
+ networks = currencyItem['networks']
1971
+ networkKeys = list(networks.keys())
1972
+ for i in range(0, len(networkKeys)):
1973
+ network = networkKeys[i]
1974
+ if network == 'ETH':
1975
+ return network
1976
+ # if it was not returned according to above options, then return the first network of currency
1977
+ return self.safe_value(networkKeys, 0)
1978
+
1979
+ def set_sandbox_mode(self, enable: bool):
1980
+ super(defx, self).set_sandbox_mode(enable)
1981
+ self.options['sandboxMode'] = enable