ccxt 4.4.77__py2.py3-none-any.whl → 4.4.78__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 (103) hide show
  1. ccxt/__init__.py +3 -3
  2. ccxt/abstract/apex.py +31 -0
  3. ccxt/apex.py +1884 -0
  4. ccxt/ascendex.py +2 -2
  5. ccxt/async_support/__init__.py +3 -3
  6. ccxt/async_support/apex.py +1884 -0
  7. ccxt/async_support/ascendex.py +2 -2
  8. ccxt/async_support/base/exchange.py +1 -1
  9. ccxt/async_support/binance.py +3 -3
  10. ccxt/async_support/bingx.py +1 -1
  11. ccxt/async_support/bitfinex.py +2 -2
  12. ccxt/async_support/bitflyer.py +2 -2
  13. ccxt/async_support/bitget.py +134 -64
  14. ccxt/async_support/bitmart.py +2 -2
  15. ccxt/async_support/bitmex.py +6 -6
  16. ccxt/async_support/cex.py +1 -1
  17. ccxt/async_support/coinbase.py +29 -4
  18. ccxt/async_support/coincatch.py +66 -0
  19. ccxt/async_support/coinex.py +1 -1
  20. ccxt/async_support/cryptocom.py +2 -2
  21. ccxt/async_support/defx.py +1 -1
  22. ccxt/async_support/delta.py +1 -1
  23. ccxt/async_support/deribit.py +2 -2
  24. ccxt/async_support/derive.py +2 -2
  25. ccxt/async_support/digifinex.py +2 -2
  26. ccxt/async_support/gate.py +1 -1
  27. ccxt/async_support/hitbtc.py +5 -2
  28. ccxt/async_support/htx.py +2 -2
  29. ccxt/async_support/hyperliquid.py +13 -6
  30. ccxt/async_support/kraken.py +2 -2
  31. ccxt/async_support/krakenfutures.py +2 -2
  32. ccxt/async_support/kucoinfutures.py +2 -2
  33. ccxt/async_support/mexc.py +50 -52
  34. ccxt/async_support/okx.py +1 -1
  35. ccxt/async_support/oxfun.py +2 -2
  36. ccxt/async_support/paradex.py +2 -2
  37. ccxt/async_support/phemex.py +4 -3
  38. ccxt/async_support/poloniex.py +3 -3
  39. ccxt/async_support/probit.py +1 -0
  40. ccxt/async_support/tradeogre.py +2 -1
  41. ccxt/async_support/upbit.py +201 -43
  42. ccxt/async_support/vertex.py +2 -2
  43. ccxt/async_support/whitebit.py +1 -0
  44. ccxt/async_support/woo.py +5 -3
  45. ccxt/async_support/woofipro.py +2 -2
  46. ccxt/async_support/xt.py +9 -2
  47. ccxt/base/errors.py +6 -0
  48. ccxt/base/exchange.py +69 -2
  49. ccxt/binance.py +3 -3
  50. ccxt/bingx.py +1 -1
  51. ccxt/bitfinex.py +2 -2
  52. ccxt/bitflyer.py +2 -2
  53. ccxt/bitget.py +134 -64
  54. ccxt/bitmart.py +2 -2
  55. ccxt/bitmex.py +6 -6
  56. ccxt/cex.py +1 -1
  57. ccxt/coinbase.py +29 -4
  58. ccxt/coincatch.py +66 -0
  59. ccxt/coinex.py +1 -1
  60. ccxt/cryptocom.py +2 -2
  61. ccxt/defx.py +1 -1
  62. ccxt/delta.py +1 -1
  63. ccxt/deribit.py +2 -2
  64. ccxt/derive.py +2 -2
  65. ccxt/digifinex.py +2 -2
  66. ccxt/gate.py +1 -1
  67. ccxt/hitbtc.py +5 -2
  68. ccxt/htx.py +2 -2
  69. ccxt/hyperliquid.py +13 -6
  70. ccxt/kraken.py +2 -2
  71. ccxt/krakenfutures.py +2 -2
  72. ccxt/kucoinfutures.py +2 -2
  73. ccxt/mexc.py +50 -52
  74. ccxt/okx.py +1 -1
  75. ccxt/oxfun.py +2 -2
  76. ccxt/paradex.py +2 -2
  77. ccxt/phemex.py +4 -3
  78. ccxt/poloniex.py +3 -3
  79. ccxt/pro/__init__.py +5 -1
  80. ccxt/pro/apex.py +984 -0
  81. ccxt/pro/coinbase.py +4 -6
  82. ccxt/pro/gate.py +22 -2
  83. ccxt/pro/hollaex.py +2 -2
  84. ccxt/pro/p2b.py +2 -2
  85. ccxt/pro/tradeogre.py +272 -0
  86. ccxt/probit.py +1 -0
  87. ccxt/test/tests_async.py +4 -0
  88. ccxt/test/tests_sync.py +4 -0
  89. ccxt/tradeogre.py +2 -1
  90. ccxt/upbit.py +201 -43
  91. ccxt/vertex.py +2 -2
  92. ccxt/whitebit.py +1 -0
  93. ccxt/woo.py +5 -3
  94. ccxt/woofipro.py +2 -2
  95. ccxt/xt.py +9 -2
  96. {ccxt-4.4.77.dist-info → ccxt-4.4.78.dist-info}/METADATA +4 -4
  97. {ccxt-4.4.77.dist-info → ccxt-4.4.78.dist-info}/RECORD +100 -98
  98. ccxt/abstract/ace.py +0 -15
  99. ccxt/ace.py +0 -1152
  100. ccxt/async_support/ace.py +0 -1152
  101. {ccxt-4.4.77.dist-info → ccxt-4.4.78.dist-info}/LICENSE.txt +0 -0
  102. {ccxt-4.4.77.dist-info → ccxt-4.4.78.dist-info}/WHEEL +0 -0
  103. {ccxt-4.4.77.dist-info → ccxt-4.4.78.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,1884 @@
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.apex import ImplicitAPI
8
+ import hashlib
9
+ import math
10
+ from ccxt.base.types import Account, Any, Balances, Currencies, Currency, Int, Market, Num, Order, OrderBook, OrderSide, OrderType, Position, Str, Strings, Ticker, Tickers, Trade, MarketInterface, TransferEntry
11
+ from typing import List
12
+ from ccxt.base.errors import ExchangeError
13
+ from ccxt.base.errors import ArgumentsRequired
14
+ from ccxt.base.errors import BadRequest
15
+ from ccxt.base.errors import InvalidOrder
16
+ from ccxt.base.errors import RateLimitExceeded
17
+ from ccxt.base.decimal_to_precision import TRUNCATE
18
+ from ccxt.base.decimal_to_precision import TICK_SIZE
19
+ from ccxt.base.precise import Precise
20
+
21
+
22
+ class apex(Exchange, ImplicitAPI):
23
+
24
+ def describe(self) -> Any:
25
+ return self.deep_extend(super(apex, self).describe(), {
26
+ 'id': 'apex',
27
+ 'name': 'Apex',
28
+ 'countries': [],
29
+ 'version': 'v3',
30
+ 'rateLimit': 20, # 600 requests per minute, 10 request per second
31
+ 'certified': False,
32
+ 'pro': True,
33
+ 'dex': True,
34
+ 'has': {
35
+ 'CORS': None,
36
+ 'spot': False,
37
+ 'margin': False,
38
+ 'swap': True,
39
+ 'future': False,
40
+ 'option': False,
41
+ 'addMargin': False,
42
+ 'borrowCrossMargin': False,
43
+ 'borrowIsolatedMargin': False,
44
+ 'cancelAllOrders': True,
45
+ 'cancelAllOrdersAfter': False,
46
+ 'cancelOrder': True,
47
+ 'cancelOrders': False,
48
+ 'cancelOrdersForSymbols': False,
49
+ 'closeAllPositions': False,
50
+ 'closePosition': False,
51
+ 'createMarketBuyOrderWithCost': False,
52
+ 'createMarketOrderWithCost': False,
53
+ 'createMarketSellOrderWithCost': False,
54
+ 'createOrder': True,
55
+ 'createOrders': False,
56
+ 'createPostOnlyOrder': True,
57
+ 'createReduceOnlyOrder': True,
58
+ 'createStopOrder': True,
59
+ 'createTriggerOrder': True,
60
+ 'editOrder': False,
61
+ 'fetchAccounts': True,
62
+ 'fetchBalance': True,
63
+ 'fetchBorrowInterest': False,
64
+ 'fetchBorrowRateHistories': False,
65
+ 'fetchBorrowRateHistory': False,
66
+ 'fetchCanceledAndClosedOrders': False,
67
+ 'fetchCanceledOrders': False,
68
+ 'fetchClosedOrders': False,
69
+ 'fetchCrossBorrowRate': False,
70
+ 'fetchCrossBorrowRates': False,
71
+ 'fetchCurrencies': True,
72
+ 'fetchDepositAddress': False,
73
+ 'fetchDepositAddresses': False,
74
+ 'fetchDeposits': False,
75
+ 'fetchDepositWithdrawFee': False,
76
+ 'fetchDepositWithdrawFees': False,
77
+ 'fetchFundingHistory': True,
78
+ 'fetchFundingRate': False,
79
+ 'fetchFundingRateHistory': True,
80
+ 'fetchFundingRates': False,
81
+ 'fetchIndexOHLCV': False,
82
+ 'fetchIsolatedBorrowRate': False,
83
+ 'fetchIsolatedBorrowRates': False,
84
+ 'fetchLedger': False,
85
+ 'fetchLeverage': False,
86
+ 'fetchLeverageTiers': False,
87
+ 'fetchLiquidations': False,
88
+ 'fetchMarginMode': False,
89
+ 'fetchMarketLeverageTiers': False,
90
+ 'fetchMarkets': True,
91
+ 'fetchMarkOHLCV': False,
92
+ 'fetchMyLiquidations': False,
93
+ 'fetchMyTrades': True,
94
+ 'fetchOHLCV': True,
95
+ 'fetchOpenInterest': True,
96
+ 'fetchOpenInterestHistory': False,
97
+ 'fetchOpenInterests': False,
98
+ 'fetchOpenOrders': True,
99
+ 'fetchOrder': True,
100
+ 'fetchOrderBook': True,
101
+ 'fetchOrders': True,
102
+ 'fetchOrderTrades': True,
103
+ 'fetchPosition': False,
104
+ 'fetchPositionMode': False,
105
+ 'fetchPositions': True,
106
+ 'fetchPositionsRisk': False,
107
+ 'fetchPremiumIndexOHLCV': False,
108
+ 'fetchTicker': True,
109
+ 'fetchTickers': True,
110
+ 'fetchTime': True,
111
+ 'fetchTrades': True,
112
+ 'fetchTradingFee': False,
113
+ 'fetchTradingFees': False,
114
+ 'fetchTransfer': True,
115
+ 'fetchTransfers': True,
116
+ 'fetchWithdrawal': False,
117
+ 'fetchWithdrawals': False,
118
+ 'reduceMargin': False,
119
+ 'repayCrossMargin': False,
120
+ 'repayIsolatedMargin': False,
121
+ 'sandbox': True,
122
+ 'setLeverage': True,
123
+ 'setMarginMode': False,
124
+ 'setPositionMode': False,
125
+ 'transfer': False,
126
+ 'withdraw': False,
127
+ },
128
+ 'timeframes': {
129
+ '1m': '1',
130
+ '5m': '5',
131
+ '15m': '15',
132
+ '30m': '30',
133
+ '1h': '60',
134
+ '2h': '120',
135
+ '4h': '240',
136
+ '6h': '360',
137
+ '12h': '720',
138
+ '1d': 'D',
139
+ '1w': 'W',
140
+ '1M': 'M',
141
+ },
142
+ 'hostname': 'omni.apex.exchange',
143
+ 'urls': {
144
+ 'logo': 'https://github.com/user-attachments/assets/fef8f2f7-4265-46aa-965e-33a91881cb00',
145
+ 'api': {
146
+ 'public': 'https://{hostname}/api',
147
+ 'private': 'https://{hostname}/api',
148
+ },
149
+ 'test': {
150
+ 'public': 'https://testnet.omni.apex.exchange/api',
151
+ 'private': 'https://testnet.omni.apex.exchange/api',
152
+ },
153
+ 'www': 'https://apex.exchange/',
154
+ 'doc': 'https://api-docs.pro.apex.exchange',
155
+ 'fees': 'https://apex-pro.gitbook.io/apex-pro/apex-omni-live-now/trading-perpetual-contracts/trading-fees',
156
+ 'referral': 'https://omni.apex.exchange/trade',
157
+ },
158
+ 'api': {
159
+ 'public': {
160
+ 'get': {
161
+ 'v3/symbols': 1,
162
+ 'v3/history-funding': 1,
163
+ 'v3/ticker': 1,
164
+ 'v3/klines': 1,
165
+ 'v3/trades': 1,
166
+ 'v3/depth': 1,
167
+ 'v3/time': 1,
168
+ 'v3/data/all-ticker-info': 1,
169
+ },
170
+ },
171
+ 'private': {
172
+ 'get': {
173
+ 'v3/account': 1,
174
+ 'v3/account-balance': 1,
175
+ 'v3/fills': 1,
176
+ 'v3/order-fills': 1,
177
+ 'v3/order': 1,
178
+ 'v3/history-orders': 1,
179
+ 'v3/order-by-client-order-id': 1,
180
+ 'v3/funding': 1,
181
+ 'v3/historical-pnl': 1,
182
+ 'v3/open-orders': 1,
183
+ 'v3/transfers': 1,
184
+ 'v3/transfer': 1,
185
+ },
186
+ 'post': {
187
+ 'v3/delete-open-orders': 1,
188
+ 'v3/delete-client-order-id': 1,
189
+ 'v3/delete-order': 1,
190
+ 'v3/order': 1,
191
+ 'v3/set-initial-margin-rate': 1,
192
+ 'v3/transfer-out': 1,
193
+ 'v3/contract-transfer-out': 1,
194
+ },
195
+ },
196
+ },
197
+ 'httpExceptions': {
198
+ '403': RateLimitExceeded, # Forbidden -- You request too many times
199
+ },
200
+ 'exceptions': {
201
+ # Uncodumented explanation of error strings:
202
+ # - oc_diff: order cost needed to place self order
203
+ # - new_oc: total order cost of open orders including the order you are trying to open
204
+ # - ob: order balance - the total cost of current open orders
205
+ # - ab: available balance
206
+ 'exact': {
207
+ '20006': 'apikey sign error', # apikey sign error
208
+ '20016': 'request para error', # apikey sign error
209
+ '10001': BadRequest,
210
+ },
211
+ 'broad': {
212
+ 'ORDER_PRICE_MUST_GREETER_ZERO': InvalidOrder,
213
+ 'ORDER_POSSIBLE_LEAD_TO_ACCOUNT_LIQUIDATED': InvalidOrder,
214
+ 'ORDER_WITH_THIS_PRICE_CANNOT_REDUCE_POSITION_ONLY': InvalidOrder,
215
+ },
216
+ },
217
+ 'fees': {
218
+ 'swap': {
219
+ 'taker': self.parse_number('0.0005'),
220
+ 'maker': self.parse_number('0.0002'),
221
+ },
222
+ },
223
+ 'requiredCredentials': {
224
+ 'apiKey': True,
225
+ 'secret': True,
226
+ 'walletAddress': False,
227
+ 'privateKey': False,
228
+ 'password': True,
229
+ },
230
+ 'precisionMode': TICK_SIZE,
231
+ 'commonCurrencies': {},
232
+ 'options': {
233
+ 'defaultType': 'swap',
234
+ 'defaultSlippage': 0.05,
235
+ 'brokerId': '6956',
236
+ },
237
+ 'features': {
238
+ 'default': {
239
+ 'sandbox': True,
240
+ 'createOrder': {
241
+ 'marginMode': False,
242
+ 'triggerPrice': True,
243
+ 'triggerPriceType': None,
244
+ 'triggerDirection': False,
245
+ 'stopLossPrice': False, # todo
246
+ 'takeProfitPrice': False, # todo
247
+ 'attachedStopLossTakeProfit': None,
248
+ 'timeInForce': {
249
+ 'IOC': True,
250
+ 'FOK': True,
251
+ 'PO': True,
252
+ 'GTD': True,
253
+ },
254
+ 'hedged': False,
255
+ 'selfTradePrevention': False,
256
+ 'trailing': True, # todo unify
257
+ 'leverage': False,
258
+ 'marketBuyByCost': False,
259
+ 'marketBuyRequiresPrice': False,
260
+ 'iceberg': False,
261
+ },
262
+ 'createOrders': None,
263
+ 'fetchMyTrades': {
264
+ 'marginMode': False,
265
+ 'limit': 500,
266
+ 'daysBack': 100000,
267
+ 'untilDays': 100000,
268
+ 'symbolRequired': False,
269
+ },
270
+ 'fetchOrder': {
271
+ 'marginMode': False,
272
+ 'trigger': False,
273
+ 'trailing': False,
274
+ 'symbolRequired': False,
275
+ },
276
+ 'fetchOpenOrders': {
277
+ 'marginMode': False,
278
+ 'limit': None,
279
+ 'trigger': False,
280
+ 'trailing': False,
281
+ 'symbolRequired': False,
282
+ },
283
+ 'fetchOrders': {
284
+ 'marginMode': False,
285
+ 'limit': 100,
286
+ 'daysBack': 100000,
287
+ 'untilDays': 100000,
288
+ 'trigger': False,
289
+ 'trailing': False,
290
+ 'symbolRequired': False,
291
+ },
292
+ 'fetchClosedOrders': None,
293
+ 'fetchOHLCV': {
294
+ 'limit': 200,
295
+ },
296
+ },
297
+ 'swap': {
298
+ 'linear': {
299
+ 'extends': 'default',
300
+ },
301
+ 'inverse': None,
302
+ },
303
+ },
304
+ })
305
+
306
+ async def fetch_time(self, params={}):
307
+ """
308
+ fetches the current integer timestamp in milliseconds from the exchange server
309
+
310
+ https://api-docs.pro.apex.exchange/#publicapi-v3-for-omni-get-system-time-v3
311
+
312
+ :param dict [params]: extra parameters specific to the exchange API endpoint
313
+ :returns int: the current integer timestamp in milliseconds from the exchange server
314
+ """
315
+ response = await self.publicGetV3Time(params)
316
+ data = self.safe_dict(response, 'data', {})
317
+ #
318
+ # {
319
+ # "data": {
320
+ # "time": 1738837534454
321
+ # }
322
+ # }
323
+ return self.safe_integer(data, 'time')
324
+
325
+ def parse_balance(self, response) -> Balances:
326
+ #
327
+ # {
328
+ # "totalEquityValue": "100.000000",
329
+ # "availableBalance": "100.000000",
330
+ # "initialMargin": "100.000000",
331
+ # "maintenanceMargin": "100.000000",
332
+ # "symbolToOraclePrice": {
333
+ # "BTC-USDC": {
334
+ # "oraclePrice": "20000",
335
+ # "createdTime": 124566
336
+ # }
337
+ # }
338
+ # }
339
+ #
340
+ timestamp = self.milliseconds()
341
+ result: dict = {
342
+ 'info': response,
343
+ 'timestamp': timestamp,
344
+ 'datetime': self.iso8601(timestamp),
345
+ }
346
+ code = 'USDT'
347
+ account = self.account()
348
+ account['free'] = self.safe_string(response, 'availableBalance')
349
+ account['total'] = self.safe_string(response, 'totalEquityValue')
350
+ result[code] = account
351
+ return self.safe_balance(result)
352
+
353
+ async def fetch_balance(self, params={}) -> Balances:
354
+ """
355
+ query for account info
356
+
357
+ https://api-docs.pro.apex.exchange/#privateapi-v3-for-omni-get-retrieve-user-account-balance
358
+
359
+ :param dict [params]: extra parameters specific to the exchange API endpoint
360
+ :returns dict: a `balance structure <https://docs.ccxt.com/#/?id=balance-structure>`
361
+ """
362
+ await self.load_markets()
363
+ response = await self.privateGetV3AccountBalance(params)
364
+ data = self.safe_dict(response, 'data', {})
365
+ return self.parse_balance(data)
366
+
367
+ def parse_account(self, account: dict) -> Account:
368
+ accountId = self.safe_string(account, 'id', '0')
369
+ return {
370
+ 'id': accountId,
371
+ 'type': None,
372
+ 'code': None,
373
+ 'info': account,
374
+ }
375
+
376
+ async def fetch_account(self, params={}) -> Account:
377
+ """
378
+ query for balance and get the amount of funds available for trading or funds locked in orders
379
+
380
+ https://api-docs.pro.apex.exchange/#privateapi-v3-for-omni-get-retrieve-user-account-data
381
+
382
+ :param dict [params]: extra parameters specific to the exchange API endpoint
383
+ :returns dict: a `balance structure <https://docs.ccxt.com/#/?id=balance-structure>`
384
+ """
385
+ await self.load_markets()
386
+ response = await self.privateGetV3Account(params)
387
+ data = self.safe_dict(response, 'data', {})
388
+ return self.parse_account(data)
389
+
390
+ async def fetch_currencies(self, params={}) -> Currencies:
391
+ """
392
+ fetches all available currencies on an exchange
393
+
394
+ https://api-docs.pro.apex.exchange/#publicapi-v3-for-omni-get-all-config-data-v3
395
+
396
+ :param dict [params]: extra parameters specific to the exchange API endpoint
397
+ :returns dict: an associative dictionary of currencies
398
+ """
399
+ response = await self.publicGetV3Symbols(params)
400
+ data = self.safe_dict(response, 'data', {})
401
+ spotConfig = self.safe_dict(data, 'spotConfig', {})
402
+ multiChain = self.safe_dict(spotConfig, 'multiChain', {})
403
+ # "spotConfig": {
404
+ # "assets": [
405
+ # {
406
+ # "tokenId": "141",
407
+ # "token": "USDT",
408
+ # "displayName": "Tether USD Coin",
409
+ # "decimals": 18,
410
+ # "showStep": "0.01",
411
+ # "iconUrl": "https://static-pro.apex.exchange/chains/chain_tokens/Ethereum/Ethereum_USDT.svg",
412
+ # "l2WithdrawFee": "0",
413
+ # "enableCollateral": True,
414
+ # "enableCrossCollateral": False,
415
+ # "crossCollateralDiscountRate": null,
416
+ # "isGray": False
417
+ # }
418
+ # ],
419
+ # "multiChain": {
420
+ # "chains": [
421
+ # {
422
+ # "chain": "Arbitrum One",
423
+ # "chainId": "9",
424
+ # "chainType": "0",
425
+ # "l1ChainId": "42161",
426
+ # "chainIconUrl": "https://static-pro.apex.exchange/chains/chain_logos/Arbitrum.svg",
427
+ # "contractAddress": "0x3169844a120c0f517b4eb4a750c08d8518c8466a",
428
+ # "swapContractAddress": "0x9e07b6Aef1bbD9E513fc2Eb8873e311E80B4f855",
429
+ # "stopDeposit": False,
430
+ # "feeLess": False,
431
+ # "gasLess": False,
432
+ # "gasToken": "ETH",
433
+ # "dynamicFee": True,
434
+ # "gasTokenDecimals": 18,
435
+ # "feeGasLimit": 300000,
436
+ # "blockTimeSeconds": 2,
437
+ # "rpcUrl": "https://arb.pro.apex.exchange",
438
+ # "minSwapUsdtAmount": "",
439
+ # "maxSwapUsdtAmount": "",
440
+ # "webRpcUrl": "https://arb.pro.apex.exchange",
441
+ # "webTxUrl": "https://arbiscan.io/tx/",
442
+ # "backupRpcUrl": "https://arb-mainnet.g.alchemy.com/v2/rGlYUbRHtUav5mfeThCPtsV9GLPt2Xq5",
443
+ # "txConfirm": 20,
444
+ # "withdrawGasFeeLess": False,
445
+ # "tokens": [
446
+ # {
447
+ # "decimals": 6,
448
+ # "iconUrl": "https://static-pro.apex.exchange/chains/chain_tokens/Arbitrum/Arbitrum_USDT.svg",
449
+ # "token": "USDT",
450
+ # "tokenAddress": "0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9",
451
+ # "pullOff": False,
452
+ # "withdrawEnable": True,
453
+ # "slippage": "",
454
+ # "isDefaultToken": False,
455
+ # "displayToken": "USDT",
456
+ # "needResetApproval": True,
457
+ # "minFee": "2",
458
+ # "maxFee": "40",
459
+ # "feeRate": "0.0001",
460
+ # "maxWithdraw": "",
461
+ # "minDeposit": "",
462
+ # "minWithdraw": "",
463
+ # "maxFastWithdrawAmount": "40000",
464
+ # "minFastWithdrawAmount": "1",
465
+ # "isGray": False
466
+ # },
467
+ # {
468
+ # "decimals": 6,
469
+ # "iconUrl": "https://static-pro.apex.exchange/chains/chain_tokens/Arbitrum/Arbitrum_USDC.svg",
470
+ # "token": "USDC",
471
+ # "tokenAddress": "0xaf88d065e77c8cc2239327c5edb3a432268e5831",
472
+ # "pullOff": False,
473
+ # "withdrawEnable": True,
474
+ # "slippage": "",
475
+ # "isDefaultToken": False,
476
+ # "displayToken": "USDC",
477
+ # "needResetApproval": True,
478
+ # "minFee": "2",
479
+ # "maxFee": "20",
480
+ # "feeRate": "0.0001",
481
+ # "maxWithdraw": "",
482
+ # "minDeposit": "",
483
+ # "minWithdraw": "",
484
+ # "maxFastWithdrawAmount": "1",
485
+ # "minFastWithdrawAmount": "1",
486
+ # "isGray": False
487
+ # }
488
+ # ]
489
+ # }
490
+ # ]
491
+ # }
492
+ rows = self.safe_list(spotConfig, 'assets', [])
493
+ chains = self.safe_list(multiChain, 'chains', [])
494
+ result: dict = {}
495
+ for i in range(0, len(rows)):
496
+ currency = rows[i]
497
+ currencyId = self.safe_string(currency, 'token')
498
+ code = self.safe_currency_code(currencyId)
499
+ name = self.safe_string(currency, 'displayName')
500
+ networks: dict = {}
501
+ minPrecision = None
502
+ minWithdrawFeeString = None
503
+ minWithdrawString = None
504
+ deposit = False
505
+ withdraw = False
506
+ for j in range(0, len(chains)):
507
+ chain = chains[j]
508
+ tokens = self.safe_list(chain, 'tokens', [])
509
+ for f in range(0, len(tokens)):
510
+ token = tokens[f]
511
+ tokenName = self.safe_string(token, 'token')
512
+ if tokenName == currencyId:
513
+ networkId = self.safe_string(chain, 'chainId')
514
+ networkCode = self.network_id_to_code(networkId)
515
+ precision = self.parse_number(self.parse_precision(self.safe_string(currency, 'decimals')))
516
+ minPrecision = precision if (minPrecision is None) else min(minPrecision, precision)
517
+ depositAllowed = not self.safe_bool(chain, 'stopDeposit')
518
+ deposit = depositAllowed if (depositAllowed) else deposit
519
+ withdrawAllowed = self.safe_bool(token, 'withdrawEnable')
520
+ withdraw = withdrawAllowed if (withdrawAllowed) else withdraw
521
+ minWithdrawFeeString = self.safe_string(token, 'minFee')
522
+ minWithdrawString = self.safe_string(token, 'minWithdraw')
523
+ minNetworkDepositString = self.safe_string(chain, 'depositMin')
524
+ networks[networkCode] = {
525
+ 'info': chain,
526
+ 'id': networkId,
527
+ 'network': networkCode,
528
+ 'active': depositAllowed and withdrawAllowed,
529
+ 'deposit': depositAllowed,
530
+ 'withdraw': withdrawAllowed,
531
+ 'fee': self.parse_number(minWithdrawFeeString),
532
+ 'precision': precision,
533
+ 'limits': {
534
+ 'withdraw': {
535
+ 'min': self.parse_number(minWithdrawString),
536
+ 'max': None,
537
+ },
538
+ 'deposit': {
539
+ 'min': self.parse_number(minNetworkDepositString),
540
+ 'max': None,
541
+ },
542
+ },
543
+ }
544
+ result[code] = {
545
+ 'info': currency,
546
+ 'code': code,
547
+ 'id': currencyId,
548
+ 'type': 'crypto',
549
+ 'name': name,
550
+ 'active': deposit and withdraw,
551
+ 'deposit': deposit,
552
+ 'withdraw': withdraw,
553
+ 'fee': self.parse_number(minWithdrawFeeString),
554
+ 'precision': minPrecision,
555
+ 'limits': {
556
+ 'amount': {
557
+ 'min': None,
558
+ 'max': None,
559
+ },
560
+ 'withdraw': {
561
+ 'min': self.parse_number(minWithdrawString),
562
+ 'max': None,
563
+ },
564
+ 'deposit': {
565
+ 'min': None,
566
+ 'max': None,
567
+ },
568
+ },
569
+ 'networks': networks,
570
+ }
571
+ return result
572
+
573
+ async def fetch_markets(self, params={}) -> List[Market]:
574
+ """
575
+ retrieves data on all markets for apex
576
+
577
+ https://api-docs.pro.apex.exchange/#publicapi-v3-for-omni-get-all-config-data-v3
578
+
579
+ :param dict [params]: extra parameters specific to the exchange API endpoint
580
+ :returns dict[]: an array of objects representing market data
581
+ """
582
+ response = await self.publicGetV3Symbols(params)
583
+ data = self.safe_dict(response, 'data', {})
584
+ contractConfig = self.safe_dict(data, 'contractConfig', {})
585
+ perpetualContract = self.safe_list(contractConfig, 'perpetualContract', [])
586
+ # {
587
+ # "perpetualContract":[
588
+ # {
589
+ # "baselinePositionValue": "50000.0000",
590
+ # "crossId": 30002,
591
+ # "crossSymbolId": 10,
592
+ # "crossSymbolName": "BTCUSDT",
593
+ # "digitMerge": "0.1,0.2,0.4,1,2",
594
+ # "displayMaxLeverage": "100",
595
+ # "displayMinLeverage": "1",
596
+ # "enableDisplay": True,
597
+ # "enableOpenPosition": True,
598
+ # "enableTrade": True,
599
+ # "fundingImpactMarginNotional": "6",
600
+ # "fundingInterestRate": "0.0003",
601
+ # "incrementalInitialMarginRate": "0.00250",
602
+ # "incrementalMaintenanceMarginRate": "0.00100",
603
+ # "incrementalPositionValue": "50000.0000",
604
+ # "initialMarginRate": "0.01",
605
+ # "maintenanceMarginRate": "0.005",
606
+ # "maxOrderSize": "50",
607
+ # "maxPositionSize": "100",
608
+ # "minOrderSize": "0.0010",
609
+ # "maxMarketPriceRange": "0.025",
610
+ # "settleAssetId": "USDT",
611
+ # "baseTokenId": "BTC",
612
+ # "stepSize": "0.001",
613
+ # "symbol": "BTC-USDT",
614
+ # "symbolDisplayName": "BTCUSDT",
615
+ # "tickSize": "0.1",
616
+ # "maxMaintenanceMarginRate": "0.5000",
617
+ # "maxPositionValue": "5000000.0000",
618
+ # "tagIconUrl": "https://static-pro.apex.exchange/icon/LABLE_HOT.svg",
619
+ # "tag": "HOT",
620
+ # "riskTip": False,
621
+ # "defaultInitialMarginRate": "0.05",
622
+ # "klineStartTime": 0,
623
+ # "maxMarketSizeBuffer": "0.98",
624
+ # "enableFundingSettlement": True,
625
+ # "indexPriceDecimals": 2,
626
+ # "indexPriceVarRate": "0.001",
627
+ # "openPositionOiLimitRate": "0.05",
628
+ # "fundingMaxRate": "0.000234",
629
+ # "fundingMinRate": "-0.000234",
630
+ # "fundingMaxValue": "",
631
+ # "enableFundingMxValue": True,
632
+ # "l2PairId": "50001",
633
+ # "settleTimeStamp": 0,
634
+ # "isPrelaunch": False,
635
+ # "riskLimitConfig": {},
636
+ # "category": "L1"
637
+ # }
638
+ # ]
639
+ # }
640
+ return self.parse_markets(perpetualContract)
641
+
642
+ def parse_market(self, market: dict) -> Market:
643
+ id = self.safe_string(market, 'symbol')
644
+ id2 = self.safe_string(market, 'crossSymbolName')
645
+ quoteId = self.safe_string(market, 'l2PairId')
646
+ baseId = self.safe_string(market, 'baseTokenId')
647
+ quote = self.safe_string(market, 'settleAssetId')
648
+ base = self.safe_currency_code(baseId)
649
+ settleId = self.safe_string(market, 'settleAssetId')
650
+ settle = self.safe_currency_code(settleId)
651
+ symbol = baseId + '/' + quote + ':' + settle
652
+ expiry = 0
653
+ takerFee = self.parse_number('0.0002')
654
+ makerFee = self.parse_number('0.0005')
655
+ return self.safe_market_structure({
656
+ 'id': id,
657
+ 'id2': id2,
658
+ 'symbol': symbol,
659
+ 'base': base,
660
+ 'quote': quote,
661
+ 'settle': settle,
662
+ 'baseId': baseId,
663
+ 'quoteId': quoteId,
664
+ 'settleId': settleId,
665
+ 'type': 'swap',
666
+ 'spot': False,
667
+ 'margin': None,
668
+ 'swap': True,
669
+ 'future': False,
670
+ 'option': False,
671
+ 'active': self.safe_bool(market, 'enableTrade'),
672
+ 'contract': True,
673
+ 'linear': True,
674
+ 'inverse': False,
675
+ 'taker': takerFee,
676
+ 'maker': makerFee,
677
+ 'contractSize': self.safe_number(market, 'minOrderSize'),
678
+ 'expiry': None if (expiry == 0) else expiry,
679
+ 'expiryDatetime': None if (expiry == 0) else self.iso8601(expiry),
680
+ 'strike': None,
681
+ 'optionType': None,
682
+ 'precision': {
683
+ 'amount': self.safe_number(market, 'stepSize'),
684
+ 'price': self.safe_number(market, 'tickSize'),
685
+ },
686
+ 'limits': {
687
+ 'leverage': {
688
+ 'min': self.safe_number(market, 'displayMinLeverage'),
689
+ 'max': self.safe_number(market, 'displayMaxLeverage'),
690
+ },
691
+ 'amount': {
692
+ 'min': self.safe_number(market, 'minOrderSize'),
693
+ 'max': self.safe_number(market, 'maxOrderSize'),
694
+ },
695
+ 'price': {
696
+ 'min': None,
697
+ 'max': None,
698
+ },
699
+ 'cost': {
700
+ 'min': None,
701
+ 'max': None,
702
+ },
703
+ },
704
+ 'created': None,
705
+ 'info': market,
706
+ })
707
+
708
+ def parse_ticker(self, ticker: dict, market: Market = None) -> Ticker:
709
+ #
710
+ # {
711
+ # "symbol": "BTCUSDT",
712
+ # "price24hPcnt": "0.450141",
713
+ # "lastPrice": "43511.50",
714
+ # "highPrice24h": "43513.50",
715
+ # "lowPrice24h": "29996.00",
716
+ # "markPrice": "43513.50",
717
+ # "indexPrice": "40828.94",
718
+ # "openInterest": "2036854775808",
719
+ # "turnover24h": "5626085.23749999",
720
+ # "volume24h": "169.317",
721
+ # "fundingRate": "0",
722
+ # "predictedFundingRate": "0",
723
+ # "nextFundingTime": "10:00:00",
724
+ # "tradeCount": 100
725
+ # }
726
+ #
727
+ timestamp = self.milliseconds()
728
+ marketId = self.safe_string(ticker, 'symbol')
729
+ market = self.safe_market(marketId, market)
730
+ symbol = self.safe_symbol(marketId, market)
731
+ last = self.safe_string(ticker, 'lastPrice')
732
+ percentage = self.safe_string(ticker, 'price24hPcnt')
733
+ quoteVolume = self.safe_string(ticker, 'turnover24h')
734
+ baseVolume = self.safe_string(ticker, 'volume24h')
735
+ high = self.safe_string(ticker, 'highPrice24h')
736
+ low = self.safe_string(ticker, 'lowPrice24h')
737
+ return self.safe_ticker({
738
+ 'symbol': symbol,
739
+ 'timestamp': timestamp,
740
+ 'datetime': self.iso8601(timestamp),
741
+ 'high': high,
742
+ 'low': low,
743
+ 'bid': None,
744
+ 'bidVolume': None,
745
+ 'ask': None,
746
+ 'askVolume': None,
747
+ 'vwap': None,
748
+ 'open': None,
749
+ 'close': last,
750
+ 'last': last,
751
+ 'previousClose': None,
752
+ 'change': None,
753
+ 'percentage': percentage,
754
+ 'average': None,
755
+ 'baseVolume': baseVolume,
756
+ 'quoteVolume': quoteVolume,
757
+ 'markPrice': self.safe_string(ticker, 'markPrice'),
758
+ 'indexPrice': self.safe_string(ticker, 'indexPrice'),
759
+ 'info': ticker,
760
+ }, market)
761
+
762
+ async def fetch_ticker(self, symbol: str, params={}) -> Ticker:
763
+ """
764
+ fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
765
+
766
+ https://api-docs.pro.apex.exchange/#publicapi-v3-for-omni-get-ticker-data-v3
767
+
768
+ :param str symbol: unified symbol of the market to fetch the ticker for
769
+ :param dict [params]: extra parameters specific to the exchange API endpoint
770
+ :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
771
+ """
772
+ await self.load_markets()
773
+ market = self.market(symbol)
774
+ request: dict = {
775
+ 'symbol': market['id2'],
776
+ }
777
+ response = await self.publicGetV3Ticker(self.extend(request, params))
778
+ tickers = self.safe_list(response, 'data', [])
779
+ rawTicker = self.safe_dict(tickers, 0, {})
780
+ return self.parse_ticker(rawTicker, market)
781
+
782
+ async def fetch_tickers(self, symbols: Strings = None, params={}) -> Tickers:
783
+ """
784
+ fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
785
+
786
+ https://api-docs.pro.apex.exchange/#publicapi-v3-for-omni-get-ticker-data-v3
787
+
788
+ :param str symbols: unified symbol of the market to fetch the ticker for
789
+ :param dict [params]: extra parameters specific to the exchange API endpoint
790
+ :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
791
+ """
792
+ await self.load_markets()
793
+ response = await self.publicGetV3DataAllTickerInfo(params)
794
+ tickers = self.safe_list(response, 'data', [])
795
+ return self.parse_tickers(tickers, symbols)
796
+
797
+ async def fetch_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}) -> List[list]:
798
+ """
799
+ fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
800
+
801
+ https://api-docs.pro.apex.exchange/#publicapi-v3-for-omni-get-candlestick-chart-data-v3
802
+
803
+ :param str symbol: unified symbol of the market to fetch OHLCV data for
804
+ :param str timeframe: the length of time each candle represents
805
+ :param int [since]: timestamp in ms of the earliest candle to fetch
806
+ :param int [limit]: the maximum amount of candles to fetch
807
+ :param dict [params]: extra parameters specific to the exchange API endpoint
808
+ :param int [params.until]: timestamp in ms of the latest candle to fetch
809
+ :returns int[][]: A list of candles ordered, open, high, low, close, volume
810
+ """
811
+ await self.load_markets()
812
+ market = self.market(symbol)
813
+ request: dict = {
814
+ 'interval': self.safe_string(self.timeframes, timeframe, timeframe),
815
+ 'symbol': market['id2'],
816
+ }
817
+ if limit is None:
818
+ limit = 200 # default is 200 when requested with `since`
819
+ request['limit'] = limit # max 200, default 200
820
+ request, params = self.handle_until_option('end', request, params)
821
+ if since is not None:
822
+ request['start'] = since
823
+ response = await self.publicGetV3Klines(self.extend(request, params))
824
+ data = self.safe_dict(response, 'data', {})
825
+ OHLCVs = self.safe_list(data, market['id2'], [])
826
+ return self.parse_ohlcvs(OHLCVs, market, timeframe, since, limit)
827
+
828
+ def parse_ohlcv(self, ohlcv, market: Market = None) -> list:
829
+ #
830
+ # {
831
+ # "start": 1647511440000,
832
+ # "symbol": "BTC-USD",
833
+ # "interval": "1",
834
+ # "low": "40000",
835
+ # "high": "45000",
836
+ # "open": "45000",
837
+ # "close": "40000",
838
+ # "volume": "1.002",
839
+ # "turnover": "3"
840
+ # } {"s":"BTCUSDT","i":"1","t":1741265880000,"c":"90235","h":"90235","l":"90156","o":"90156","v":"0.052","tr":"4690.4466"}
841
+ #
842
+ return [
843
+ self.safe_integer_n(ohlcv, ['start', 't']),
844
+ self.safe_number_n(ohlcv, ['open', 'o']),
845
+ self.safe_number_n(ohlcv, ['high', 'h']),
846
+ self.safe_number_n(ohlcv, ['low', 'l']),
847
+ self.safe_number_n(ohlcv, ['close', 'c']),
848
+ self.safe_number_n(ohlcv, ['volume', 'v']),
849
+ ]
850
+
851
+ async def fetch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook:
852
+ """
853
+ fetches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
854
+
855
+ https://api-docs.pro.apex.exchange/#publicapi-v3-for-omni-get-market-depth-v3
856
+
857
+ :param str symbol: unified symbol of the market to fetch the order book for
858
+ :param int [limit]: the maximum amount of order book entries to return
859
+ :param dict [params]: extra parameters specific to the exchange API endpoint
860
+ :returns dict: A dictionary of `order book structures <https://docs.ccxt.com/#/?id=order-book-structure>` indexed by market symbols
861
+ """
862
+ await self.load_markets()
863
+ market = self.market(symbol)
864
+ request: dict = {
865
+ 'symbol': market['id2'],
866
+ }
867
+ if limit is None:
868
+ limit = 100 # default is 200 when requested with `since`
869
+ request['limit'] = limit # max 100, default 100
870
+ response = await self.publicGetV3Depth(self.extend(request, params))
871
+ #
872
+ # {
873
+ # "a": [
874
+ # [
875
+ # "96576.3",
876
+ # "0.399"
877
+ # ],
878
+ # [
879
+ # "96577.6",
880
+ # "0.106"
881
+ # ]
882
+ # ],
883
+ # "b": [
884
+ # [
885
+ # "96565.2",
886
+ # "0.131"
887
+ # ],
888
+ # [
889
+ # "96565.1",
890
+ # "0.038"
891
+ # ]
892
+ # ],
893
+ # "s": "BTCUSDT",
894
+ # "u": 18665465
895
+ # }
896
+ #
897
+ data = self.safe_dict(response, 'data', {})
898
+ timestamp = self.milliseconds()
899
+ orderbook = self.parse_order_book(data, market['symbol'], timestamp, 'b', 'a')
900
+ orderbook['nonce'] = self.safe_integer(data, 'u')
901
+ return orderbook
902
+
903
+ async def fetch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
904
+ """
905
+ get the list of most recent trades for a particular symbol
906
+
907
+ https://api-docs.pro.apex.exchange/#publicapi-v3-for-omni-get-newest-trading-data-v3
908
+
909
+ :param str symbol: unified symbol of the market to fetch trades for
910
+ :param int [since]: timestamp in ms of the earliest trade to fetch
911
+ :param int [limit]: the maximum amount of trades to fetch
912
+ :param dict [params]: extra parameters specific to the exchange API endpoint
913
+ :param int [params.until]: the latest time in ms to fetch trades for
914
+ :param boolean [params.paginate]: default False, when True will automatically paginate by calling self endpoint multiple times
915
+ :returns Trade[]: a list of `trade structures <https://docs.ccxt.com/#/?id=public-trades>`
916
+ """
917
+ await self.load_markets()
918
+ market = self.market(symbol)
919
+ request: dict = {
920
+ 'symbol': market['id2'],
921
+ }
922
+ if limit is None:
923
+ limit = 500 # default is 50
924
+ request['limit'] = limit
925
+ response = await self.publicGetV3Trades(self.extend(request, params))
926
+ #
927
+ # [
928
+ # {
929
+ # "i": "993f7f85-9215-5723-9078-2186ae140847",
930
+ # "p": "96534.3",
931
+ # "S": "Sell",
932
+ # "v": "0.261",
933
+ # "s": "BTCUSDT",
934
+ # "T": 1739118072710
935
+ # },
936
+ # {
937
+ # "i": "c947c9cf-8c18-5784-89c3-91bdf86ddde8",
938
+ # "p": "96513.5",
939
+ # "S": "Sell",
940
+ # "v": "0.042",
941
+ # "s": "BTCUSDT",
942
+ # "T": 1739118075944
943
+ # }
944
+ # ]
945
+ #
946
+ trades = self.safe_list(response, 'data', [])
947
+ return self.parse_trades(trades, market, since, limit)
948
+
949
+ def parse_trade(self, trade: dict, market: Market = None) -> Trade:
950
+ #
951
+ # [
952
+ # {
953
+ # "i": "993f7f85-9215-5723-9078-2186ae140847",
954
+ # "p": "96534.3",
955
+ # "S": "Sell",
956
+ # "v": "0.261",
957
+ # "s": "BTCUSDT",
958
+ # "T": 1739118072710
959
+ # }
960
+ # ]
961
+ #
962
+ marketId = self.safe_string_n(trade, ['s', 'symbol'])
963
+ market = self.safe_market(marketId, market)
964
+ id = self.safe_string_n(trade, ['i', 'id'])
965
+ timestamp = self.safe_integer_n(trade, ['t', 'T', 'createdAt'])
966
+ priceString = self.safe_string_n(trade, ['p', 'price'])
967
+ amountString = self.safe_string_n(trade, ['v', 'size'])
968
+ side = self.safe_string_lower_n(trade, ['S', 'side'])
969
+ type = self.safe_string_n(trade, ['type'])
970
+ fee = self.safe_string_n(trade, ['fee'])
971
+ return self.safe_trade({
972
+ 'info': trade,
973
+ 'id': id,
974
+ 'order': None,
975
+ 'timestamp': timestamp,
976
+ 'datetime': self.iso8601(timestamp),
977
+ 'symbol': market['symbol'],
978
+ 'type': type,
979
+ 'takerOrMaker': None,
980
+ 'side': side,
981
+ 'price': priceString,
982
+ 'amount': amountString,
983
+ 'cost': None,
984
+ 'fee': fee,
985
+ }, market)
986
+
987
+ async def fetch_open_interest(self, symbol: str, params={}):
988
+ """
989
+ retrieves the open interest of a contract trading pair
990
+
991
+ https://api-docs.pro.apex.exchange/#publicapi-v3-for-omni-get-ticker-data-v3
992
+
993
+ :param str symbol: unified CCXT market symbol
994
+ :param dict [params]: exchange specific parameters
995
+ :returns dict} an open interest structure{@link https://docs.ccxt.com/#/?id=open-interest-structure:
996
+ """
997
+ await self.load_markets()
998
+ market = self.market(symbol)
999
+ request: dict = {
1000
+ 'symbol': market['id2'],
1001
+ }
1002
+ response = await self.publicGetV3Ticker(self.extend(request, params))
1003
+ tickers = self.safe_list(response, 'data', [])
1004
+ rawTicker = self.safe_dict(tickers, 0, {})
1005
+ return self.parse_open_interest(rawTicker, market)
1006
+
1007
+ def parse_open_interest(self, interest, market: Market = None):
1008
+ #
1009
+ # {
1010
+ # "symbol": "BTCUSDT",
1011
+ # "price24hPcnt": "0.450141",
1012
+ # "lastPrice": "43511.50",
1013
+ # "highPrice24h": "43513.50",
1014
+ # "lowPrice24h": "29996.00",
1015
+ # "markPrice": "43513.50",
1016
+ # "indexPrice": "40828.94",
1017
+ # "openInterest": "2036854775808",
1018
+ # "turnover24h": "5626085.23749999",
1019
+ # "volume24h": "169.317",
1020
+ # "fundingRate": "0",
1021
+ # "predictedFundingRate": "0",
1022
+ # "nextFundingTime": "10:00:00",
1023
+ # "tradeCount": 100
1024
+ # }
1025
+ #
1026
+ timestamp = self.milliseconds()
1027
+ marketId = self.safe_string(interest, 'symbol')
1028
+ market = self.safe_market(marketId, market)
1029
+ symbol = self.safe_symbol(marketId, market)
1030
+ return self.safe_open_interest({
1031
+ 'symbol': symbol,
1032
+ 'openInterestAmount': self.safe_string(interest, 'openInterest'),
1033
+ 'openInterestValue': None,
1034
+ 'timestamp': timestamp,
1035
+ 'datetime': self.iso8601(timestamp),
1036
+ 'info': interest,
1037
+ }, market)
1038
+
1039
+ async def fetch_funding_rate_history(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
1040
+ """
1041
+ fetches historical funding rate prices
1042
+
1043
+ https://api-docs.pro.apex.exchange/#publicapi-v3-for-omni-get-funding-rate-history-v3
1044
+
1045
+ :param str symbol: unified symbol of the market to fetch the funding rate history for
1046
+ :param int [since]: timestamp in ms of the earliest funding rate to fetch
1047
+ :param int [limit]: the maximum amount of `funding rate structures <https://docs.ccxt.com/#/?id=funding-rate-history-structure>` to fetch
1048
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1049
+ :param int [params.until]: timestamp in ms of the latest funding rate
1050
+ :param boolean [params.paginate]: default False, when True will automatically paginate by calling self endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
1051
+ :returns dict[]: a list of `funding rate structures <https://docs.ccxt.com/#/?id=funding-rate-history-structure>`
1052
+ """
1053
+ if symbol is None:
1054
+ raise ArgumentsRequired(self.id + ' fetchFundingRateHistory() requires a symbol argument')
1055
+ await self.load_markets()
1056
+ request: dict = {}
1057
+ market = self.market(symbol)
1058
+ request['symbol'] = market['id']
1059
+ if since is not None:
1060
+ request['beginTimeInclusive'] = since
1061
+ if limit is not None:
1062
+ request['limit'] = limit
1063
+ page = self.safe_integer(params, 'page')
1064
+ if page is not None:
1065
+ request['page'] = page
1066
+ endTimeExclusive = self.safe_integer_n(params, ['endTime', 'endTimeExclusive', 'until'])
1067
+ if endTimeExclusive is not None:
1068
+ request['endTimeExclusive'] = endTimeExclusive
1069
+ response = await self.publicGetV3HistoryFunding(self.extend(request, params))
1070
+ #
1071
+ # {
1072
+ # "historyFunds": [
1073
+ # {
1074
+ # "symbol": "BTC-USD",
1075
+ # "rate": "0.0000125000",
1076
+ # "price": "31297.5000008009374142",
1077
+ # "fundingTime": 12315555,
1078
+ # "fundingTimestamp": 12315555
1079
+ # }
1080
+ # ],
1081
+ # "totalSize": 11
1082
+ # }
1083
+ #
1084
+ rates = []
1085
+ data = self.safe_dict(response, 'data', {})
1086
+ resultList = self.safe_list(data, 'historyFunds', [])
1087
+ for i in range(0, len(resultList)):
1088
+ entry = resultList[i]
1089
+ timestamp = self.safe_integer(entry, 'fundingTimestamp')
1090
+ rates.append({
1091
+ 'info': entry,
1092
+ 'symbol': self.safe_string(entry, 'symbol'),
1093
+ 'fundingRate': self.safe_number(entry, 'rate'),
1094
+ 'timestamp': timestamp,
1095
+ 'datetime': self.iso8601(timestamp),
1096
+ })
1097
+ sorted = self.sort_by(rates, 'timestamp')
1098
+ return self.filter_by_symbol_since_limit(sorted, symbol, since, limit)
1099
+
1100
+ def parse_order(self, order: dict, market: Market = None) -> Order:
1101
+ #
1102
+ # {
1103
+ # "id": "1234",
1104
+ # "clientId": "1234",
1105
+ # "accountId": "12345",
1106
+ # "symbol": "BTC-USD",
1107
+ # "side": "SELL",
1108
+ # "price": "18000",
1109
+ # "limitFee": "100",
1110
+ # "fee": "100",
1111
+ # "triggerPrice": "1.2",
1112
+ # "trailingPercent": "0.12",
1113
+ # "size": "100",
1114
+ # "remainingSize": "100",
1115
+ # "type": "LIMIT",
1116
+ # "createdAt": 1647502440973,
1117
+ # "updatedTime": 1647502440973,
1118
+ # "expiresAt": 1647502440973,
1119
+ # "status": "PENDING",
1120
+ # "timeInForce": "GOOD_TIL_CANCEL",
1121
+ # "postOnly": False,
1122
+ # "reduceOnly": False,
1123
+ # "stopPnl": False,
1124
+ # "latestMatchFillPrice": "reason",
1125
+ # "cumMatchFillSize": "0.1",
1126
+ # "cumMatchFillValue": "1000",
1127
+ # "cumMatchFillFee": "1",
1128
+ # "cumSuccessFillSize": "0.1",
1129
+ # "cumSuccessFillValue": "1000",
1130
+ # "cumSuccessFillFee": "1",
1131
+ # "triggerPriceType": "INDEX",
1132
+ # "isOpenTpslOrder": True,
1133
+ # "isSetOpenTp": True,
1134
+ # "isSetOpenSl": False,
1135
+ # "openTpParam": {
1136
+ # "side": "SELL",
1137
+ # "price": "18000",
1138
+ # "limitFee": "100",
1139
+ # "clientOrderId": "111100",
1140
+ # "triggerPrice": "1.2",
1141
+ # "trailingPercent": "0.12",
1142
+ # "size": "100"
1143
+ # },
1144
+ # "openSlParam": {
1145
+ # "side": "SELL",
1146
+ # "price": "18000",
1147
+ # "limitFee": "100",
1148
+ # "clientOrderId": "111100",
1149
+ # "triggerPrice": "1.2",
1150
+ # "trailingPercent": "0.12",
1151
+ # "size": "100"
1152
+ # }
1153
+ # }
1154
+ #
1155
+ timestamp = self.safe_integer(order, 'createdAt')
1156
+ orderId = self.safe_string(order, 'id')
1157
+ clientOrderId = self.safe_string(order, 'clientId')
1158
+ marketId = self.safe_string(order, 'symbol')
1159
+ market = self.safe_market(marketId, market)
1160
+ symbol = market['symbol']
1161
+ price = self.safe_string(order, 'price')
1162
+ amount = self.safe_string(order, 'size')
1163
+ orderType = self.safe_string(order, 'type')
1164
+ status = self.safe_string(order, 'status')
1165
+ side = self.safe_string_lower(order, 'side')
1166
+ # average = self.omit_zero(self.safe_string(order, 'avg_fill_price'))
1167
+ remaining = self.omit_zero(self.safe_string(order, 'remainingSize'))
1168
+ lastUpdateTimestamp = self.safe_integer(order, 'updatedTime')
1169
+ return self.safe_order({
1170
+ 'id': orderId,
1171
+ 'clientOrderId': clientOrderId,
1172
+ 'timestamp': timestamp,
1173
+ 'datetime': self.iso8601(timestamp),
1174
+ 'lastTradeTimestamp': None,
1175
+ 'lastUpdateTimestamp': lastUpdateTimestamp,
1176
+ 'status': self.parse_order_status(status),
1177
+ 'symbol': symbol,
1178
+ 'type': self.parse_order_type(orderType),
1179
+ 'timeInForce': self.parse_time_in_force(self.safe_string(order, 'timeInForce')),
1180
+ 'postOnly': self.safe_bool(order, 'postOnly'),
1181
+ 'reduceOnly': self.safe_bool(order, 'reduceOnly'),
1182
+ 'side': side,
1183
+ 'price': price,
1184
+ 'triggerPrice': self.safe_string(order, 'triggerPrice'),
1185
+ 'takeProfitPrice': None,
1186
+ 'stopLossPrice': None,
1187
+ 'average': None,
1188
+ 'amount': amount,
1189
+ 'filled': None,
1190
+ 'remaining': remaining,
1191
+ 'cost': None,
1192
+ 'trades': None,
1193
+ 'fee': {
1194
+ 'cost': self.safe_string(order, 'fee'),
1195
+ 'currency': market['settleId'],
1196
+ },
1197
+ 'info': order,
1198
+ }, market)
1199
+
1200
+ def parse_time_in_force(self, timeInForce: Str):
1201
+ timeInForces: dict = {
1202
+ 'GOOD_TIL_CANCEL': 'GOOD_TIL_CANCEL',
1203
+ 'FILL_OR_KILL': 'FILL_OR_KILL',
1204
+ 'IMMEDIATE_OR_CANCEL': 'IMMEDIATE_OR_CANCEL',
1205
+ 'POST_ONLY': 'POST_ONLY',
1206
+ }
1207
+ return self.safe_string(timeInForces, timeInForce, None)
1208
+
1209
+ def parse_order_status(self, status: Str):
1210
+ if status is not None:
1211
+ statuses: dict = {
1212
+ 'PENDING': 'open',
1213
+ 'OPEN': 'open',
1214
+ 'FILLED': 'filled',
1215
+ 'CANCELING': 'canceled',
1216
+ 'CANCELED': 'canceled',
1217
+ 'UNTRIGGERED': 'open',
1218
+ }
1219
+ return self.safe_string(statuses, status, status)
1220
+ return status
1221
+
1222
+ def parse_order_type(self, type: Str):
1223
+ types: dict = {
1224
+ 'LIMIT': 'LIMIT',
1225
+ 'MARKET': 'MARKET',
1226
+ 'STOP_LIMIT': 'STOP_LIMIT',
1227
+ 'STOP_MARKET': 'STOP_MARKET',
1228
+ 'TAKE_PROFIT_LIMIT': 'TAKE_PROFIT_LIMIT',
1229
+ 'TAKE_PROFIT_MARKET': 'TAKE_PROFIT_MARKET',
1230
+ }
1231
+ return self.safe_string_upper(types, type, type)
1232
+
1233
+ def safe_market(self, marketId: Str = None, market: Market = None, delimiter: Str = None, marketType: Str = None) -> MarketInterface:
1234
+ if market is None and marketId is not None:
1235
+ if marketId in self.markets:
1236
+ market = self.markets[marketId]
1237
+ elif marketId in self.markets_by_id:
1238
+ market = self.markets_by_id[marketId]
1239
+ else:
1240
+ newMarketId = self.add_hyphen_before_usdt(marketId)
1241
+ if newMarketId in self.markets_by_id:
1242
+ markets = self.markets_by_id[newMarketId]
1243
+ numMarkets = len(markets)
1244
+ if numMarkets > 0:
1245
+ if self.markets_by_id[newMarketId][0]['id2'] == marketId:
1246
+ market = self.markets_by_id[newMarketId][0]
1247
+ return super(apex, self).safe_market(marketId, market, delimiter, marketType)
1248
+
1249
+ def generate_random_client_id_omni(self, _accountId: str):
1250
+ accountId = _accountId or str(self.rand_number(12))
1251
+ return 'apexomni-' + accountId + '-' + str(self.milliseconds()) + '-' + str(self.rand_number(6))
1252
+
1253
+ def add_hyphen_before_usdt(self, symbol: str):
1254
+ uppercaseSymbol = symbol.upper()
1255
+ index = uppercaseSymbol.find('USDT')
1256
+ symbolChar = self.safe_string(symbol, index - 1)
1257
+ if index > 0 and symbolChar != '-':
1258
+ return symbol[0:index] + '-' + symbol[index:]
1259
+ return symbol
1260
+
1261
+ def get_seeds(self):
1262
+ seeds = self.safe_string(self.options, 'seeds')
1263
+ if seeds is None:
1264
+ raise ArgumentsRequired(self.id + ' the "seeds" key is required in the options to access private endpoints. You can find it in API Management > Omni Key, and then set it.options["seeds"] = XXXX')
1265
+ return seeds
1266
+
1267
+ async def get_account_id(self):
1268
+ accountId = self.safe_string(self.options, 'accountId', '0')
1269
+ if accountId == '0':
1270
+ accountData = await self.fetch_account()
1271
+ self.options['accountId'] = self.safe_string(accountData, 'id', '0')
1272
+ return self.options['accountId']
1273
+
1274
+ async def create_order(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
1275
+ """
1276
+ create a trade order
1277
+
1278
+ https://api-docs.pro.apex.exchange/#privateapi-v3-for-omni-post-creating-orders
1279
+
1280
+ :param str symbol: unified symbol of the market to create an order in
1281
+ :param str type: 'market' or 'limit'
1282
+ :param str side: 'buy' or 'sell'
1283
+ :param float amount: how much of currency you want to trade in units of base currency
1284
+ :param float [price]: the price at which the order is to be fullfilled, in units of the quote currency, ignored in market orders
1285
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1286
+ :param float [params.triggerPrice]: The price a trigger order is triggered at
1287
+ :param str [params.timeInForce]: "GTC", "IOC", or "POST_ONLY"
1288
+ :param bool [params.postOnly]: True or False
1289
+ :param bool [params.reduceOnly]: Ensures that the executed order does not flip the opened position.
1290
+ :param str [params.clientOrderId]: a unique id for the order
1291
+ :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1292
+ """
1293
+ await self.load_markets()
1294
+ market = self.market(symbol)
1295
+ orderType = type.upper()
1296
+ orderSide = side.upper()
1297
+ orderSize = self.amount_to_precision(symbol, amount)
1298
+ orderPrice = '0'
1299
+ if price is not None:
1300
+ orderPrice = self.price_to_precision(symbol, price)
1301
+ fees = self.safe_dict(self.fees, 'swap', {})
1302
+ taker = self.safe_number(fees, 'taker', 0.0005)
1303
+ maker = self.safe_number(fees, 'maker', 0.0002)
1304
+ limitFee = self.decimal_to_precision(Precise.string_add(Precise.string_mul(Precise.string_mul(orderPrice, orderSize), str(taker)), str(market['precision']['price'])), TRUNCATE, market['precision']['price'], self.precisionMode, self.paddingMode)
1305
+ timeNow = self.milliseconds()
1306
+ # triggerPrice = self.safe_string_2(params, 'triggerPrice', 'stopPrice')
1307
+ isMarket = orderType == 'MARKET'
1308
+ if isMarket and (price is None):
1309
+ raise ArgumentsRequired(self.id + ' createOrder() requires a price argument for market orders')
1310
+ timeInForce = self.safe_string_upper(params, 'timeInForce')
1311
+ postOnly = self.is_post_only(isMarket, None, params)
1312
+ if timeInForce is None:
1313
+ timeInForce = 'GOOD_TIL_CANCEL'
1314
+ if not isMarket:
1315
+ if postOnly:
1316
+ timeInForce = 'POST_ONLY'
1317
+ elif timeInForce == 'ioc':
1318
+ timeInForce = 'IMMEDIATE_OR_CANCEL'
1319
+ params = self.omit(params, 'timeInForce')
1320
+ params = self.omit(params, 'postOnly')
1321
+ clientOrderId = self.safe_string_n(params, ['clientId', 'clientOrderId', 'client_order_id'])
1322
+ accountId = await self.get_account_id()
1323
+ if clientOrderId is None:
1324
+ clientOrderId = self.generate_random_client_id_omni(accountId)
1325
+ params = self.omit(params, ['clientId', 'clientOrderId', 'client_order_id'])
1326
+ orderToSign = {
1327
+ 'accountId': accountId,
1328
+ 'slotId': clientOrderId,
1329
+ 'nonce': clientOrderId,
1330
+ 'pairId': market['quoteId'],
1331
+ 'size': orderSize,
1332
+ 'price': orderPrice,
1333
+ 'direction': orderSide,
1334
+ 'makerFeeRate': str(maker),
1335
+ 'takerFeeRate': str(taker),
1336
+ }
1337
+ signature = await self.get_zk_contract_signature_obj(self.remove0x_prefix(self.get_seeds()), orderToSign)
1338
+ request: dict = {
1339
+ 'symbol': market['id'],
1340
+ 'side': orderSide,
1341
+ 'type': orderType, # LIMIT/MARKET/STOP_LIMIT/STOP_MARKET
1342
+ 'size': orderSize,
1343
+ 'price': orderPrice,
1344
+ 'limitFee': limitFee,
1345
+ 'expiration': int(math.floor(timeNow / 1000 + 30 * 24 * 60 * 60)),
1346
+ 'timeInForce': timeInForce,
1347
+ 'clientId': clientOrderId,
1348
+ 'brokerId': self.safe_string(self.options, 'brokerId', '6956'),
1349
+ }
1350
+ request['signature'] = signature
1351
+ response = await self.privatePostV3Order(self.extend(request, params))
1352
+ data = self.safe_dict(response, 'data', {})
1353
+ return self.parse_order(data, market)
1354
+
1355
+ async def transfer(self, code: str, amount: float, fromAccount: str, toAccount: str, params={}) -> TransferEntry:
1356
+ """
1357
+ transfer currency internally between wallets on the same account
1358
+ :param str code: unified currency code
1359
+ :param float amount: amount to transfer
1360
+ :param str fromAccount: account to transfer from
1361
+ :param str toAccount: account to transfer to
1362
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1363
+ :param str [params.transferId]: UUID, which is unique across the platform
1364
+ :returns dict: a `transfer structure <https://docs.ccxt.com/#/?id=transfer-structure>`
1365
+ """
1366
+ await self.load_markets()
1367
+ configResponse = await self.publicGetV3Symbols(params)
1368
+ configData = self.safe_dict(configResponse, 'data', {})
1369
+ contractConfig = self.safe_dict(configData, 'contractConfig', {})
1370
+ contractAssets = self.safe_list(contractConfig, 'assets', [])
1371
+ spotConfig = self.safe_dict(configData, 'spotConfig', {})
1372
+ spotAssets = self.safe_list(spotConfig, 'assets', [])
1373
+ globalConfig = self.safe_dict(spotConfig, 'global', {})
1374
+ receiverAddress = self.safe_string(globalConfig, 'contractAssetPoolEthAddress', '')
1375
+ receiverZkAccountId = self.safe_string(globalConfig, 'contractAssetPoolZkAccountId', '')
1376
+ receiverSubAccountId = self.safe_string(globalConfig, 'contractAssetPoolSubAccount', '')
1377
+ receiverAccountId = self.safe_string(globalConfig, 'contractAssetPoolAccountId', '')
1378
+ accountResponse = await self.privateGetV3Account(params)
1379
+ accountData = self.safe_dict(accountResponse, 'data', {})
1380
+ spotAccount = self.safe_dict(accountData, 'spotAccount', {})
1381
+ zkAccountId = self.safe_string(spotAccount, 'zkAccountId', '')
1382
+ subAccountId = self.safe_string(spotAccount, 'defaultSubAccountId', '0')
1383
+ subAccounts = self.safe_list(spotAccount, 'subAccounts', [])
1384
+ nonce = '0'
1385
+ if len(subAccounts) > 0:
1386
+ nonce = self.safe_string(subAccounts[0], 'nonce', '0')
1387
+ ethAddress = self.safe_string(accountData, 'ethereumAddress', '')
1388
+ accountId = self.safe_string(accountData, 'id', '')
1389
+ currency = {}
1390
+ assets = []
1391
+ if fromAccount is not None and fromAccount.lower() == 'contract':
1392
+ assets = contractAssets
1393
+ else:
1394
+ assets = spotAssets
1395
+ for i in range(0, len(assets)):
1396
+ if self.safe_string(assets[i], 'token', '') == code:
1397
+ currency = assets[i]
1398
+ tokenId = self.safe_string(currency, 'tokenId', '')
1399
+ amountNumber = self.parse_to_int(amount * (math.pow(10, self.safe_number(currency, 'decimals', 0))))
1400
+ timestampSeconds = self.parse_to_int(self.milliseconds() / 1000)
1401
+ clientOrderId = self.safe_string_n(params, ['clientId', 'clientOrderId', 'client_order_id'])
1402
+ if clientOrderId is None:
1403
+ clientOrderId = self.generate_random_client_id_omni(self.safe_string(self.options, 'accountId'))
1404
+ params = self.omit(params, ['clientId', 'clientOrderId', 'client_order_id'])
1405
+ if fromAccount is not None and fromAccount.lower() == 'contract':
1406
+ formattedUint32 = '4294967295'
1407
+ zkSignAccountId = Precise.string_mod(accountId, formattedUint32)
1408
+ expireTime = timestampSeconds + 3600 * 24 * 28
1409
+ orderToSign = {
1410
+ 'zkAccountId': zkSignAccountId,
1411
+ 'receiverAddress': ethAddress,
1412
+ 'subAccountId': subAccountId,
1413
+ 'receiverSubAccountId': subAccountId,
1414
+ 'tokenId': tokenId,
1415
+ 'amount': str(amountNumber),
1416
+ 'fee': '0',
1417
+ 'nonce': clientOrderId,
1418
+ 'timestampSeconds': expireTime,
1419
+ 'isContract': True,
1420
+ }
1421
+ signature = await self.get_zk_transfer_signature_obj(self.remove0x_prefix(self.get_seeds()), orderToSign)
1422
+ request: dict = {
1423
+ 'amount': amount,
1424
+ 'expireTime': expireTime,
1425
+ 'clientWithdrawId': clientOrderId,
1426
+ 'signature': signature,
1427
+ 'token': code,
1428
+ 'ethAddress': ethAddress,
1429
+ }
1430
+ response = await self.privatePostV3ContractTransferOut(self.extend(request, params))
1431
+ data = self.safe_dict(response, 'data', {})
1432
+ currentTime = self.milliseconds()
1433
+ return self.extend(self.parse_transfer(data, self.currency(code)), {
1434
+ 'timestamp': currentTime,
1435
+ 'datetime': self.iso8601(currentTime),
1436
+ 'amount': self.parse_number(amount),
1437
+ 'fromAccount': 'contract',
1438
+ 'toAccount': 'spot',
1439
+ })
1440
+ else:
1441
+ orderToSign = {
1442
+ 'zkAccountId': zkAccountId,
1443
+ 'receiverAddress': receiverAddress,
1444
+ 'subAccountId': subAccountId,
1445
+ 'receiverSubAccountId': receiverSubAccountId,
1446
+ 'tokenId': tokenId,
1447
+ 'amount': str(amountNumber),
1448
+ 'fee': '0',
1449
+ 'nonce': nonce,
1450
+ 'timestampSeconds': timestampSeconds,
1451
+ }
1452
+ signature = await self.get_zk_transfer_signature_obj(self.remove0x_prefix(self.get_seeds()), orderToSign)
1453
+ request: dict = {
1454
+ 'amount': str(amount),
1455
+ 'timestamp': timestampSeconds,
1456
+ 'clientTransferId': clientOrderId,
1457
+ 'signature': signature,
1458
+ 'zkAccountId': zkAccountId,
1459
+ 'subAccountId': subAccountId,
1460
+ 'fee': '0',
1461
+ 'token': code,
1462
+ 'tokenId': tokenId,
1463
+ 'receiverAccountId': receiverAccountId,
1464
+ 'receiverZkAccountId': receiverZkAccountId,
1465
+ 'receiverSubAccountId': receiverSubAccountId,
1466
+ 'receiverAddress': receiverAddress,
1467
+ 'nonce': nonce,
1468
+ }
1469
+ response = await self.privatePostV3TransferOut(self.extend(request, params))
1470
+ data = self.safe_dict(response, 'data', {})
1471
+ currentTime = self.milliseconds()
1472
+ return self.extend(self.parse_transfer(data, self.currency(code)), {
1473
+ 'timestamp': currentTime,
1474
+ 'datetime': self.iso8601(currentTime),
1475
+ 'amount': self.parse_number(amount),
1476
+ 'fromAccount': 'spot',
1477
+ 'toAccount': 'contract',
1478
+ })
1479
+
1480
+ def parse_transfer(self, transfer: dict, currency: Currency = None) -> TransferEntry:
1481
+ currencyId = self.safe_string(transfer, 'coin')
1482
+ timestamp = self.safe_integer(transfer, 'timestamp')
1483
+ fromAccount = self.safe_string(transfer, 'fromAccount')
1484
+ toAccount = self.safe_string(transfer, 'toAccount')
1485
+ return {
1486
+ 'info': transfer,
1487
+ 'id': self.safe_string_n(transfer, ['transferId', 'id']),
1488
+ 'timestamp': timestamp,
1489
+ 'datetime': self.iso8601(timestamp),
1490
+ 'currency': self.safe_currency_code(currencyId, currency),
1491
+ 'amount': self.safe_number(transfer, 'amount'),
1492
+ 'fromAccount': fromAccount,
1493
+ 'toAccount': toAccount,
1494
+ 'status': self.safe_string(transfer, 'status'),
1495
+ }
1496
+
1497
+ async def cancel_all_orders(self, symbol: Str = None, params={}):
1498
+ """
1499
+ cancel all open orders in a market
1500
+
1501
+ https://api-docs.pro.apex.exchange/#privateapi-v3-for-omni-post-cancel-all-open-orders
1502
+
1503
+ :param str symbol: unified market symbol of the market to cancel orders in
1504
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1505
+ :returns dict[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
1506
+ """
1507
+ await self.load_markets()
1508
+ market = None
1509
+ request: dict = {}
1510
+ if symbol is not None:
1511
+ market = self.market(symbol)
1512
+ request['symbol'] = market['id']
1513
+ response = await self.privatePostV3DeleteOpenOrders(self.extend(request, params))
1514
+ data = self.safe_dict(response, 'data', {})
1515
+ return data
1516
+
1517
+ async def cancel_order(self, id: str, symbol: Str = None, params={}):
1518
+ """
1519
+ cancels an open order
1520
+
1521
+ https://api-docs.pro.apex.exchange/#privateapi-v3-for-omni-post-cancel-order
1522
+
1523
+ :param str id: order id
1524
+ @param symbol
1525
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1526
+ :returns dict: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1527
+ """
1528
+ request: dict = {}
1529
+ clientOrderId = self.safe_string_n(params, ['clientId', 'clientOrderId', 'client_order_id'])
1530
+ response = None
1531
+ if clientOrderId is not None:
1532
+ request['id'] = clientOrderId
1533
+ params = self.omit(params, ['clientId', 'clientOrderId', 'client_order_id'])
1534
+ response = await self.privatePostV3DeleteClientOrderId(self.extend(request, params))
1535
+ else:
1536
+ request['id'] = id
1537
+ response = await self.privatePostV3DeleteOrder(self.extend(request, params))
1538
+ data = self.safe_dict(response, 'data', {})
1539
+ return data
1540
+
1541
+ async def fetch_order(self, id: str, symbol: Str = None, params={}):
1542
+ """
1543
+ fetches information on an order made by the user
1544
+
1545
+ https://api-docs.pro.apex.exchange/#privateapi-v3-for-omni-get-order-id
1546
+ https://api-docs.pro.apex.exchange/#privateapi-v3-for-omni-get-order-by-clientorderid
1547
+
1548
+ :param str id: the order id
1549
+ :param str symbol: unified symbol of the market the order was made in
1550
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1551
+ :param str [params.clientOrderId]: a unique id for the order
1552
+ :returns dict: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1553
+ """
1554
+ await self.load_markets()
1555
+ request: dict = {}
1556
+ clientOrderId = self.safe_string_n(params, ['clientId', 'clientOrderId', 'client_order_id'])
1557
+ response = None
1558
+ if clientOrderId is not None:
1559
+ request['id'] = clientOrderId
1560
+ params = self.omit(params, ['clientId', 'clientOrderId', 'client_order_id'])
1561
+ response = await self.privateGetV3OrderByClientOrderId(self.extend(request, params))
1562
+ else:
1563
+ request['id'] = id
1564
+ response = await self.privateGetV3Order(self.extend(request, params))
1565
+ data = self.safe_dict(response, 'data', {})
1566
+ return self.parse_order(data)
1567
+
1568
+ async def fetch_open_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
1569
+ """
1570
+ fetches information on multiple orders made by the user
1571
+
1572
+ https://api-docs.pro.apex.exchange/#privateapi-v3-for-omni-get-open-orders
1573
+
1574
+ :param str symbol: unified market symbol of the market orders were made in
1575
+ :param int [since]: the earliest time in ms to fetch orders for
1576
+ :param int [limit]: the maximum number of order structures to retrieve
1577
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1578
+ :returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
1579
+ """
1580
+ await self.load_markets()
1581
+ response = await self.privateGetV3OpenOrders(params)
1582
+ orders = self.safe_list(response, 'data', [])
1583
+ return self.parse_orders(orders, None, since, limit)
1584
+
1585
+ async def fetch_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
1586
+ """
1587
+ fetches information on multiple orders made by the user *classic accounts only*
1588
+
1589
+ https://api-docs.pro.apex.exchange/#privateapi-v3-for-omni-get-all-order-history
1590
+
1591
+ :param str symbol: unified market symbol of the market orders were made in
1592
+ :param int [since]: the earliest time in ms to fetch orders for
1593
+ :param int [limit]: the maximum number of order structures to retrieve, default 100
1594
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1595
+ :param dict [params.until]: end time, ms
1596
+ :param boolean [params.status]: "PENDING", "OPEN", "FILLED", "CANCELED", "EXPIRED", "UNTRIGGERED"
1597
+ :param boolean [params.side]: BUY or SELL
1598
+ :param str [params.type]: "LIMIT", "MARKET","STOP_LIMIT", "STOP_MARKET", "TAKE_PROFIT_LIMIT","TAKE_PROFIT_MARKET"
1599
+ :param str [params.orderType]: "ACTIVE","CONDITION","HISTORY"
1600
+ :param boolean [params.page]: Page numbers start from 0
1601
+ :returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
1602
+ """
1603
+ await self.load_markets()
1604
+ request: dict = {}
1605
+ market = None
1606
+ if symbol is not None:
1607
+ market = self.market(symbol)
1608
+ request['symbol'] = market['id']
1609
+ if since is not None:
1610
+ request['beginTimeInclusive'] = since
1611
+ if limit is not None:
1612
+ request['limit'] = limit
1613
+ endTimeExclusive = self.safe_integer_n(params, ['endTime', 'endTimeExclusive', 'until'])
1614
+ if endTimeExclusive is not None:
1615
+ request['endTimeExclusive'] = endTimeExclusive
1616
+ params = self.omit(params, ['endTime', 'endTimeExclusive', 'until'])
1617
+ response = await self.privateGetV3HistoryOrders(self.extend(request, params))
1618
+ data = self.safe_dict(response, 'data', {})
1619
+ orders = self.safe_list(data, 'orders', [])
1620
+ return self.parse_orders(orders, market, since, limit)
1621
+
1622
+ async def fetch_order_trades(self, id: str, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
1623
+ """
1624
+ fetch all the trades made from a single order
1625
+
1626
+ https://api-docs.pro.apex.exchange/#privateapi-v3-for-omni-get-trade-history
1627
+
1628
+ :param str id: order id
1629
+ :param str symbol: unified market symbol
1630
+ :param int [since]: the earliest time in ms to fetch trades for
1631
+ :param int [limit]: the maximum number of trades to retrieve
1632
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1633
+ :returns dict[]: a list of `trade structures <https://docs.ccxt.com/#/?id=trade-structure>`
1634
+ """
1635
+ await self.load_markets()
1636
+ request: dict = {}
1637
+ clientOrderId = self.safe_string_2(params, 'clientOrderId', 'clientId')
1638
+ if clientOrderId is not None:
1639
+ request['clientOrderId'] = clientOrderId
1640
+ else:
1641
+ request['orderId'] = id
1642
+ params = self.omit(params, ['clientOrderId', 'clientId'])
1643
+ response = await self.privateGetV3OrderFills(self.extend(request, params))
1644
+ data = self.safe_dict(response, 'data', {})
1645
+ orders = self.safe_list(data, 'orders', [])
1646
+ return self.parse_trades(orders, None, since, limit)
1647
+
1648
+ async def fetch_my_trades(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
1649
+ """
1650
+ fetches information on multiple orders made by the user *classic accounts only*
1651
+
1652
+ https://api-docs.pro.apex.exchange/#privateapi-v3-for-omni-get-trade-history
1653
+
1654
+ :param str symbol: unified market symbol of the market orders were made in
1655
+ :param int [since]: the earliest time in ms to fetch orders for
1656
+ :param int [limit]: the maximum number of order structures to retrieve, default 100
1657
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1658
+ :param dict [params.until]: end time
1659
+ :param boolean [params.side]: BUY or SELL
1660
+ :param str [params.orderType]: "LIMIT", "MARKET","STOP_LIMIT", "STOP_MARKET", "TAKE_PROFIT_LIMIT","TAKE_PROFIT_MARKET"
1661
+ :param boolean [params.page]: Page numbers start from 0
1662
+ :returns Trade[]: a list of `trade structures <https://docs.ccxt.com/#/?id=trade-structure>`
1663
+ """
1664
+ await self.load_markets()
1665
+ request: dict = {}
1666
+ market = None
1667
+ if symbol is not None:
1668
+ market = self.market(symbol)
1669
+ request['symbol'] = market['id']
1670
+ if since is not None:
1671
+ request['beginTimeInclusive'] = since
1672
+ if limit is not None:
1673
+ request['limit'] = limit
1674
+ endTimeExclusive = self.safe_integer_n(params, ['endTime', 'endTimeExclusive', 'until'])
1675
+ if endTimeExclusive is not None:
1676
+ request['endTimeExclusive'] = endTimeExclusive
1677
+ params = self.omit(params, ['endTime', 'endTimeExclusive', 'until'])
1678
+ response = await self.privateGetV3Fills(self.extend(request, params))
1679
+ data = self.safe_dict(response, 'data', {})
1680
+ orders = self.safe_list(data, 'orders', [])
1681
+ return self.parse_trades(orders, market, since, limit)
1682
+
1683
+ async def fetch_funding_history(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
1684
+ """
1685
+ fetches information on multiple orders made by the user *classic accounts only*
1686
+
1687
+ https://api-docs.pro.apex.exchange/#privateapi-v3-for-omni-get-funding-rate
1688
+
1689
+ :param str symbol: unified market symbol of the market orders were made in
1690
+ :param int [since]: the earliest time in ms to fetch orders for
1691
+ :param int [limit]: the maximum number of order structures to retrieve, default 100
1692
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1693
+ :param dict [params.until]: end time, ms
1694
+ :param boolean [params.side]: BUY or SELL
1695
+ :param boolean [params.page]: Page numbers start from 0
1696
+ :returns Trade[]: a list of `trade structures <https://docs.ccxt.com/#/?id=funding-history-structure>`
1697
+ """
1698
+ await self.load_markets()
1699
+ request: dict = {}
1700
+ market = None
1701
+ if symbol is not None:
1702
+ market = self.market(symbol)
1703
+ request['symbol'] = market['id']
1704
+ if since is not None:
1705
+ request['beginTimeInclusive'] = since
1706
+ if limit is not None:
1707
+ request['limit'] = limit
1708
+ endTimeExclusive = self.safe_integer_n(params, ['endTime', 'endTimeExclusive', 'until'])
1709
+ if endTimeExclusive is not None:
1710
+ params = self.omit(params, ['endTime', 'endTimeExclusive', 'until'])
1711
+ request['endTimeExclusive'] = endTimeExclusive
1712
+ response = await self.privateGetV3Funding(self.extend(request, params))
1713
+ data = self.safe_dict(response, 'data', {})
1714
+ fundingValues = self.safe_list(data, 'fundingValues', [])
1715
+ return self.parse_incomes(fundingValues, market, since, limit)
1716
+
1717
+ def parse_income(self, income, market: Market = None):
1718
+ #
1719
+ # {
1720
+ # "id": "1234",
1721
+ # "symbol": "BTC-USDT",
1722
+ # "fundingValue": "10000",
1723
+ # "rate": "0.0000125000",
1724
+ # "positionSize": "500",
1725
+ # "price": "90",
1726
+ # "side": "LONG",
1727
+ # "status": "SUCCESS",
1728
+ # "fundingTime": 1647502440973,
1729
+ # "transactionId": "1234556"
1730
+ # }
1731
+ #
1732
+ marketId = self.safe_string(income, 'symbol')
1733
+ market = self.safe_market(marketId, market, None, 'contract')
1734
+ code = 'USDT'
1735
+ timestamp = self.safe_integer(income, 'fundingTime')
1736
+ return {
1737
+ 'info': income,
1738
+ 'symbol': self.safe_symbol(marketId, market),
1739
+ 'code': code,
1740
+ 'timestamp': timestamp,
1741
+ 'datetime': self.iso8601(timestamp),
1742
+ 'id': self.safe_string(income, 'id'),
1743
+ 'amount': self.safe_number(income, 'fundingValue'),
1744
+ 'rate': self.safe_number(income, 'rate'),
1745
+ }
1746
+
1747
+ async def set_leverage(self, leverage: Int, symbol: Str = None, params={}):
1748
+ """
1749
+ set the level of leverage for a market
1750
+
1751
+ https://api-docs.pro.apex.exchange/#privateapi-v3-for-omni-post-sets-the-initial-margin-rate-of-a-contract
1752
+
1753
+ :param float leverage: the rate of leverage
1754
+ :param str symbol: unified market symbol
1755
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1756
+ :returns dict: response from the exchange
1757
+ """
1758
+ if symbol is None:
1759
+ raise ArgumentsRequired(self.id + ' setLeverage() requires a symbol argument')
1760
+ await self.load_markets()
1761
+ market = self.market(symbol)
1762
+ leverageString = self.number_to_string(leverage)
1763
+ initialMarginRate = Precise.string_div('1', leverageString, 4)
1764
+ request: dict = {
1765
+ 'symbol': market['id'],
1766
+ 'initialMarginRate': initialMarginRate,
1767
+ }
1768
+ response = await self.privatePostV3SetInitialMarginRate(self.extend(request, params))
1769
+ data = self.safe_dict(response, 'data', {})
1770
+ return data
1771
+
1772
+ async def fetch_positions(self, symbols: Strings = None, params={}) -> List[Position]:
1773
+ """
1774
+ fetch all open positions
1775
+
1776
+ https://api-docs.pro.apex.exchange/#privateapi-v3-for-omni-get-retrieve-user-account-data
1777
+
1778
+ :param str[] [symbols]: list of unified market symbols
1779
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1780
+ :returns dict[]: a list of `position structure <https://docs.ccxt.com/#/?id=position-structure>`
1781
+ """
1782
+ await self.load_markets()
1783
+ response = await self.privateGetV3Account(params)
1784
+ data = self.safe_dict(response, 'data', {})
1785
+ positions = self.safe_list(data, 'positions', [])
1786
+ return self.parse_positions(positions, symbols)
1787
+
1788
+ def parse_position(self, position: dict, market: Market = None):
1789
+ #
1790
+ # {
1791
+ # "symbol": "BTC-USDT",
1792
+ # "status": "",
1793
+ # "side": "LONG",
1794
+ # "size": "0.000",
1795
+ # "entryPrice": "0.00",
1796
+ # "exitPrice": "",
1797
+ # "createdAt": 1690366452416,
1798
+ # "updatedTime": 1690366452416,
1799
+ # "fee": "0.000000",
1800
+ # "fundingFee": "0.000000",
1801
+ # "lightNumbers": "",
1802
+ # "customInitialMarginRate": "0"
1803
+ # }
1804
+ marketId = self.safe_string(position, 'symbol')
1805
+ market = self.safe_market(marketId, market)
1806
+ symbol = market['symbol']
1807
+ side = self.safe_string_lower(position, 'side')
1808
+ quantity = self.safe_string(position, 'size')
1809
+ timestamp = self.safe_integer(position, 'updatedTime')
1810
+ leverage = 20
1811
+ customInitialMarginRate = self.safe_string_n(position, ['customInitialMarginRate', 'customImr'], '0')
1812
+ if self.precision_from_string(customInitialMarginRate) != 0:
1813
+ leverage = self.parse_to_int(Precise.string_div('1', customInitialMarginRate, 4))
1814
+ return self.safe_position({
1815
+ 'info': position,
1816
+ 'id': self.safe_string(position, 'id'),
1817
+ 'symbol': symbol,
1818
+ 'entryPrice': self.safe_string(position, 'entryPrice'),
1819
+ 'markPrice': None,
1820
+ 'notional': None,
1821
+ 'collateral': None,
1822
+ 'unrealizedPnl': None,
1823
+ 'side': side,
1824
+ 'contracts': self.parse_number(quantity),
1825
+ 'contractSize': None,
1826
+ 'timestamp': timestamp,
1827
+ 'datetime': self.iso8601(timestamp),
1828
+ 'hedged': None,
1829
+ 'maintenanceMargin': None,
1830
+ 'maintenanceMarginPercentage': None,
1831
+ 'initialMargin': None,
1832
+ 'initialMarginPercentage': None,
1833
+ 'leverage': leverage,
1834
+ 'liquidationPrice': None,
1835
+ 'marginRatio': None,
1836
+ 'marginMode': None,
1837
+ 'percentage': None,
1838
+ })
1839
+
1840
+ def sign(self, path, api='public', method='GET', params={}, headers=None, body=None):
1841
+ url = self.implode_hostname(self.urls['api'][api]) + '/' + path
1842
+ headers = {
1843
+ 'User-Agent': 'apex-CCXT',
1844
+ 'Accept': 'application/json',
1845
+ 'Content-Type': 'application/x-www-form-urlencoded',
1846
+ }
1847
+ signPath = '/api/' + path
1848
+ signBody = body
1849
+ if method.upper() != 'POST':
1850
+ if params:
1851
+ signPath += '?' + self.rawencode(params)
1852
+ url += '?' + self.rawencode(params)
1853
+ else:
1854
+ sortedQuery = self.keysort(params)
1855
+ signBody = self.rawencode(sortedQuery)
1856
+ if api == 'private':
1857
+ self.check_required_credentials()
1858
+ timestamp = str(self.milliseconds())
1859
+ messageString = timestamp + method.upper() + signPath
1860
+ if signBody is not None:
1861
+ messageString = messageString + signBody
1862
+ signature = self.hmac(self.encode(messageString), self.encode(self.string_to_base64(self.secret)), hashlib.sha256, 'base64')
1863
+ headers['APEX-SIGNATURE'] = signature
1864
+ headers['APEX-API-KEY'] = self.apiKey
1865
+ headers['APEX-TIMESTAMP'] = timestamp
1866
+ headers['APEX-PASSPHRASE'] = self.password
1867
+ return {'url': url, 'method': method, 'body': signBody, 'headers': headers}
1868
+
1869
+ def handle_errors(self, code: int, reason: str, url: str, method: str, headers: dict, body: str, response, requestHeaders, requestBody):
1870
+ #
1871
+ # {"code":3,"msg":"Order price must be greater than 0. Order price is 0.","key":"ORDER_PRICE_MUST_GREETER_ZERO","detail":{"price":"0"}}
1872
+ # {"code":400,"msg":"strconv.ParseInt: parsing \"dsfdfsd\": invalid syntax","timeCost":5320995}
1873
+ #
1874
+ if response is None:
1875
+ return None
1876
+ errorCode = self.safe_integer(response, 'code')
1877
+ if errorCode is not None and errorCode != 0:
1878
+ feedback = self.id + ' ' + body
1879
+ message = self.safe_string_2(response, 'key', 'msg')
1880
+ self.throw_broadly_matched_exception(self.exceptions['broad'], message, feedback)
1881
+ status = str(code)
1882
+ self.throw_exactly_matched_exception(self.exceptions['exact'], status, feedback)
1883
+ raise ExchangeError(feedback)
1884
+ return None