ccxt 3.1.60__py2.py3-none-any.whl → 4.0.3__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.
ccxt/async_support/xt.py DELETED
@@ -1,4420 +0,0 @@
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.xt import ImplicitAPI
8
- import asyncio
9
- import hashlib
10
- from typing import Optional
11
- from typing import List
12
- from ccxt.base.errors import ExchangeError
13
- from ccxt.base.errors import PermissionDenied
14
- from ccxt.base.errors import BadRequest
15
- from ccxt.base.errors import BadSymbol
16
- from ccxt.base.errors import InsufficientFunds
17
- from ccxt.base.errors import InvalidOrder
18
- from ccxt.base.errors import NotSupported
19
- from ccxt.base.errors import NetworkError
20
- from ccxt.base.errors import RateLimitExceeded
21
- from ccxt.base.errors import OnMaintenance
22
- from ccxt.base.errors import RequestTimeout
23
- from ccxt.base.errors import AuthenticationError
24
- from ccxt.base.decimal_to_precision import TICK_SIZE
25
- from ccxt.base.precise import Precise
26
-
27
-
28
- class xt(Exchange, ImplicitAPI):
29
-
30
- def describe(self):
31
- return self.deep_extend(super(xt, self).describe(), {
32
- 'id': 'xt',
33
- 'name': 'XT',
34
- 'countries': ['SC'], # Seychelles
35
- # spot api ratelimits are None, 10/s/ip, 50/s/ip, 100/s/ip or 200/s/ip
36
- # futures 3 requests per second => 1000ms / (100 * 3.33) = 3.003(get assets -> fetchMarkets & fetchCurrencies)
37
- # futures 10 requests per second => 1000ms / (100 * 1) = 10(all other)
38
- # futures 1000 times per minute for each single IP -> Otherwise account locked for 10min
39
- 'rateLimit': 100,
40
- 'version': 'v4',
41
- 'certified': True,
42
- 'pro': False,
43
- 'has': {
44
- 'CORS': False,
45
- 'spot': True,
46
- 'margin': True,
47
- 'swap': True,
48
- 'future': True,
49
- 'option': False,
50
- 'addMargin': True,
51
- 'borrowMargin': False,
52
- 'cancelAllOrders': True,
53
- 'cancelOrder': True,
54
- 'cancelOrders': True,
55
- 'createDepositAddress': False,
56
- 'createOrder': True,
57
- 'createPostOnlyOrder': False,
58
- 'createReduceOnlyOrder': True,
59
- 'editOrder': False,
60
- 'fetchAccounts': False,
61
- 'fetchBalance': True,
62
- 'fetchBidsAsks': True,
63
- 'fetchBorrowInterest': False,
64
- 'fetchBorrowRate': False,
65
- 'fetchBorrowRateHistories': False,
66
- 'fetchBorrowRateHistory': False,
67
- 'fetchBorrowRatesPerSymbol': False,
68
- 'fetchCanceledOrders': True,
69
- 'fetchClosedOrders': True,
70
- 'fetchCurrencies': True,
71
- 'fetchDeposit': False,
72
- 'fetchDepositAddress': True,
73
- 'fetchDeposits': True,
74
- 'fetchDepositWithdrawals': False,
75
- 'fetchDepositWithdrawFee': False,
76
- 'fetchDepositWithdrawFees': False,
77
- 'fetchFundingHistory': True,
78
- 'fetchFundingRate': True,
79
- 'fetchFundingRateHistory': True,
80
- 'fetchFundingRates': False,
81
- 'fetchIndexOHLCV': False,
82
- 'fetchL3OrderBook': False,
83
- 'fetchLedger': True,
84
- 'fetchLedgerEntry': False,
85
- 'fetchLeverage': False,
86
- 'fetchLeverageTiers': True,
87
- 'fetchMarketLeverageTiers': True,
88
- 'fetchMarkets': True,
89
- 'fetchMarkOHLCV': False,
90
- 'fetchMyTrades': True,
91
- 'fetchOHLCV': True,
92
- 'fetchOpenInterest': False,
93
- 'fetchOpenInterestHistory': False,
94
- 'fetchOpenOrders': True,
95
- 'fetchOrder': True,
96
- 'fetchOrderBook': True,
97
- 'fetchOrderBooks': False,
98
- 'fetchOrders': True,
99
- 'fetchOrdersByStatus': True,
100
- 'fetchOrderTrades': False,
101
- 'fetchPosition': True,
102
- 'fetchPositions': True,
103
- 'fetchPremiumIndexOHLCV': False,
104
- 'fetchSettlementHistory': False,
105
- 'fetchStatus': False,
106
- 'fetchTicker': True,
107
- 'fetchTickers': True,
108
- 'fetchTime': True,
109
- 'fetchTrades': True,
110
- 'fetchTradingFee': False,
111
- 'fetchTradingFees': False,
112
- 'fetchTradingLimits': False,
113
- 'fetchTransactionFee': False,
114
- 'fetchTransactionFees': False,
115
- 'fetchTransactions': False,
116
- 'fetchTransfer': False,
117
- 'fetchTransfers': False,
118
- 'fetchWithdrawal': False,
119
- 'fetchWithdrawals': True,
120
- 'fetchWithdrawalWhitelist': False,
121
- 'reduceMargin': True,
122
- 'repayMargin': False,
123
- 'setLeverage': True,
124
- 'setMargin': False,
125
- 'setMarginMode': False,
126
- 'setPositionMode': False,
127
- 'signIn': False,
128
- 'transfer': True,
129
- 'withdraw': True,
130
- },
131
- 'precisionMode': TICK_SIZE,
132
- 'urls': {
133
- 'logo': 'https://user-images.githubusercontent.com/14319357/232636712-466df2fc-560a-4ca4-aab2-b1d954a58e24.jpg',
134
- 'api': {
135
- 'spot': 'https://sapi.xt.com',
136
- 'linear': 'https://fapi.xt.com',
137
- 'inverse': 'https://dapi.xt.com',
138
- 'user': 'https://api.xt.com',
139
- },
140
- 'www': 'https://xt.com',
141
- 'referral': 'https://www.xt.com/en/accounts/register?ref=9PTM9VW',
142
- 'doc': [
143
- 'https://doc.xt.com/',
144
- 'https://github.com/xtpub/api-doc',
145
- ],
146
- 'fees': 'https://www.xt.com/en/rate',
147
- },
148
- 'api': {
149
- 'public': {
150
- 'spot': {
151
- 'get': {
152
- 'currencies': 1,
153
- 'depth': 0.05,
154
- 'kline': 0.1,
155
- 'symbol': 1, # 0.1 for a single symbol
156
- 'ticker': 1, # 0.1 for a single symbol
157
- 'ticker/book': 1, # 0.1 for a single symbol
158
- 'ticker/price': 1, # 0.1 for a single symbol
159
- 'ticker/24h': 1, # 0.1 for a single symbol
160
- 'time': 1,
161
- 'trade/history': 0.1,
162
- 'trade/recent': 0.1,
163
- 'wallet/support/currency': 1,
164
- },
165
- },
166
- 'linear': {
167
- 'get': {
168
- 'future/market/v1/public/contract/risk-balance': 1,
169
- 'future/market/v1/public/contract/open-interest': 1,
170
- 'future/market/v1/public/leverage/bracket/detail': 1,
171
- 'future/market/v1/public/leverage/bracket/list': 1,
172
- 'future/market/v1/public/q/agg-ticker': 1,
173
- 'future/market/v1/public/q/agg-tickers': 1,
174
- 'future/market/v1/public/q/deal': 1,
175
- 'future/market/v1/public/q/depth': 1,
176
- 'future/market/v1/public/q/funding-rate': 1,
177
- 'future/market/v1/public/q/funding-rate-record': 1,
178
- 'future/market/v1/public/q/index-price': 1,
179
- 'future/market/v1/public/q/kline': 1,
180
- 'future/market/v1/public/q/mark-price': 1,
181
- 'future/market/v1/public/q/symbol-index-price': 1,
182
- 'future/market/v1/public/q/symbol-mark-price': 1,
183
- 'future/market/v1/public/q/ticker': 1,
184
- 'future/market/v1/public/q/tickers': 1,
185
- 'future/market/v1/public/symbol/coins': 3.33,
186
- 'future/market/v1/public/symbol/detail': 3.33,
187
- 'future/market/v1/public/symbol/list': 1,
188
- },
189
- },
190
- 'inverse': {
191
- 'get': {
192
- 'future/market/v1/public/contract/risk-balance': 1,
193
- 'future/market/v1/public/contract/open-interest': 1,
194
- 'future/market/v1/public/leverage/bracket/detail': 1,
195
- 'future/market/v1/public/leverage/bracket/list': 1,
196
- 'future/market/v1/public/q/agg-ticker': 1,
197
- 'future/market/v1/public/q/agg-tickers': 1,
198
- 'future/market/v1/public/q/deal': 1,
199
- 'future/market/v1/public/q/depth': 1,
200
- 'future/market/v1/public/q/funding-rate': 1,
201
- 'future/market/v1/public/q/funding-rate-record': 1,
202
- 'future/market/v1/public/q/index-price': 1,
203
- 'future/market/v1/public/q/kline': 1,
204
- 'future/market/v1/public/q/mark-price': 1,
205
- 'future/market/v1/public/q/symbol-index-price': 1,
206
- 'future/market/v1/public/q/symbol-mark-price': 1,
207
- 'future/market/v1/public/q/ticker': 1,
208
- 'future/market/v1/public/q/tickers': 1,
209
- 'future/market/v1/public/symbol/coins': 3.33,
210
- 'future/market/v1/public/symbol/detail': 3.33,
211
- 'future/market/v1/public/symbol/list': 1,
212
- },
213
- },
214
- },
215
- 'private': {
216
- 'spot': {
217
- 'get': {
218
- 'balance': 1,
219
- 'balances': 1,
220
- 'batch-order': 1,
221
- 'deposit/address': 1,
222
- 'deposit/history': 1,
223
- 'history-order': 1,
224
- 'open-order': 1,
225
- 'order': 1,
226
- 'order/{orderId}': 1,
227
- 'trade': 1,
228
- 'withdraw/history': 1,
229
- },
230
- 'post': {
231
- 'order': 0.2,
232
- 'withdraw': 1,
233
- 'balance/transfer': 1,
234
- 'balance/account/transfer': 1,
235
- },
236
- 'delete': {
237
- 'batch-order': 1,
238
- 'open-order': 1,
239
- 'order/{orderId}': 1,
240
- },
241
- },
242
- 'linear': {
243
- 'get': {
244
- 'future/trade/v1/entrust/plan-detail': 1,
245
- 'future/trade/v1/entrust/plan-list': 1,
246
- 'future/trade/v1/entrust/plan-list-history': 1,
247
- 'future/trade/v1/entrust/profit-detail': 1,
248
- 'future/trade/v1/entrust/profit-list': 1,
249
- 'future/trade/v1/order/detail': 1,
250
- 'future/trade/v1/order/list': 1,
251
- 'future/trade/v1/order/list-history': 1,
252
- 'future/trade/v1/order/trade-list': 1,
253
- 'future/user/v1/account/info': 1,
254
- 'future/user/v1/balance/bills': 1,
255
- 'future/user/v1/balance/detail': 1,
256
- 'future/user/v1/balance/funding-rate-list': 1,
257
- 'future/user/v1/balance/list': 1,
258
- 'future/user/v1/position/adl': 1,
259
- 'future/user/v1/position/list': 1,
260
- 'future/user/v1/user/collection/list': 1,
261
- 'future/user/v1/user/listen-key': 1,
262
- },
263
- 'post': {
264
- 'future/trade/v1/entrust/cancel-all-plan': 1,
265
- 'future/trade/v1/entrust/cancel-all-profit-stop': 1,
266
- 'future/trade/v1/entrust/cancel-plan': 1,
267
- 'future/trade/v1/entrust/cancel-profit-stop': 1,
268
- 'future/trade/v1/entrust/create-plan': 1,
269
- 'future/trade/v1/entrust/create-profit': 1,
270
- 'future/trade/v1/entrust/update-profit-stop': 1,
271
- 'future/trade/v1/order/cancel': 1,
272
- 'future/trade/v1/order/cancel-all': 1,
273
- 'future/trade/v1/order/create': 1,
274
- 'future/trade/v1/order/create-batch': 1,
275
- 'future/user/v1/account/open': 1,
276
- 'future/user/v1/position/adjust-leverage': 1,
277
- 'future/user/v1/position/auto-margin': 1,
278
- 'future/user/v1/position/close-all': 1,
279
- 'future/user/v1/position/margin': 1,
280
- 'future/user/v1/user/collection/add': 1,
281
- 'future/user/v1/user/collection/cancel': 1,
282
- },
283
- },
284
- 'inverse': {
285
- 'get': {
286
- 'future/trade/v1/entrust/plan-detail': 1,
287
- 'future/trade/v1/entrust/plan-list': 1,
288
- 'future/trade/v1/entrust/plan-list-history': 1,
289
- 'future/trade/v1/entrust/profit-detail': 1,
290
- 'future/trade/v1/entrust/profit-list': 1,
291
- 'future/trade/v1/order/detail': 1,
292
- 'future/trade/v1/order/list': 1,
293
- 'future/trade/v1/order/list-history': 1,
294
- 'future/trade/v1/order/trade-list': 1,
295
- 'future/user/v1/account/info': 1,
296
- 'future/user/v1/balance/bills': 1,
297
- 'future/user/v1/balance/detail': 1,
298
- 'future/user/v1/balance/funding-rate-list': 1,
299
- 'future/user/v1/balance/list': 1,
300
- 'future/user/v1/position/adl': 1,
301
- 'future/user/v1/position/list': 1,
302
- 'future/user/v1/user/collection/list': 1,
303
- 'future/user/v1/user/listen-key': 1,
304
- },
305
- 'post': {
306
- 'future/trade/v1/entrust/cancel-all-plan': 1,
307
- 'future/trade/v1/entrust/cancel-all-profit-stop': 1,
308
- 'future/trade/v1/entrust/cancel-plan': 1,
309
- 'future/trade/v1/entrust/cancel-profit-stop': 1,
310
- 'future/trade/v1/entrust/create-plan': 1,
311
- 'future/trade/v1/entrust/create-profit': 1,
312
- 'future/trade/v1/entrust/update-profit-stop': 1,
313
- 'future/trade/v1/order/cancel': 1,
314
- 'future/trade/v1/order/cancel-all': 1,
315
- 'future/trade/v1/order/create': 1,
316
- 'future/trade/v1/order/create-batch': 1,
317
- 'future/user/v1/account/open': 1,
318
- 'future/user/v1/position/adjust-leverage': 1,
319
- 'future/user/v1/position/auto-margin': 1,
320
- 'future/user/v1/position/close-all': 1,
321
- 'future/user/v1/position/margin': 1,
322
- 'future/user/v1/user/collection/add': 1,
323
- 'future/user/v1/user/collection/cancel': 1,
324
- },
325
- },
326
- 'user': {
327
- 'get': {
328
- 'user/account': 1,
329
- 'user/account/api-key': 1,
330
- },
331
- 'post': {
332
- 'user/account': 1,
333
- 'user/account/api-key': 1,
334
- },
335
- 'put': {
336
- 'user/account/api-key': 1,
337
- },
338
- 'delete': {
339
- 'user/account/{apikeyId}': 1,
340
- },
341
- },
342
- },
343
- },
344
- 'fees': {
345
- 'spot': {
346
- 'tierBased': True,
347
- 'percentage': True,
348
- 'maker': self.parse_number('0.002'),
349
- 'taker': self.parse_number('0.002'),
350
- 'tiers': {
351
- 'maker': [
352
- [self.parse_number('0'), self.parse_number('0.002')],
353
- [self.parse_number('5000'), self.parse_number('0.0018')],
354
- [self.parse_number('10000'), self.parse_number('0.0016')],
355
- [self.parse_number('20000'), self.parse_number('0.0014')],
356
- [self.parse_number('50000'), self.parse_number('0.0012')],
357
- [self.parse_number('150000'), self.parse_number('0.0010')],
358
- [self.parse_number('300000'), self.parse_number('0.0008')],
359
- [self.parse_number('600000'), self.parse_number('0.0007')],
360
- [self.parse_number('1200000'), self.parse_number('0.0006')],
361
- [self.parse_number('2500000'), self.parse_number('0.0005')],
362
- [self.parse_number('6000000'), self.parse_number('0.0004')],
363
- [self.parse_number('15000000'), self.parse_number('0.0003')],
364
- [self.parse_number('30000000'), self.parse_number('0.0002')],
365
- ],
366
- 'taker': [
367
- [self.parse_number('0'), self.parse_number('0.002')],
368
- [self.parse_number('5000'), self.parse_number('0.0018')],
369
- [self.parse_number('10000'), self.parse_number('0.0016')],
370
- [self.parse_number('20000'), self.parse_number('0.0014')],
371
- [self.parse_number('50000'), self.parse_number('0.0012')],
372
- [self.parse_number('150000'), self.parse_number('0.0010')],
373
- [self.parse_number('300000'), self.parse_number('0.0008')],
374
- [self.parse_number('600000'), self.parse_number('0.0007')],
375
- [self.parse_number('1200000'), self.parse_number('0.0006')],
376
- [self.parse_number('2500000'), self.parse_number('0.0005')],
377
- [self.parse_number('6000000'), self.parse_number('0.0004')],
378
- [self.parse_number('15000000'), self.parse_number('0.0003')],
379
- [self.parse_number('30000000'), self.parse_number('0.0002')],
380
- ],
381
- },
382
- },
383
- 'contract': {
384
- 'tierBased': True,
385
- 'percentage': True,
386
- 'maker': self.parse_number('0.0004'),
387
- 'taker': self.parse_number('0.0006'),
388
- 'tiers': {
389
- 'maker': [
390
- [self.parse_number('0'), self.parse_number('0.0004')],
391
- [self.parse_number('200000'), self.parse_number('0.00038')],
392
- [self.parse_number('1000000'), self.parse_number('0.00036')],
393
- [self.parse_number('5000000'), self.parse_number('0.00034')],
394
- [self.parse_number('10000000'), self.parse_number('0.00032')],
395
- [self.parse_number('15000000'), self.parse_number('0.00028')],
396
- [self.parse_number('30000000'), self.parse_number('0.00024')],
397
- [self.parse_number('50000000'), self.parse_number('0.0002')],
398
- [self.parse_number('100000000'), self.parse_number('0.00016')],
399
- [self.parse_number('300000000'), self.parse_number('0.00012')],
400
- [self.parse_number('500000000'), self.parse_number('0.00008')],
401
- ],
402
- 'taker': [
403
- [self.parse_number('0'), self.parse_number('0.0006')],
404
- [self.parse_number('200000'), self.parse_number('0.000588')],
405
- [self.parse_number('1000000'), self.parse_number('0.00057')],
406
- [self.parse_number('5000000'), self.parse_number('0.00054')],
407
- [self.parse_number('10000000'), self.parse_number('0.00051')],
408
- [self.parse_number('15000000'), self.parse_number('0.00048')],
409
- [self.parse_number('30000000'), self.parse_number('0.00045')],
410
- [self.parse_number('50000000'), self.parse_number('0.00045')],
411
- [self.parse_number('100000000'), self.parse_number('0.00036')],
412
- [self.parse_number('300000000'), self.parse_number('0.00033')],
413
- [self.parse_number('500000000'), self.parse_number('0.0003')],
414
- ],
415
- },
416
- },
417
- },
418
- 'exceptions': {
419
- 'exact': {
420
- '400': NetworkError, # {"returnCode":1,"msgInfo":"failure","error":{"code":"400","msg":"Connection refused: /10.0.26.71:8080"},"result":null}
421
- '404': ExchangeError, # interface does not exist
422
- '429': RateLimitExceeded, # The request is too frequent, please control the request rate according to the speed limit requirement
423
- '500': ExchangeError, # Service exception
424
- '502': ExchangeError, # Gateway exception
425
- '503': OnMaintenance, # Service unavailable, please try again later
426
- 'AUTH_001': AuthenticationError, # missing request header xt-validate-appkey
427
- 'AUTH_002': AuthenticationError, # missing request header xt-validate-timestamp
428
- 'AUTH_003': AuthenticationError, # missing request header xt-validate-recvwindow
429
- 'AUTH_004': AuthenticationError, # bad request header xt-validate-recvwindow
430
- 'AUTH_005': AuthenticationError, # missing request header xt-validate-algorithms
431
- 'AUTH_006': AuthenticationError, # bad request header xt-validate-algorithms
432
- 'AUTH_007': AuthenticationError, # missing request header xt-validate-signature
433
- 'AUTH_101': AuthenticationError, # ApiKey does not exist
434
- 'AUTH_102': AuthenticationError, # ApiKey is not activated
435
- 'AUTH_103': AuthenticationError, # Signature error, {"rc":1,"mc":"AUTH_103","ma":[],"result":null}
436
- 'AUTH_104': AuthenticationError, # Unbound IP request
437
- 'AUTH_105': AuthenticationError, # outdated message
438
- 'AUTH_106': PermissionDenied, # Exceeded apikey permission
439
- 'SYMBOL_001': BadSymbol, # Symbol not exist
440
- 'SYMBOL_002': BadSymbol, # Symbol offline
441
- 'SYMBOL_003': BadSymbol, # Symbol suspend trading
442
- 'SYMBOL_004': BadSymbol, # Symbol country disallow trading
443
- 'SYMBOL_005': BadSymbol, # The symbol does not support trading via API
444
- 'ORDER_001': InvalidOrder, # Platform rejection
445
- 'ORDER_002': InsufficientFunds, # insufficient funds
446
- 'ORDER_003': InvalidOrder, # Trading Pair Suspended
447
- 'ORDER_004': InvalidOrder, # no transaction
448
- 'ORDER_005': InvalidOrder, # Order not exist
449
- 'ORDER_006': InvalidOrder, # Too many open orders
450
- 'ORDER_007': PermissionDenied, # The sub-account has no transaction authority
451
- 'ORDER_F0101': InvalidOrder, # Trigger Price Filter - Min
452
- 'ORDER_F0102': InvalidOrder, # Trigger Price Filter - Max
453
- 'ORDER_F0103': InvalidOrder, # Trigger Price Filter - Step Value
454
- 'ORDER_F0201': InvalidOrder, # Trigger Quantity Filter - Min
455
- 'ORDER_F0202': InvalidOrder, # Trigger Quantity Filter - Max
456
- 'ORDER_F0203': InvalidOrder, # Trigger Quantity Filter - Step Value
457
- 'ORDER_F0301': InvalidOrder, # Trigger QUOTE_QTY Filter - Min Value
458
- 'ORDER_F0401': InvalidOrder, # Trigger PROTECTION_ONLINE Filter
459
- 'ORDER_F0501': InvalidOrder, # Trigger PROTECTION_LIMIT Filter - Buy Max Deviation
460
- 'ORDER_F0502': InvalidOrder, # Trigger PROTECTION_LIMIT Filter - Sell Max Deviation
461
- 'ORDER_F0601': InvalidOrder, # Trigger PROTECTION_MARKET Filter
462
- 'COMMON_001': ExchangeError, # The user does not exist
463
- 'COMMON_002': ExchangeError, # System busy, please try it later
464
- 'COMMON_003': BadRequest, # Operation failed, please try it later
465
- 'CURRENCY_001': BadRequest, # Information of currency is abnormal
466
- 'DEPOSIT_001': BadRequest, # Deposit is not open
467
- 'DEPOSIT_002': PermissionDenied, # The current account security level is low, please bind any two security verifications in mobile phone/email/Google Authenticator before deposit
468
- 'DEPOSIT_003': BadRequest, # The format of address is incorrect, please enter again
469
- 'DEPOSIT_004': BadRequest, # The address is already exists, please enter again
470
- 'DEPOSIT_005': BadRequest, # Can not find the address of offline wallet
471
- 'DEPOSIT_006': BadRequest, # No deposit address, please try it later
472
- 'DEPOSIT_007': BadRequest, # Address is being generated, please try it later
473
- 'DEPOSIT_008': BadRequest, # Deposit is not available
474
- 'WITHDRAW_001': BadRequest, # Withdraw is not open
475
- 'WITHDRAW_002': BadRequest, # The withdrawal address is invalid
476
- 'WITHDRAW_003': PermissionDenied, # The current account security level is low, please bind any two security verifications in mobile phone/email/Google Authenticator before withdraw
477
- 'WITHDRAW_004': BadRequest, # The withdrawal address is not added
478
- 'WITHDRAW_005': BadRequest, # The withdrawal address cannot be empty
479
- 'WITHDRAW_006': BadRequest, # Memo cannot be empty
480
- 'WITHDRAW_008': PermissionDenied, # Risk control is triggered, withdraw of self currency is not currently supported
481
- 'WITHDRAW_009': PermissionDenied, # Withdraw failed, some hasattr(self, assets) withdraw are restricted by T+1 withdraw
482
- 'WITHDRAW_010': BadRequest, # The precision of withdrawal is invalid
483
- 'WITHDRAW_011': InsufficientFunds, # free balance is not enough
484
- 'WITHDRAW_012': PermissionDenied, # Withdraw failed, your remaining withdrawal limit today is not enough
485
- 'WITHDRAW_013': PermissionDenied, # Withdraw failed, your remaining withdrawal limit today is not enough, the withdrawal amount can be increased by completing a higher level of real-name authentication
486
- 'WITHDRAW_014': BadRequest, # This withdrawal address cannot be used in the internal transfer function, please cancel the internal transfer function before submitting
487
- 'WITHDRAW_015': BadRequest, # The withdrawal amount is not enough to deduct the handling fee
488
- 'WITHDRAW_016': BadRequest, # This withdrawal address is already exists
489
- 'WITHDRAW_017': BadRequest, # This withdrawal has been processed and cannot be canceled
490
- 'WITHDRAW_018': BadRequest, # Memo must be a number
491
- 'WITHDRAW_019': BadRequest, # Memo is incorrect, please enter again
492
- 'WITHDRAW_020': PermissionDenied, # Your withdrawal amount has reached the upper limit for today, please try it tomorrow
493
- 'WITHDRAW_021': PermissionDenied, # Your withdrawal amount has reached the upper limit for today, you can only withdraw up to {0} self time
494
- 'WITHDRAW_022': BadRequest, # Withdrawal amount must be greater than {0}
495
- 'WITHDRAW_023': BadRequest, # Withdrawal amount must be less than {0}
496
- 'WITHDRAW_024': BadRequest, # Withdraw is not supported
497
- 'WITHDRAW_025': BadRequest, # Please create a FIO address in the deposit page
498
- 'FUND_001': BadRequest, # Duplicate request(a bizId can only be requested once)
499
- 'FUND_002': InsufficientFunds, # Insufficient account balance
500
- 'FUND_003': BadRequest, # Transfer operations are not supported(for example, sub-accounts do not support financial transfers)
501
- 'FUND_004': ExchangeError, # Unfreeze failed
502
- 'FUND_005': PermissionDenied, # Transfer prohibited
503
- 'FUND_014': BadRequest, # The transfer-in account id and transfer-out account ID cannot be the same
504
- 'FUND_015': BadRequest, # From and to business types cannot be the same
505
- 'FUND_016': BadRequest, # Leverage transfer, symbol cannot be empty
506
- 'FUND_017': BadRequest, # Parameter error
507
- 'FUND_018': BadRequest, # Invalid freeze record
508
- 'FUND_019': BadRequest, # Freeze users not equal
509
- 'FUND_020': BadRequest, # Freeze currency are not equal
510
- 'FUND_021': BadRequest, # Operation not supported
511
- 'FUND_022': BadRequest, # Freeze record does not exist
512
- 'FUND_044': BadRequest, # The maximum length of the amount is 113 and cannot exceed the limit
513
- 'TRANSFER_001': BadRequest, # Duplicate request(a bizId can only be requested once)
514
- 'TRANSFER_002': InsufficientFunds, # Insufficient account balance
515
- 'TRANSFER_003': BadRequest, # User not registered
516
- 'TRANSFER_004': PermissionDenied, # The currency is not allowed to be transferred
517
- 'TRANSFER_005': PermissionDenied, # The user’s currency is not allowed to be transferred
518
- 'TRANSFER_006': PermissionDenied, # Transfer prohibited
519
- 'TRANSFER_007': RequestTimeout, # Request timed out
520
- 'TRANSFER_008': BadRequest, # Transferring to a leveraged account is abnormal
521
- 'TRANSFER_009': BadRequest, # Departing from a leveraged account is abnormal
522
- 'TRANSFER_010': PermissionDenied, # Leverage cleared, transfer prohibited
523
- 'TRANSFER_011': PermissionDenied, # Leverage with borrowing, transfer prohibited
524
- 'TRANSFER_012': PermissionDenied, # Currency transfer prohibited
525
- 'symbol_not_support_trading_via_api': BadSymbol, # {"returnCode":1,"msgInfo":"failure","error":{"code":"symbol_not_support_trading_via_api","msg":"The symbol does not support trading via API"},"result":null}
526
- 'open_order_min_nominal_value_limit': InvalidOrder, # {"returnCode":1,"msgInfo":"failure","error":{"code":"open_order_min_nominal_value_limit","msg":"Exceeds the minimum notional value of a single order"},"result":null}
527
- },
528
- 'broad': {
529
- 'The symbol does not support trading via API': BadSymbol, # {"returnCode":1,"msgInfo":"failure","error":{"code":"symbol_not_support_trading_via_api","msg":"The symbol does not support trading via API"},"result":null}
530
- 'Exceeds the minimum notional value of a single order': InvalidOrder, # {"returnCode":1,"msgInfo":"failure","error":{"code":"open_order_min_nominal_value_limit","msg":"Exceeds the minimum notional value of a single order"},"result":null}
531
- },
532
- },
533
- 'timeframes': {
534
- '1m': '1m',
535
- '5m': '5m',
536
- '15m': '15m',
537
- '30m': '30m',
538
- '1h': '1h', # spot only
539
- '2h': '2h', # spot only
540
- '4h': '4h',
541
- '6h': '6h', # spot only
542
- '8h': '8h', # spot only
543
- '1d': '1d',
544
- '3d': '3d', # spot only
545
- '1w': '1w',
546
- '1M': '1M', # spot only
547
- },
548
- 'commonCurrencies': {},
549
- 'options': {
550
- 'adjustForTimeDifference': False,
551
- 'timeDifference': 0,
552
- 'accountsById': {
553
- 'spot': 'SPOT',
554
- 'leverage': 'LEVER',
555
- 'finance': 'FINANCE',
556
- 'swap': 'FUTURES_U',
557
- 'future': 'FUTURES_U',
558
- 'linear': 'FUTURES_U',
559
- 'inverse': 'FUTURES_C',
560
- },
561
- 'networks': {
562
- 'ERC20': 'Ethereum',
563
- 'TRC20': 'Tron',
564
- 'BEP20': 'BNB Smart Chain',
565
- 'BEP2': 'BNB-BEP2',
566
- 'ETH': 'Ethereum',
567
- 'TRON': 'Tron',
568
- 'BNB': 'BNB Smart Chain',
569
- 'AVAX': 'AVAX C-Chain',
570
- 'GAL': 'GAL(FT)',
571
- 'ALEO': 'ALEO(IOU)',
572
- 'BTC': 'Bitcoin',
573
- 'XT': 'XT Smart Chain',
574
- 'ETC': 'Ethereum Classic',
575
- 'MATIC': 'Polygon',
576
- 'LTC': 'Litecoin',
577
- 'BTS': 'BitShares',
578
- 'XRP': 'Ripple',
579
- 'XLM': 'Stellar Network',
580
- 'ADA': 'Cardano',
581
- 'XWC': 'XWC-XWC',
582
- 'DOGE': 'dogecoin',
583
- 'DCR': 'Decred',
584
- 'SC': 'Siacoin',
585
- 'XTZ': 'Tezos',
586
- 'ZEC': 'Zcash',
587
- 'XMR': 'Monero',
588
- 'LSK': 'Lisk',
589
- 'ATOM': 'Cosmos',
590
- 'ONT': 'Ontology',
591
- 'ALGO': 'Algorand',
592
- 'SOL': 'SOL-SOL',
593
- 'DOT': 'Polkadot',
594
- 'ZEN': 'Horizen',
595
- 'FIL': 'Filecoin',
596
- 'CHZ': 'chz',
597
- 'ICP': 'Internet Computer',
598
- 'KSM': 'Kusama',
599
- 'LUNA': 'Terra',
600
- 'THETA': 'Theta Token',
601
- 'FTM': 'Fantom',
602
- 'VET': 'VeChain',
603
- 'NEAR': 'NEAR Protocol',
604
- 'ONE': 'Harmony',
605
- 'KLAY': 'Klaytn',
606
- 'AR': 'Arweave',
607
- 'CELT': 'OKT',
608
- 'EGLD': 'Elrond eGold',
609
- 'CRO': 'CRO-CRONOS',
610
- 'BCH': 'Bitcoin Cash',
611
- 'GLMR': 'Moonbeam',
612
- 'LOOP': 'LOOP-LRC',
613
- 'REI': 'REI Network',
614
- 'ASTR': 'Astar Network',
615
- 'OP': 'OPT',
616
- 'MMT': 'MMT-MMT',
617
- 'TBC': 'TBC-TBC',
618
- 'OMAX': 'OMAX-OMAX CHAIN',
619
- 'GMMT': 'GMMT chain',
620
- 'ZIL': 'Zilliqa',
621
- },
622
- 'networksById': {
623
- 'Ethereum': 'ERC20',
624
- 'Tron': 'TRC20',
625
- 'BNB Smart Chain': 'BEP20',
626
- 'BNB-BEP2': 'BEP2',
627
- 'Bitcoin': 'BTC',
628
- 'XT Smart Chain': 'XT',
629
- 'Ethereum Classic': 'ETC',
630
- 'Polygon': 'MATIC',
631
- 'Litecoin': 'LTC',
632
- 'BitShares': 'BTS',
633
- 'Ripple': 'XRP',
634
- 'Stellar Network': 'XLM',
635
- 'Cardano': 'ADA',
636
- 'XWC-XWC': 'XWC',
637
- 'dogecoin': 'DOGE',
638
- 'Decred': 'DCR',
639
- 'Siacoin': 'SC',
640
- 'Tezos': 'XTZ',
641
- 'Zcash': 'ZEC',
642
- 'Monero': 'XMR',
643
- 'Lisk': 'LSK',
644
- 'Cosmos': 'ATOM',
645
- 'Ontology': 'ONT',
646
- 'Algorand': 'ALGO',
647
- 'SOL-SOL': 'SOL',
648
- 'Polkadot': 'DOT',
649
- 'Horizen': 'ZEN',
650
- 'Filecoin': 'FIL',
651
- 'chz': 'CHZ',
652
- 'Internet Computer': 'ICP',
653
- 'Kusama': 'KSM',
654
- 'Terra': 'LUNA',
655
- 'Theta Token': 'THETA',
656
- 'Fantom': 'FTM',
657
- 'VeChain': 'VET',
658
- 'AVAX C-Chain': 'AVAX',
659
- 'NEAR Protocol': 'NEAR',
660
- 'Harmony': 'ONE',
661
- 'Klaytn': 'KLAY',
662
- 'Arweave': 'AR',
663
- 'OKT': 'CELT',
664
- 'Elrond eGold': 'EGLD',
665
- 'CRO-CRONOS': 'CRO',
666
- 'Bitcoin Cash': 'BCH',
667
- 'Moonbeam': 'GLMR',
668
- 'LOOP-LRC': 'LOOP',
669
- 'REI Network': 'REI',
670
- 'Astar Network': 'ASTR',
671
- 'GAL(FT)': 'GAL',
672
- 'ALEO(IOU)': 'ALEO',
673
- 'OPT': 'OP',
674
- 'MMT-MMT': 'MMT',
675
- 'TBC-TBC': 'TBC',
676
- 'OMAX-OMAX CHAIN': 'OMAX',
677
- 'GMMT chain': 'GMMT',
678
- 'Zilliqa': 'ZIL',
679
- },
680
- 'createMarketBuyOrderRequiresPrice': True,
681
- 'recvWindow': '5000', # in milliseconds, spot only
682
- },
683
- })
684
-
685
- def nonce(self):
686
- return self.milliseconds() - self.options['timeDifference']
687
-
688
- async def fetch_time(self, params={}):
689
- """
690
- fetches the current integer timestamp in milliseconds from the xt server
691
- see https://doc.xt.com/#market1serverInfo
692
- :param dict params: extra parameters specific to the xt api endpoint
693
- :returns int: the current integer timestamp in milliseconds from the xt server
694
- """
695
- response = await self.publicSpotGetTime(params)
696
- #
697
- # {
698
- # "rc": 0,
699
- # "mc": "SUCCESS",
700
- # "ma": [],
701
- # "result": {
702
- # "serverTime": 1677823301643
703
- # }
704
- # }
705
- #
706
- data = self.safe_value(response, 'result')
707
- return self.safe_integer(data, 'serverTime')
708
-
709
- async def fetch_currencies(self, params={}):
710
- """
711
- fetches all available currencies on an exchange
712
- see https://doc.xt.com/#deposit_withdrawalsupportedCurrenciesGet
713
- :param dict params: extra parameters specific to the xt api endpoint
714
- :returns dict: an associative dictionary of currencies
715
- """
716
- promisesRaw = [self.publicSpotGetWalletSupportCurrency(params), self.publicSpotGetCurrencies(params)]
717
- chainsResponse, currenciesResponse = await asyncio.gather(*promisesRaw)
718
- #
719
- # currencies
720
- #
721
- # {
722
- # "time": "1686626116145",
723
- # "version": "5dbbb2f2527c22b2b2e3b47187ef13d1",
724
- # "currencies": [
725
- # {
726
- # "id": "2",
727
- # "currency": "btc",
728
- # "fullName": "Bitcoin",
729
- # "logo": "https://a.static-global.com/1/currency/btc.png",
730
- # "cmcLink": "https://coinmarketcap.com/currencies/bitcoin/",
731
- # "weight": "99999",
732
- # "maxPrecision": "10",
733
- # "depositStatus": "1",
734
- # "withdrawStatus": "1",
735
- # "convertEnabled": "1",
736
- # "transferEnabled": "1",
737
- # "isChainExist": "1",
738
- # "plates": [152]
739
- # },
740
- # ],
741
- # }
742
- #
743
- #
744
- # chains
745
- #
746
- # {
747
- # "rc": 0,
748
- # "mc": "SUCCESS",
749
- # "ma": [],
750
- # "result": [
751
- # {
752
- # "currency": "btc",
753
- # "supportChains": [
754
- # {
755
- # "chain": "Bitcoin",
756
- # "depositEnabled": True,
757
- # "withdrawEnabled": True,
758
- # "withdrawFeeAmount": 0.0009,
759
- # "withdrawMinAmount": 0.0005,
760
- # "depositFeeRate": 0
761
- # },
762
- # ]
763
- # },
764
- # ]
765
- # }
766
- #
767
- # note: individual network's full data is available on per-currency endpoint: https://www.xt.com/sapi/v4/balance/public/currency/11
768
- #
769
- chainsData = self.safe_value(chainsResponse, 'result', [])
770
- currenciesResult = self.safe_value(currenciesResponse, 'result', [])
771
- currenciesData = self.safe_value(currenciesResult, 'currencies', [])
772
- chainsDataIndexed = self.index_by(chainsData, 'currency')
773
- result = {}
774
- for i in range(0, len(currenciesData)):
775
- entry = currenciesData[i]
776
- currencyId = self.safe_string(entry, 'currency')
777
- code = self.safe_currency_code(currencyId)
778
- minPrecision = self.parse_number(self.parse_precision(self.safe_string(entry, 'maxPrecision')))
779
- networkEntry = self.safe_value(chainsDataIndexed, currencyId, {})
780
- rawNetworks = self.safe_value(networkEntry, 'supportChains', [])
781
- networks = {}
782
- minWithdrawString = None
783
- minWithdrawFeeString = None
784
- active = False
785
- deposit = False
786
- withdraw = False
787
- for j in range(0, len(rawNetworks)):
788
- rawNetwork = rawNetworks[j]
789
- networkId = self.safe_string(rawNetwork, 'chain')
790
- network = self.network_id_to_code(networkId)
791
- depositEnabled = self.safe_value(rawNetwork, 'depositEnabled')
792
- deposit = depositEnabled if (depositEnabled) else deposit
793
- withdrawEnabled = self.safe_value(rawNetwork, 'withdrawEnabled')
794
- withdraw = withdrawEnabled if (withdrawEnabled) else withdraw
795
- networkActive = depositEnabled and withdrawEnabled
796
- active = networkActive if (networkActive) else active
797
- withdrawFeeString = self.safe_string(rawNetwork, 'withdrawFeeAmount')
798
- if withdrawFeeString is not None:
799
- minWithdrawFeeString = withdrawFeeString if (minWithdrawFeeString is None) else Precise.string_min(withdrawFeeString, minWithdrawFeeString)
800
- minNetworkWithdrawString = self.safe_string(rawNetwork, 'withdrawMinAmount')
801
- if minNetworkWithdrawString is not None:
802
- minWithdrawString = minNetworkWithdrawString if (minWithdrawString is None) else Precise.string_min(minNetworkWithdrawString, minWithdrawString)
803
- networks[network] = {
804
- 'info': rawNetwork,
805
- 'id': networkId,
806
- 'network': network,
807
- 'name': None,
808
- 'active': networkActive,
809
- 'fee': self.parse_number(withdrawFeeString),
810
- 'precision': minPrecision,
811
- 'deposit': depositEnabled,
812
- 'withdraw': withdrawEnabled,
813
- 'limits': {
814
- 'amount': {
815
- 'min': None,
816
- 'max': None,
817
- },
818
- 'withdraw': {
819
- 'min': self.parse_number(minNetworkWithdrawString),
820
- 'max': None,
821
- },
822
- 'deposit': {
823
- 'min': None,
824
- 'max': None,
825
- },
826
- },
827
- }
828
- result[code] = {
829
- 'info': entry,
830
- 'id': currencyId,
831
- 'code': code,
832
- 'name': self.safe_string(entry, 'fullName'),
833
- 'active': active,
834
- 'fee': self.parse_number(minWithdrawFeeString),
835
- 'precision': None,
836
- 'deposit': deposit,
837
- 'withdraw': withdraw,
838
- 'networks': networks,
839
- 'limits': {
840
- 'amount': {
841
- 'min': None,
842
- 'max': None,
843
- },
844
- 'withdraw': {
845
- 'min': self.parse_number(minWithdrawString),
846
- 'max': None,
847
- },
848
- 'deposit': {
849
- 'min': None,
850
- 'max': None,
851
- },
852
- },
853
- }
854
- return result
855
-
856
- async def fetch_markets(self, params={}):
857
- """
858
- retrieves data on all markets for xt
859
- see https://doc.xt.com/#market2symbol
860
- see https://doc.xt.com/#futures_quotesgetSymbols
861
- :param dict params: extra parameters specific to the xt api endpoint
862
- :returns [dict]: an array of objects representing market data
863
- """
864
- if self.options['adjustForTimeDifference']:
865
- await self.load_time_difference()
866
- promisesUnresolved = [
867
- self.fetch_spot_markets(params),
868
- self.fetch_swap_and_future_markets(params),
869
- ]
870
- promises = await asyncio.gather(*promisesUnresolved)
871
- spotMarkets = promises[0]
872
- swapAndFutureMarkets = promises[1]
873
- return self.array_concat(spotMarkets, swapAndFutureMarkets)
874
-
875
- async def fetch_spot_markets(self, params={}):
876
- response = await self.publicSpotGetSymbol(params)
877
- #
878
- # {
879
- # "rc": 0,
880
- # "mc": "SUCCESS",
881
- # "ma": [],
882
- # "result": {
883
- # "time": 1677881368812,
884
- # "version": "abb101d1543e54bee40687b135411ba0",
885
- # "symbols": [
886
- # {
887
- # "id": 640,
888
- # "symbol": "xt_usdt",
889
- # "state": "ONLINE",
890
- # "stateTime": 1554048000000,
891
- # "tradingEnabled": True,
892
- # "openapiEnabled": True,
893
- # "nextStateTime": null,
894
- # "nextState": null,
895
- # "depthMergePrecision": 5,
896
- # "baseCurrency": "xt",
897
- # "baseCurrencyPrecision": 8,
898
- # "baseCurrencyId": 128,
899
- # "quoteCurrency": "usdt",
900
- # "quoteCurrencyPrecision": 8,
901
- # "quoteCurrencyId": 11,
902
- # "pricePrecision": 4,
903
- # "quantityPrecision": 2,
904
- # "orderTypes": ["LIMIT","MARKET"],
905
- # "timeInForces": ["GTC","IOC"],
906
- # "displayWeight": 10002,
907
- # "displayLevel": "FULL",
908
- # "plates": [],
909
- # "filters":[
910
- # {
911
- # "filter": "QUOTE_QTY",
912
- # "min": "1"
913
- # },
914
- # {
915
- # "filter": "PROTECTION_LIMIT",
916
- # "buyMaxDeviation": "0.8",
917
- # "sellMaxDeviation": "4"
918
- # },
919
- # {
920
- # "filter": "PROTECTION_MARKET",
921
- # "maxDeviation": "0.02"
922
- # }
923
- # ]
924
- # },
925
- # ]
926
- # }
927
- # }
928
- #
929
- data = self.safe_value(response, 'result', {})
930
- symbols = self.safe_value(data, 'symbols', [])
931
- return self.parse_markets(symbols)
932
-
933
- async def fetch_swap_and_future_markets(self, params={}):
934
- markets = await asyncio.gather(*[self.publicLinearGetFutureMarketV1PublicSymbolList(params), self.publicInverseGetFutureMarketV1PublicSymbolList(params)])
935
- #
936
- # {
937
- # "returnCode": 0,
938
- # "msgInfo": "success",
939
- # "error": null,
940
- # "result": [
941
- # {
942
- # "id": 52,
943
- # "symbolGroupId": 71,
944
- # "symbol": "xt_usdt",
945
- # "pair": "xt_usdt",
946
- # "contractType": "PERPETUAL",
947
- # "productType": "perpetual",
948
- # "predictEventType": null,
949
- # "underlyingType": "U_BASED",
950
- # "contractSize": "1",
951
- # "tradeSwitch": True,
952
- # "isDisplay": True,
953
- # "isOpenApi": False,
954
- # "state": 0,
955
- # "initLeverage": 20,
956
- # "initPositionType": "CROSSED",
957
- # "baseCoin": "xt",
958
- # "quoteCoin": "usdt",
959
- # "baseCoinPrecision": 8,
960
- # "baseCoinDisplayPrecision": 4,
961
- # "quoteCoinPrecision": 8,
962
- # "quoteCoinDisplayPrecision": 4,
963
- # "quantityPrecision": 0,
964
- # "pricePrecision": 4,
965
- # "supportOrderType": "LIMIT,MARKET",
966
- # "supportTimeInForce": "GTC,FOK,IOC,GTX",
967
- # "supportEntrustType": "TAKE_PROFIT,STOP,TAKE_PROFIT_MARKET,STOP_MARKET,TRAILING_STOP_MARKET",
968
- # "supportPositionType": "CROSSED,ISOLATED",
969
- # "minQty": "1",
970
- # "minNotional": "5",
971
- # "maxNotional": "20000000",
972
- # "multiplierDown": "0.1",
973
- # "multiplierUp": "0.1",
974
- # "maxOpenOrders": 200,
975
- # "maxEntrusts": 200,
976
- # "makerFee": "0.0004",
977
- # "takerFee": "0.0006",
978
- # "liquidationFee": "0.01",
979
- # "marketTakeBound": "0.1",
980
- # "depthPrecisionMerge": 5,
981
- # "labels": ["HOT"],
982
- # "onboardDate": 1657101601000,
983
- # "enName": "XTUSDT ",
984
- # "cnName": "XTUSDT",
985
- # "minStepPrice": "0.0001",
986
- # "minPrice": null,
987
- # "maxPrice": null,
988
- # "deliveryDate": 1669879634000,
989
- # "deliveryPrice": null,
990
- # "deliveryCompletion": False,
991
- # "cnDesc": null,
992
- # "enDesc": null
993
- # },
994
- # ]
995
- # }
996
- #
997
- swapAndFutureMarkets = self.array_concat(self.safe_value(markets[0], 'result', []), self.safe_value(markets[1], 'result', []))
998
- return self.parse_markets(swapAndFutureMarkets)
999
-
1000
- def parse_markets(self, markets):
1001
- result = []
1002
- for i in range(0, len(markets)):
1003
- result.append(self.parse_market(markets[i]))
1004
- return result
1005
-
1006
- def parse_market(self, market):
1007
- #
1008
- # spot
1009
- #
1010
- # {
1011
- # "id": 640,
1012
- # "symbol": "xt_usdt",
1013
- # "state": "ONLINE",
1014
- # "stateTime": 1554048000000,
1015
- # "tradingEnabled": True,
1016
- # "openapiEnabled": True,
1017
- # "nextStateTime": null,
1018
- # "nextState": null,
1019
- # "depthMergePrecision": 5,
1020
- # "baseCurrency": "xt",
1021
- # "baseCurrencyPrecision": 8,
1022
- # "baseCurrencyId": 128,
1023
- # "quoteCurrency": "usdt",
1024
- # "quoteCurrencyPrecision": 8,
1025
- # "quoteCurrencyId": 11,
1026
- # "pricePrecision": 4,
1027
- # "quantityPrecision": 2,
1028
- # "orderTypes": ["LIMIT","MARKET"],
1029
- # "timeInForces": ["GTC","IOC"],
1030
- # "displayWeight": 10002,
1031
- # "displayLevel": "FULL",
1032
- # "plates": [],
1033
- # "filters":[
1034
- # {
1035
- # "filter": "QUOTE_QTY",
1036
- # "min": "1"
1037
- # },
1038
- # {
1039
- # "filter": "PRICE",
1040
- # "min": null,
1041
- # "max": null,
1042
- # "tickSize": null
1043
- # },
1044
- # {
1045
- # "filter": "QUANTITY",
1046
- # "min": null,
1047
- # "max": null,
1048
- # "tickSize": null
1049
- # },
1050
- # {
1051
- # "filter": "PROTECTION_LIMIT",
1052
- # "buyMaxDeviation": "0.8",
1053
- # "sellMaxDeviation": "4"
1054
- # },
1055
- # {
1056
- # "filter": "PROTECTION_MARKET",
1057
- # "maxDeviation": "0.02"
1058
- # },
1059
- # {
1060
- # "filter": "PROTECTION_ONLINE",
1061
- # "durationSeconds": "300",
1062
- # "maxPriceMultiple": "5"
1063
- # },
1064
- # ]
1065
- # }
1066
- #
1067
- # swap and future
1068
- #
1069
- # {
1070
- # "id": 52,
1071
- # "symbolGroupId": 71,
1072
- # "symbol": "xt_usdt",
1073
- # "pair": "xt_usdt",
1074
- # "contractType": "PERPETUAL",
1075
- # "productType": "perpetual",
1076
- # "predictEventType": null,
1077
- # "underlyingType": "U_BASED",
1078
- # "contractSize": "1",
1079
- # "tradeSwitch": True,
1080
- # "isDisplay": True,
1081
- # "isOpenApi": False,
1082
- # "state": 0,
1083
- # "initLeverage": 20,
1084
- # "initPositionType": "CROSSED",
1085
- # "baseCoin": "xt",
1086
- # "quoteCoin": "usdt",
1087
- # "baseCoinPrecision": 8,
1088
- # "baseCoinDisplayPrecision": 4,
1089
- # "quoteCoinPrecision": 8,
1090
- # "quoteCoinDisplayPrecision": 4,
1091
- # "quantityPrecision": 0,
1092
- # "pricePrecision": 4,
1093
- # "supportOrderType": "LIMIT,MARKET",
1094
- # "supportTimeInForce": "GTC,FOK,IOC,GTX",
1095
- # "supportEntrustType": "TAKE_PROFIT,STOP,TAKE_PROFIT_MARKET,STOP_MARKET,TRAILING_STOP_MARKET",
1096
- # "supportPositionType": "CROSSED,ISOLATED",
1097
- # "minQty": "1",
1098
- # "minNotional": "5",
1099
- # "maxNotional": "20000000",
1100
- # "multiplierDown": "0.1",
1101
- # "multiplierUp": "0.1",
1102
- # "maxOpenOrders": 200,
1103
- # "maxEntrusts": 200,
1104
- # "makerFee": "0.0004",
1105
- # "takerFee": "0.0006",
1106
- # "liquidationFee": "0.01",
1107
- # "marketTakeBound": "0.1",
1108
- # "depthPrecisionMerge": 5,
1109
- # "labels": ["HOT"],
1110
- # "onboardDate": 1657101601000,
1111
- # "enName": "XTUSDT ",
1112
- # "cnName": "XTUSDT",
1113
- # "minStepPrice": "0.0001",
1114
- # "minPrice": null,
1115
- # "maxPrice": null,
1116
- # "deliveryDate": 1669879634000,
1117
- # "deliveryPrice": null,
1118
- # "deliveryCompletion": False,
1119
- # "cnDesc": null,
1120
- # "enDesc": null
1121
- # }
1122
- #
1123
- id = self.safe_string(market, 'symbol')
1124
- baseId = self.safe_string_2(market, 'baseCurrency', 'baseCoin')
1125
- quoteId = self.safe_string_2(market, 'quoteCurrency', 'quoteCoin')
1126
- base = self.safe_currency_code(baseId)
1127
- quote = self.safe_currency_code(quoteId)
1128
- state = self.safe_string(market, 'state')
1129
- symbol = base + '/' + quote
1130
- filters = self.safe_value(market, 'filters', [])
1131
- minAmount = None
1132
- maxAmount = None
1133
- minCost = None
1134
- maxCost = None
1135
- minPrice = None
1136
- maxPrice = None
1137
- for i in range(0, len(filters)):
1138
- entry = filters[i]
1139
- filter = self.safe_string(entry, 'filter')
1140
- if filter == 'QUANTITY':
1141
- minAmount = self.safe_number(entry, 'min')
1142
- maxAmount = self.safe_number(entry, 'max')
1143
- if filter == 'QUOTE_QTY':
1144
- minCost = self.safe_number(entry, 'min')
1145
- if filter == 'PRICE':
1146
- minPrice = self.safe_number(entry, 'min')
1147
- maxPrice = self.safe_number(entry, 'max')
1148
- underlyingType = self.safe_string(market, 'underlyingType')
1149
- linear = None
1150
- inverse = None
1151
- settleId = None
1152
- settle = None
1153
- expiry = None
1154
- future = False
1155
- swap = False
1156
- contract = False
1157
- spot = True
1158
- type = 'spot'
1159
- if underlyingType == 'U_BASED':
1160
- symbol = symbol + ':' + quote
1161
- settleId = baseId
1162
- settle = quote
1163
- linear = True
1164
- inverse = False
1165
- elif underlyingType == 'COIN_BASED':
1166
- symbol = symbol + ':' + base
1167
- settleId = baseId
1168
- settle = base
1169
- linear = False
1170
- inverse = True
1171
- if underlyingType is not None:
1172
- expiry = self.safe_integer(market, 'deliveryDate')
1173
- productType = self.safe_string(market, 'productType')
1174
- if productType != 'perpetual':
1175
- symbol = symbol + '-' + self.yymmdd(expiry)
1176
- type = 'future'
1177
- future = True
1178
- else:
1179
- type = 'swap'
1180
- swap = True
1181
- minAmount = self.safe_number(market, 'minQty')
1182
- minCost = self.safe_number(market, 'minNotional')
1183
- maxCost = self.safe_number(market, 'maxNotional')
1184
- minPrice = self.safe_number(market, 'minPrice')
1185
- maxPrice = self.safe_number(market, 'maxPrice')
1186
- contract = True
1187
- spot = False
1188
- isActive = False
1189
- if contract:
1190
- isActive = self.safe_value(market, 'isOpenApi', False)
1191
- else:
1192
- if (state == 'ONLINE') and (self.safe_value(market, 'tradingEnabled')) and (self.safe_value(market, 'openapiEnabled')):
1193
- isActive = True
1194
- return {
1195
- 'id': id,
1196
- 'symbol': symbol,
1197
- 'base': base,
1198
- 'quote': quote,
1199
- 'settle': settle,
1200
- 'baseId': baseId,
1201
- 'quoteId': quoteId,
1202
- 'settleId': settleId,
1203
- 'type': type,
1204
- 'spot': spot,
1205
- 'margin': None,
1206
- 'swap': swap,
1207
- 'future': future,
1208
- 'option': False,
1209
- 'active': isActive,
1210
- 'contract': contract,
1211
- 'linear': linear,
1212
- 'inverse': inverse,
1213
- 'taker': self.safe_number(market, 'takerFee'),
1214
- 'maker': self.safe_number(market, 'makerFee'),
1215
- 'contractSize': self.safe_number(market, 'contractSize'),
1216
- 'expiry': expiry,
1217
- 'expiryDatetime': self.iso8601(expiry),
1218
- 'strike': None,
1219
- 'optionType': None,
1220
- 'precision': {
1221
- 'price': self.parse_number(self.parse_precision(self.safe_string(market, 'pricePrecision'))),
1222
- 'amount': self.parse_number(self.parse_precision(self.safe_string(market, 'quantityPrecision'))),
1223
- 'base': self.parse_number(self.parse_precision(self.safe_string(market, 'baseCoinPrecision'))),
1224
- 'quote': self.parse_number(self.parse_precision(self.safe_string(market, 'quoteCoinPrecision'))),
1225
- },
1226
- 'limits': {
1227
- 'leverage': {
1228
- 'min': self.parse_number('1'),
1229
- 'max': None,
1230
- },
1231
- 'amount': {
1232
- 'min': minAmount,
1233
- 'max': maxAmount,
1234
- },
1235
- 'price': {
1236
- 'min': minPrice,
1237
- 'max': maxPrice,
1238
- },
1239
- 'cost': {
1240
- 'min': minCost,
1241
- 'max': maxCost,
1242
- },
1243
- },
1244
- 'info': market,
1245
- }
1246
-
1247
- async def fetch_ohlcv(self, symbol: str, timeframe='1m', since: Optional[int] = None, limit: Optional[int] = None, params={}):
1248
- """
1249
- fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
1250
- see https://doc.xt.com/#market4kline
1251
- see https://doc.xt.com/#futures_quotesgetKLine
1252
- :param str symbol: unified symbol of the market to fetch OHLCV data for
1253
- :param str timeframe: the length of time each candle represents
1254
- :param int|None since: timestamp in ms of the earliest candle to fetch
1255
- :param int|None limit: the maximum amount of candles to fetch
1256
- :param dict params: extra parameters specific to the xt api endpoint
1257
- :returns [[int]]: A list of candles ordered, open, high, low, close, volume
1258
- """
1259
- await self.load_markets()
1260
- market = self.market(symbol)
1261
- request = {
1262
- 'symbol': market['id'],
1263
- 'interval': self.safe_string(self.timeframes, timeframe, timeframe),
1264
- }
1265
- if since is not None:
1266
- request['startTime'] = since
1267
- if limit is not None:
1268
- request['limit'] = limit
1269
- response = None
1270
- if market['linear']:
1271
- response = await self.publicLinearGetFutureMarketV1PublicQKline(self.extend(request, params))
1272
- elif market['inverse']:
1273
- response = await self.publicInverseGetFutureMarketV1PublicQKline(self.extend(request, params))
1274
- else:
1275
- response = await self.publicSpotGetKline(self.extend(request, params))
1276
- #
1277
- # spot
1278
- #
1279
- # {
1280
- # "rc": 0,
1281
- # "mc": "SUCCESS",
1282
- # "ma": [],
1283
- # "result": [
1284
- # {
1285
- # "t": 1678167720000,
1286
- # "o": "22467.85",
1287
- # "c": "22465.87",
1288
- # "h": "22468.86",
1289
- # "l": "22465.21",
1290
- # "q": "1.316656",
1291
- # "v": "29582.73018498"
1292
- # },
1293
- # ]
1294
- # }
1295
- #
1296
- # swap and future
1297
- #
1298
- # {
1299
- # "returnCode": 0,
1300
- # "msgInfo": "success",
1301
- # "error": null,
1302
- # "result": [
1303
- # {
1304
- # "s": "btc_usdt",
1305
- # "p": "btc_usdt",
1306
- # "t": 1678168020000,
1307
- # "o": "22450.0",
1308
- # "c": "22441.5",
1309
- # "h": "22450.0",
1310
- # "l": "22441.5",
1311
- # "a": "312931",
1312
- # "v": "702461.58895"
1313
- # },
1314
- # ]
1315
- # }
1316
- #
1317
- ohlcvs = self.safe_value(response, 'result', [])
1318
- return self.parse_ohlcvs(ohlcvs, market, timeframe, since, limit)
1319
-
1320
- def parse_ohlcv(self, ohlcv, market=None):
1321
- #
1322
- # spot
1323
- #
1324
- # {
1325
- # "t": 1678167720000,
1326
- # "o": "22467.85",
1327
- # "c": "22465.87",
1328
- # "h": "22468.86",
1329
- # "l": "22465.21",
1330
- # "q": "1.316656",
1331
- # "v": "29582.73018498"
1332
- # }
1333
- #
1334
- # swap and future
1335
- #
1336
- # {
1337
- # "s": "btc_usdt",
1338
- # "p": "btc_usdt",
1339
- # "t": 1678168020000,
1340
- # "o": "22450.0",
1341
- # "c": "22441.5",
1342
- # "h": "22450.0",
1343
- # "l": "22441.5",
1344
- # "a": "312931",
1345
- # "v": "702461.58895"
1346
- # }
1347
- #
1348
- volumeIndex = 'v' if (market['inverse']) else 'a'
1349
- return [
1350
- self.safe_integer(ohlcv, 't'),
1351
- self.safe_number(ohlcv, 'o'),
1352
- self.safe_number(ohlcv, 'h'),
1353
- self.safe_number(ohlcv, 'l'),
1354
- self.safe_number(ohlcv, 'c'),
1355
- self.safe_number_2(ohlcv, volumeIndex, 'v'),
1356
- ]
1357
-
1358
- async def fetch_order_book(self, symbol: str, limit: Optional[int] = None, params={}):
1359
- """
1360
- see https://doc.xt.com/#market3depth
1361
- see https://doc.xt.com/#futures_quotesgetDepth
1362
- fetches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
1363
- :param str symbol: unified market symbol to fetch the order book for
1364
- :param int|None limit: the maximum amount of order book entries to return
1365
- :param dict params: extra parameters specific to the xt api endpoint
1366
- :returns dict: A dictionary of `order book structures <https://docs.ccxt.com/en/latest/manual.html#order-book-structure>` indexed by market symbols
1367
- """
1368
- await self.load_markets()
1369
- market = self.market(symbol)
1370
- request = {
1371
- 'symbol': market['id'],
1372
- }
1373
- response = None
1374
- if market['spot']:
1375
- if limit is not None:
1376
- request['limit'] = min(limit, 500)
1377
- response = await self.publicSpotGetDepth(self.extend(request, params))
1378
- else:
1379
- if limit is not None:
1380
- request['level'] = min(limit, 50)
1381
- else:
1382
- request['level'] = 50
1383
- if market['linear']:
1384
- response = await self.publicLinearGetFutureMarketV1PublicQDepth(self.extend(request, params))
1385
- elif market['inverse']:
1386
- response = await self.publicInverseGetFutureMarketV1PublicQDepth(self.extend(request, params))
1387
- #
1388
- # spot
1389
- #
1390
- # {
1391
- # "rc": 0,
1392
- # "mc": "SUCCESS",
1393
- # "ma": [],
1394
- # "result": {
1395
- # "timestamp": 1678169975184,
1396
- # "lastUpdateId": 1675333221812,
1397
- # "bids": [
1398
- # ["22444.51", "0.129887"],
1399
- # ["22444.49", "0.114245"],
1400
- # ["22444.30", "0.225956"]
1401
- # ],
1402
- # "asks": [
1403
- # ["22446.19", "0.095330"],
1404
- # ["22446.24", "0.224413"],
1405
- # ["22446.28", "0.329095"]
1406
- # ]
1407
- # }
1408
- # }
1409
- #
1410
- # swap and future
1411
- #
1412
- # {
1413
- # "returnCode": 0,
1414
- # "msgInfo": "success",
1415
- # "error": null,
1416
- # "result": {
1417
- # "t": 1678170311005,
1418
- # "s": "btc_usdt",
1419
- # "u": 471694545627,
1420
- # "b": [
1421
- # ["22426", "198623"],
1422
- # ["22423.5", "80295"],
1423
- # ["22423", "163580"]
1424
- # ],
1425
- # "a": [
1426
- # ["22427", "3417"],
1427
- # ["22428.5", "43532"],
1428
- # ["22429", "119"]
1429
- # ]
1430
- # }
1431
- # }
1432
- #
1433
- orderBook = self.safe_value(response, 'result', {})
1434
- timestamp = self.safe_integer_2(orderBook, 'timestamp', 't')
1435
- if market['spot']:
1436
- return self.parse_order_book(orderBook, symbol, timestamp)
1437
- return self.parse_order_book(orderBook, symbol, timestamp, 'b', 'a')
1438
-
1439
- async def fetch_ticker(self, symbol: str, params={}):
1440
- """
1441
- fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
1442
- see https://doc.xt.com/#market10ticker24h
1443
- see https://doc.xt.com/#futures_quotesgetAggTicker
1444
- :param str symbol: unified market symbol to fetch the ticker for
1445
- :param dict params: extra parameters specific to the xt api endpoint
1446
- :returns dict: a `ticker structure <https://docs.ccxt.com/en/latest/manual.html#ticker-structure>`
1447
- """
1448
- await self.load_markets()
1449
- market = self.market(symbol)
1450
- request = {
1451
- 'symbol': market['id'],
1452
- }
1453
- response = None
1454
- if market['linear']:
1455
- response = await self.publicLinearGetFutureMarketV1PublicQAggTicker(self.extend(request, params))
1456
- elif market['inverse']:
1457
- response = await self.publicInverseGetFutureMarketV1PublicQAggTicker(self.extend(request, params))
1458
- else:
1459
- response = await self.publicSpotGetTicker24h(self.extend(request, params))
1460
- #
1461
- # spot
1462
- #
1463
- # {
1464
- # "rc": 0,
1465
- # "mc": "SUCCESS",
1466
- # "ma": [],
1467
- # "result": [
1468
- # {
1469
- # "s": "btc_usdt",
1470
- # "t": 1678172693931,
1471
- # "cv": "34.00",
1472
- # "cr": "0.0015",
1473
- # "o": "22398.05",
1474
- # "l": "22323.72",
1475
- # "h": "22600.50",
1476
- # "c": "22432.05",
1477
- # "q": "7962.256931",
1478
- # "v": "178675209.47416856"
1479
- # }
1480
- # ]
1481
- # }
1482
- #
1483
- # swap and future
1484
- #
1485
- # {
1486
- # "returnCode": 0,
1487
- # "msgInfo": "success",
1488
- # "error": null,
1489
- # "result": {
1490
- # "t": 1678172848572,
1491
- # "s": "btc_usdt",
1492
- # "c": "22415.5",
1493
- # "h": "22590.0",
1494
- # "l": "22310.0",
1495
- # "a": "623654031",
1496
- # "v": "1399166074.31675",
1497
- # "o": "22381.5",
1498
- # "r": "0.0015",
1499
- # "i": "22424.5",
1500
- # "m": "22416.5",
1501
- # "bp": "22415",
1502
- # "ap": "22415.5"
1503
- # }
1504
- # }
1505
- #
1506
- ticker = self.safe_value(response, 'result')
1507
- if market['spot']:
1508
- return self.parse_ticker(ticker[0], market)
1509
- return self.parse_ticker(ticker, market)
1510
-
1511
- async def fetch_tickers(self, symbols: Optional[List[str]] = None, params={}):
1512
- """
1513
- fetches price tickers for multiple markets, statistical calculations with the information calculated over the past 24 hours each market
1514
- see https://doc.xt.com/#market10ticker24h
1515
- see https://doc.xt.com/#futures_quotesgetAggTickers
1516
- :param [str]|None symbols: unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
1517
- :param dict params: extra parameters specific to the xt api endpoint
1518
- :returns dict: an array of `ticker structures <https://docs.ccxt.com/en/latest/manual.html#ticker-structure>`
1519
- """
1520
- await self.load_markets()
1521
- market = None
1522
- if symbols is not None:
1523
- symbols = self.market_symbols(symbols)
1524
- market = self.market(symbols[0])
1525
- request = {}
1526
- type = None
1527
- subType = None
1528
- response = None
1529
- type, params = self.handle_market_type_and_params('fetchTickers', market, params)
1530
- subType, params = self.handle_sub_type_and_params('fetchTickers', market, params)
1531
- if subType == 'inverse':
1532
- response = await self.publicInverseGetFutureMarketV1PublicQAggTickers(self.extend(request, params))
1533
- elif (subType == 'linear') or (type == 'swap') or (type == 'future'):
1534
- response = await self.publicLinearGetFutureMarketV1PublicQAggTickers(self.extend(request, params))
1535
- else:
1536
- response = await self.publicSpotGetTicker24h(self.extend(request, params))
1537
- #
1538
- # spot
1539
- #
1540
- # {
1541
- # "rc": 0,
1542
- # "mc": "SUCCESS",
1543
- # "ma": [],
1544
- # "result": [
1545
- # {
1546
- # "s": "btc_usdt",
1547
- # "t": 1678172693931,
1548
- # "cv": "34.00",
1549
- # "cr": "0.0015",
1550
- # "o": "22398.05",
1551
- # "l": "22323.72",
1552
- # "h": "22600.50",
1553
- # "c": "22432.05",
1554
- # "q": "7962.256931",
1555
- # "v": "178675209.47416856"
1556
- # }
1557
- # ]
1558
- # }
1559
- #
1560
- # swap and future
1561
- #
1562
- # {
1563
- # "returnCode": 0,
1564
- # "msgInfo": "success",
1565
- # "error": null,
1566
- # "result": [
1567
- # {
1568
- # "t": 1680738775108,
1569
- # "s": "badger_usdt",
1570
- # "c": "2.7176",
1571
- # "h": "2.7917",
1572
- # "l": "2.6818",
1573
- # "a": "88332",
1574
- # "v": "242286.3520",
1575
- # "o": "2.7422",
1576
- # "r": "-0.0089",
1577
- # "i": "2.7155",
1578
- # "m": "2.7161",
1579
- # "bp": "2.7152",
1580
- # "ap": "2.7176"
1581
- # },
1582
- # ]
1583
- # }
1584
- #
1585
- tickers = self.safe_value(response, 'result', [])
1586
- result = {}
1587
- for i in range(0, len(tickers)):
1588
- ticker = self.parse_ticker(tickers[i], market)
1589
- symbol = ticker['symbol']
1590
- result[symbol] = ticker
1591
- return self.filter_by_array(result, 'symbol', symbols)
1592
-
1593
- async def fetch_bids_asks(self, symbols: Optional[List[str]] = None, params={}):
1594
- """
1595
- fetches the bid and ask price and volume for multiple markets
1596
- see https://doc.xt.com/#market9tickerBook
1597
- :param [str]|None symbols: unified symbols of the markets to fetch the bids and asks for, all markets are returned if not assigned
1598
- :param dict params: extra parameters specific to the xt api endpoint
1599
- :returns dict: a dictionary of `ticker structures <https://docs.ccxt.com/en/latest/manual.html#ticker-structure>`
1600
- """
1601
- await self.load_markets()
1602
- symbols = self.market_symbols(symbols)
1603
- request = {}
1604
- market = None
1605
- if symbols is not None:
1606
- market = self.market(symbols[0])
1607
- subType = None
1608
- subType, params = self.handle_sub_type_and_params('fetchBidsAsks', market, params)
1609
- if subType is not None:
1610
- raise NotSupported(self.id + ' fetchBidsAsks() is not available for swap and future markets, only spot markets are supported')
1611
- response = await self.publicSpotGetTickerBook(self.extend(request, params))
1612
- #
1613
- # {
1614
- # "rc": 0,
1615
- # "mc": "SUCCESS",
1616
- # "ma": [],
1617
- # "result": [
1618
- # {
1619
- # "s": "kas_usdt",
1620
- # "t": 1679539891853,
1621
- # "ap": "0.016298",
1622
- # "aq": "5119.09",
1623
- # "bp": "0.016290",
1624
- # "bq": "135.37"
1625
- # },
1626
- # ]
1627
- # }
1628
- #
1629
- tickers = self.safe_value(response, 'result', [])
1630
- return self.parse_tickers(tickers, symbols)
1631
-
1632
- def parse_ticker(self, ticker, market=None):
1633
- #
1634
- # spot: fetchTicker, fetchTickers
1635
- #
1636
- # {
1637
- # "s": "btc_usdt",
1638
- # "t": 1678172693931,
1639
- # "cv": "34.00",
1640
- # "cr": "0.0015",
1641
- # "o": "22398.05",
1642
- # "l": "22323.72",
1643
- # "h": "22600.50",
1644
- # "c": "22432.05",
1645
- # "q": "7962.256931",
1646
- # "v": "178675209.47416856"
1647
- # }
1648
- #
1649
- # swap and future: fetchTicker, fetchTickers
1650
- #
1651
- # {
1652
- # "t": 1678172848572,
1653
- # "s": "btc_usdt",
1654
- # "c": "22415.5",
1655
- # "h": "22590.0",
1656
- # "l": "22310.0",
1657
- # "a": "623654031",
1658
- # "v": "1399166074.31675",
1659
- # "o": "22381.5",
1660
- # "r": "0.0015",
1661
- # "i": "22424.5",
1662
- # "m": "22416.5",
1663
- # "bp": "22415",
1664
- # "ap": "22415.5"
1665
- # }
1666
- #
1667
- # fetchBidsAsks
1668
- #
1669
- # {
1670
- # "s": "kas_usdt",
1671
- # "t": 1679539891853,
1672
- # "ap": "0.016298",
1673
- # "aq": "5119.09",
1674
- # "bp": "0.016290",
1675
- # "bq": "135.37"
1676
- # }
1677
- #
1678
- marketId = self.safe_string(ticker, 's')
1679
- marketType = market['type'] if (market is not None) else None
1680
- if marketType is None:
1681
- marketType = ('cv' in ticker) or 'spot' if ('aq' in ticker) else 'contract'
1682
- market = self.safe_market(marketId, market, '_', marketType)
1683
- symbol = market['symbol']
1684
- timestamp = self.safe_integer(ticker, 't')
1685
- return self.safe_ticker({
1686
- 'symbol': symbol,
1687
- 'timestamp': timestamp,
1688
- 'datetime': self.iso8601(timestamp),
1689
- 'high': self.safe_number(ticker, 'h'),
1690
- 'low': self.safe_number(ticker, 'l'),
1691
- 'bid': self.safe_number(ticker, 'bp'),
1692
- 'bidVolume': self.safe_number(ticker, 'bq'),
1693
- 'ask': self.safe_number(ticker, 'ap'),
1694
- 'askVolume': self.safe_number(ticker, 'aq'),
1695
- 'vwap': None,
1696
- 'open': self.safe_string(ticker, 'o'),
1697
- 'close': self.safe_string(ticker, 'c'),
1698
- 'last': self.safe_string(ticker, 'c'),
1699
- 'previousClose': None,
1700
- 'change': self.safe_number(ticker, 'cv'),
1701
- 'percentage': self.safe_number_2(ticker, 'cr', 'r'),
1702
- 'average': None,
1703
- 'baseVolume': None,
1704
- 'quoteVolume': self.safe_number_2(ticker, 'a', 'v'),
1705
- 'info': ticker,
1706
- }, market)
1707
-
1708
- async def fetch_trades(self, symbol: str, since: Optional[int] = None, limit: Optional[int] = None, params={}):
1709
- """
1710
- get the list of most recent trades for a particular symbol
1711
- see https://doc.xt.com/#market5tradeRecent
1712
- see https://doc.xt.com/#futures_quotesgetDeal
1713
- :param str symbol: unified market symbol to fetch trades for
1714
- :param int|None since: timestamp in ms of the earliest trade to fetch
1715
- :param int|None limit: the maximum amount of trades to fetch
1716
- :param dict params: extra parameters specific to the xt api endpoint
1717
- :returns [dict]: a list of `trade structures <https://docs.ccxt.com/en/latest/manual.html?#public-trades>`
1718
- """
1719
- await self.load_markets()
1720
- market = self.market(symbol)
1721
- request = {
1722
- 'symbol': market['id'],
1723
- }
1724
- response = None
1725
- if market['spot']:
1726
- if limit is not None:
1727
- request['limit'] = limit
1728
- response = await self.publicSpotGetTradeRecent(self.extend(request, params))
1729
- else:
1730
- if limit is not None:
1731
- request['num'] = limit
1732
- if market['linear']:
1733
- response = await self.publicLinearGetFutureMarketV1PublicQDeal(self.extend(request, params))
1734
- elif market['inverse']:
1735
- response = await self.publicInverseGetFutureMarketV1PublicQDeal(self.extend(request, params))
1736
- #
1737
- # spot
1738
- #
1739
- # {
1740
- # "rc": 0,
1741
- # "mc": "SUCCESS",
1742
- # "ma": [],
1743
- # "result": [
1744
- # {
1745
- # "i": 203530723141917063,
1746
- # "t": 1678227505815,
1747
- # "p": "22038.81",
1748
- # "q": "0.000978",
1749
- # "v": "21.55395618",
1750
- # "b": True
1751
- # },
1752
- # ]
1753
- # }
1754
- #
1755
- # swap and future
1756
- #
1757
- # {
1758
- # "returnCode": 0,
1759
- # "msgInfo": "success",
1760
- # "error": null,
1761
- # "result": [
1762
- # {
1763
- # "t": 1678227683897,
1764
- # "s": "btc_usdt",
1765
- # "p": "22031",
1766
- # "a": "1067",
1767
- # "m": "BID"
1768
- # },
1769
- # ]
1770
- # }
1771
- #
1772
- trades = self.safe_value(response, 'result', [])
1773
- return self.parse_trades(trades, market)
1774
-
1775
- async def fetch_my_trades(self, symbol: Optional[str] = None, since: Optional[int] = None, limit: Optional[int] = None, params={}):
1776
- """
1777
- fetch all trades made by the user
1778
- see https://doc.xt.com/#tradetradeGet
1779
- see https://doc.xt.com/#futures_ordergetTrades
1780
- :param str|None symbol: unified market symbol to fetch trades for
1781
- :param int|None since: timestamp in ms of the earliest trade to fetch
1782
- :param int|None limit: the maximum amount of trades to fetch
1783
- :param dict params: extra parameters specific to the xt api endpoint
1784
- :returns [dict]: a list of `trade structures <https://docs.ccxt.com/en/latest/manual.html?#public-trades>`
1785
- """
1786
- await self.load_markets()
1787
- request = {}
1788
- market = None
1789
- if symbol is not None:
1790
- market = self.market(symbol)
1791
- request['symbol'] = market['id']
1792
- if since is not None:
1793
- request['startTime'] = since
1794
- type = None
1795
- subType = None
1796
- response = None
1797
- type, params = self.handle_market_type_and_params('fetchMyTrades', market, params)
1798
- subType, params = self.handle_sub_type_and_params('fetchMyTrades', market, params)
1799
- if (subType is not None) or (type == 'swap') or (type == 'future'):
1800
- if limit is not None:
1801
- request['size'] = limit
1802
- if subType == 'inverse':
1803
- response = await self.privateInverseGetFutureTradeV1OrderTradeList(self.extend(request, params))
1804
- else:
1805
- response = await self.privateLinearGetFutureTradeV1OrderTradeList(self.extend(request, params))
1806
- else:
1807
- marginMode = None
1808
- marginMode, params = self.handle_margin_mode_and_params('fetchMyTrades', params)
1809
- marginOrSpotRequest = 'LEVER' if (marginMode is not None) else 'SPOT'
1810
- request['bizType'] = marginOrSpotRequest
1811
- if limit is not None:
1812
- request['limit'] = limit
1813
- response = await self.privateSpotGetTrade(self.extend(request, params))
1814
- #
1815
- # spot and margin
1816
- #
1817
- # {
1818
- # "rc": 0,
1819
- # "mc": "SUCCESS",
1820
- # "ma": [],
1821
- # "result": {
1822
- # "hasPrev": False,
1823
- # "hasNext": False,
1824
- # "items": [
1825
- # {
1826
- # "symbol": "btc_usdt",
1827
- # "tradeId": "206906233569974658",
1828
- # "orderId": "206906233178463488",
1829
- # "orderSide": "SELL",
1830
- # "orderType": "MARKET",
1831
- # "bizType": "SPOT",
1832
- # "time": 1679032290215,
1833
- # "price": "25703.46",
1834
- # "quantity": "0.000099",
1835
- # "quoteQty": "2.54464254",
1836
- # "baseCurrency": "btc",
1837
- # "quoteCurrency": "usdt",
1838
- # "fee": "0.00508929",
1839
- # "feeCurrency": "usdt",
1840
- # "takerMaker": "TAKER"
1841
- # },
1842
- # ]
1843
- # }
1844
- # }
1845
- #
1846
- # swap and future
1847
- #
1848
- # {
1849
- # "returnCode": 0,
1850
- # "msgInfo": "success",
1851
- # "error": null,
1852
- # "result": {
1853
- # "page": 1,
1854
- # "ps": 10,
1855
- # "total": 2,
1856
- # "items": [
1857
- # {
1858
- # "orderId": "207260566170987200",
1859
- # "execId": "207260566790603265",
1860
- # "symbol": "btc_usdt",
1861
- # "quantity": "13",
1862
- # "price": "27368",
1863
- # "fee": "0.02134704",
1864
- # "feeCoin": "usdt",
1865
- # "timestamp": 1679116769838,
1866
- # "takerMaker": "TAKER"
1867
- # },
1868
- # ]
1869
- # }
1870
- # }
1871
- #
1872
- data = self.safe_value(response, 'result', {})
1873
- trades = self.safe_value(data, 'items', [])
1874
- return self.parse_trades(trades, market, since, limit)
1875
-
1876
- def parse_trade(self, trade, market=None):
1877
- #
1878
- # spot: fetchTrades
1879
- #
1880
- # {
1881
- # "i": 203530723141917063,
1882
- # "t": 1678227505815,
1883
- # "p": "22038.81",
1884
- # "q": "0.000978",
1885
- # "v": "21.55395618",
1886
- # "b": True
1887
- # }
1888
- #
1889
- # swap and future: fetchTrades
1890
- #
1891
- # {
1892
- # "t": 1678227683897,
1893
- # "s": "btc_usdt",
1894
- # "p": "22031",
1895
- # "a": "1067",
1896
- # "m": "BID"
1897
- # }
1898
- #
1899
- # spot: fetchMyTrades
1900
- #
1901
- # {
1902
- # "symbol": "btc_usdt",
1903
- # "tradeId": "206906233569974658",
1904
- # "orderId": "206906233178463488",
1905
- # "orderSide": "SELL",
1906
- # "orderType": "MARKET",
1907
- # "bizType": "SPOT",
1908
- # "time": 1679032290215,
1909
- # "price": "25703.46",
1910
- # "quantity": "0.000099",
1911
- # "quoteQty": "2.54464254",
1912
- # "baseCurrency": "btc",
1913
- # "quoteCurrency": "usdt",
1914
- # "fee": "0.00508929",
1915
- # "feeCurrency": "usdt",
1916
- # "takerMaker": "TAKER"
1917
- # }
1918
- #
1919
- # swap and future: fetchMyTrades
1920
- #
1921
- # {
1922
- # "orderId": "207260566170987200",
1923
- # "execId": "207260566790603265",
1924
- # "symbol": "btc_usdt",
1925
- # "quantity": "13",
1926
- # "price": "27368",
1927
- # "fee": "0.02134704",
1928
- # "feeCoin": "usdt",
1929
- # "timestamp": 1679116769838,
1930
- # "takerMaker": "TAKER"
1931
- # }
1932
- #
1933
- marketId = self.safe_string_2(trade, 's', 'symbol')
1934
- marketType = market['type'] if (market is not None) else None
1935
- if marketType is None:
1936
- marketType = ('b' in trade) or 'spot' if ('bizType' in trade) else 'contract'
1937
- market = self.safe_market(marketId, market, '_', marketType)
1938
- bidOrAsk = self.safe_string(trade, 'm')
1939
- side = self.safe_string_lower(trade, 'orderSide')
1940
- if bidOrAsk is not None:
1941
- side = 'buy' if (bidOrAsk == 'BID') else 'sell'
1942
- buyerMaker = self.safe_value(trade, 'b')
1943
- takerOrMaker = self.safe_string_lower(trade, 'takerMaker')
1944
- if buyerMaker is not None:
1945
- takerOrMaker = 'maker' if buyerMaker else 'taker'
1946
- timestamp = self.safe_integer_n(trade, ['t', 'time', 'timestamp'])
1947
- quantity = self.safe_string_2(trade, 'q', 'quantity')
1948
- amount = None
1949
- if marketType == 'spot':
1950
- amount = quantity
1951
- else:
1952
- if quantity is None:
1953
- amount = Precise.string_mul(self.safe_string(trade, 'a'), self.number_to_string(market['contractSize']))
1954
- else:
1955
- amount = Precise.string_mul(quantity, self.number_to_string(market['contractSize']))
1956
- return self.safe_trade({
1957
- 'info': trade,
1958
- 'id': self.safe_string_n(trade, ['i', 'tradeId', 'execId']),
1959
- 'timestamp': timestamp,
1960
- 'datetime': self.iso8601(timestamp),
1961
- 'symbol': market['symbol'],
1962
- 'order': self.safe_string(trade, 'orderId'),
1963
- 'type': self.safe_string_lower(trade, 'orderType'),
1964
- 'side': side,
1965
- 'takerOrMaker': takerOrMaker,
1966
- 'price': self.safe_string_2(trade, 'p', 'price'),
1967
- 'amount': amount,
1968
- 'cost': None,
1969
- 'fee': {
1970
- 'currency': self.safe_currency_code(self.safe_string_2(trade, 'feeCurrency', 'feeCoin')),
1971
- 'cost': self.safe_string(trade, 'fee'),
1972
- 'rate': None,
1973
- },
1974
- }, market)
1975
-
1976
- async def fetch_balance(self, params={}):
1977
- """
1978
- query for balance and get the amount of funds available for trading or funds locked in orders
1979
- see https://doc.xt.com/#balancebalancesGet
1980
- see https://doc.xt.com/#futures_usergetBalances
1981
- :param dict params: extra parameters specific to the xt api endpoint
1982
- :returns dict: a `balance structure <https://docs.ccxt.com/en/latest/manual.html?#balance-structure>`
1983
- """
1984
- await self.load_markets()
1985
- type = None
1986
- subType = None
1987
- response = None
1988
- type, params = self.handle_market_type_and_params('fetchBalance', None, params)
1989
- subType, params = self.handle_sub_type_and_params('fetchBalance', None, params)
1990
- isContractWallet = ((type == 'swap') or (type == 'future'))
1991
- if subType == 'inverse':
1992
- response = await self.privateInverseGetFutureUserV1BalanceList(params)
1993
- elif (subType == 'linear') or isContractWallet:
1994
- response = await self.privateLinearGetFutureUserV1BalanceList(params)
1995
- else:
1996
- response = await self.privateSpotGetBalances(params)
1997
- #
1998
- # spot
1999
- #
2000
- # {
2001
- # "rc": 0,
2002
- # "mc": "SUCCESS",
2003
- # "ma": [],
2004
- # "result": {
2005
- # "totalUsdtAmount": "31.75931133",
2006
- # "totalBtcAmount": "0.00115951",
2007
- # "assets": [
2008
- # {
2009
- # "currency": "usdt",
2010
- # "currencyId": 11,
2011
- # "frozenAmount": "0.03834082",
2012
- # "availableAmount": "31.70995965",
2013
- # "totalAmount": "31.74830047",
2014
- # "convertBtcAmount": "0.00115911",
2015
- # "convertUsdtAmount": "31.74830047"
2016
- # },
2017
- # ]
2018
- # }
2019
- # }
2020
- #
2021
- # swap and future
2022
- #
2023
- # {
2024
- # "returnCode": 0,
2025
- # "msgInfo": "success",
2026
- # "error": null,
2027
- # "result": [
2028
- # {
2029
- # "coin": "usdt",
2030
- # "walletBalance": "19.29849875",
2031
- # "openOrderMarginFrozen": "0",
2032
- # "isolatedMargin": "0.709475",
2033
- # "crossedMargin": "0",
2034
- # "availableBalance": "18.58902375",
2035
- # "bonus": "0",
2036
- # "coupon":"0"
2037
- # }
2038
- # ]
2039
- # }
2040
- #
2041
- balances = None
2042
- if (subType is not None) or isContractWallet:
2043
- balances = self.safe_value(response, 'result', [])
2044
- else:
2045
- data = self.safe_value(response, 'result', {})
2046
- balances = self.safe_value(data, 'assets', [])
2047
- return self.parse_balance(balances)
2048
-
2049
- def parse_balance(self, response):
2050
- #
2051
- # spot
2052
- #
2053
- # {
2054
- # "currency": "usdt",
2055
- # "currencyId": 11,
2056
- # "frozenAmount": "0.03834082",
2057
- # "availableAmount": "31.70995965",
2058
- # "totalAmount": "31.74830047",
2059
- # "convertBtcAmount": "0.00115911",
2060
- # "convertUsdtAmount": "31.74830047"
2061
- # }
2062
- #
2063
- # swap and future
2064
- #
2065
- # {
2066
- # "coin": "usdt",
2067
- # "walletBalance": "19.29849875",
2068
- # "openOrderMarginFrozen": "0",
2069
- # "isolatedMargin": "0.709475",
2070
- # "crossedMargin": "0",
2071
- # "availableBalance": "18.58902375",
2072
- # "bonus": "0",
2073
- # "coupon":"0"
2074
- # }
2075
- #
2076
- result = {'info': response}
2077
- for i in range(0, len(response)):
2078
- balance = response[i]
2079
- currencyId = self.safe_string_2(balance, 'currency', 'coin')
2080
- code = self.safe_currency_code(currencyId)
2081
- account = self.account()
2082
- free = self.safe_string_2(balance, 'availableAmount', 'availableBalance')
2083
- used = self.safe_string(balance, 'frozenAmount')
2084
- total = self.safe_string_2(balance, 'totalAmount', 'walletBalance')
2085
- if used is None:
2086
- crossedAndIsolatedMargin = Precise.string_add(self.safe_string(balance, 'crossedMargin'), self.safe_string(balance, 'isolatedMargin'))
2087
- used = Precise.string_add(self.safe_string(balance, 'openOrderMarginFrozen'), crossedAndIsolatedMargin)
2088
- account['free'] = free
2089
- account['used'] = used
2090
- account['total'] = total
2091
- result[code] = account
2092
- return self.safe_balance(result)
2093
-
2094
- async def create_order(self, symbol: str, type, side, amount, price=None, params={}):
2095
- """
2096
- create a trade order
2097
- see https://doc.xt.com/#orderorderPost
2098
- see https://doc.xt.com/#futures_ordercreate
2099
- see https://doc.xt.com/#futures_entrustcreatePlan
2100
- see https://doc.xt.com/#futures_entrustcreateProfit
2101
- :param str symbol: unified symbol of the market to create an order in
2102
- :param str type: 'market' or 'limit'
2103
- :param str side: 'buy' or 'sell'
2104
- :param float amount: how much you want to trade in units of the base currency
2105
- :param float|None price: the price to fulfill the order, in units of the quote currency, can be ignored in market orders
2106
- :param dict params: extra parameters specific to the xt api endpoint
2107
- :param str|None params['timeInForce']: 'GTC', 'IOC', 'FOK' or 'GTX'
2108
- :param str|None params['entrustType']: 'TAKE_PROFIT', 'STOP', 'TAKE_PROFIT_MARKET', 'STOP_MARKET', 'TRAILING_STOP_MARKET', required if stopPrice is defined, currently isn't functioning on xt's side
2109
- :param str|None params['triggerPriceType']: 'INDEX_PRICE', 'MARK_PRICE', 'LATEST_PRICE', required if stopPrice is defined
2110
- :param float|None params['stopPrice']: price to trigger a stop order
2111
- :param float|None params['stopLoss']: price to set a stop-loss on an open position
2112
- :param float|None params['takeProfit']: price to set a take-profit on an open position
2113
- :returns dict: an `order structure <https://docs.ccxt.com/en/latest/manual.html#order-structure>`
2114
- """
2115
- await self.load_markets()
2116
- market = self.market(symbol)
2117
- symbol = market['symbol']
2118
- if market['spot']:
2119
- return await self.create_spot_order(symbol, type, side, amount, price, params)
2120
- else:
2121
- return await self.create_contract_order(symbol, type, side, amount, price, params)
2122
-
2123
- async def create_spot_order(self, symbol: str, type, side, amount, price=None, params={}):
2124
- await self.load_markets()
2125
- market = self.market(symbol)
2126
- request = {
2127
- 'symbol': market['id'],
2128
- 'side': side.upper(),
2129
- 'type': type.upper(),
2130
- }
2131
- timeInForce = None
2132
- marginMode = None
2133
- marginMode, params = self.handle_margin_mode_and_params('createOrder', params)
2134
- marginOrSpotRequest = 'LEVER' if (marginMode is not None) else 'SPOT'
2135
- request['bizType'] = marginOrSpotRequest
2136
- if type == 'market':
2137
- timeInForce = self.safe_string_upper(params, 'timeInForce', 'FOK')
2138
- if side == 'buy':
2139
- createMarketBuyOrderRequiresPrice = self.safe_value(self.options, 'createMarketBuyOrderRequiresPrice', True)
2140
- if createMarketBuyOrderRequiresPrice:
2141
- if price is None:
2142
- raise InvalidOrder(self.id + ' createOrder() requires a price argument for market buy orders on spot markets to calculate the total amount to spend(amount * price), alternatively set the createMarketBuyOrderRequiresPrice option to False and pass in the cost to spend into the amount parameter')
2143
- else:
2144
- amountString = self.number_to_string(amount)
2145
- priceString = self.number_to_string(price)
2146
- cost = self.parse_number(Precise.string_mul(amountString, priceString))
2147
- request['quoteQty'] = self.cost_to_precision(symbol, cost)
2148
- else:
2149
- request['quoteQty'] = self.amount_to_precision(symbol, amount)
2150
- else:
2151
- timeInForce = self.safe_string_upper(params, 'timeInForce', 'GTC')
2152
- request['price'] = self.price_to_precision(symbol, price)
2153
- if (side == 'sell') or (type == 'limit'):
2154
- request['quantity'] = self.amount_to_precision(symbol, amount)
2155
- request['timeInForce'] = timeInForce
2156
- response = await self.privateSpotPostOrder(self.extend(request, params))
2157
- #
2158
- # {
2159
- # "rc": 0,
2160
- # "mc": "SUCCESS",
2161
- # "ma": [],
2162
- # "result": {
2163
- # "orderId": "204371980095156544"
2164
- # }
2165
- # }
2166
- #
2167
- order = self.safe_value(response, 'result', {})
2168
- return self.parse_order(order, market)
2169
-
2170
- async def create_contract_order(self, symbol: str, type, side, amount, price=None, params={}):
2171
- await self.load_markets()
2172
- market = self.market(symbol)
2173
- request = {
2174
- 'symbol': market['id'],
2175
- 'origQty': self.amount_to_precision(symbol, amount),
2176
- }
2177
- timeInForce = self.safe_string_upper(params, 'timeInForce')
2178
- if timeInForce is not None:
2179
- request['timeInForce'] = timeInForce
2180
- reduceOnly = self.safe_value(params, 'reduceOnly', False)
2181
- if side == 'buy':
2182
- requestType = 'SHORT' if (reduceOnly) else 'LONG'
2183
- request['positionSide'] = requestType
2184
- else:
2185
- requestType = 'LONG' if (reduceOnly) else 'SHORT'
2186
- request['positionSide'] = requestType
2187
- response = None
2188
- triggerPrice = self.safe_number_2(params, 'triggerPrice', 'stopPrice')
2189
- stopLoss = self.safe_number_2(params, 'stopLoss', 'triggerStopPrice')
2190
- takeProfit = self.safe_number_2(params, 'takeProfit', 'triggerProfitPrice')
2191
- isTrigger = (triggerPrice is not None)
2192
- isStopLoss = (stopLoss is not None)
2193
- isTakeProfit = (takeProfit is not None)
2194
- if price is not None:
2195
- if not (isStopLoss) and not (isTakeProfit):
2196
- request['price'] = self.price_to_precision(symbol, price)
2197
- if isTrigger:
2198
- request['timeInForce'] = self.safe_string_upper(params, 'timeInForce', 'GTC')
2199
- request['triggerPriceType'] = self.safe_string(params, 'triggerPriceType', 'LATEST_PRICE')
2200
- request['orderSide'] = side.upper()
2201
- request['stopPrice'] = self.price_to_precision(symbol, triggerPrice)
2202
- entrustType = 'STOP_MARKET' if (type == 'market') else 'STOP'
2203
- request['entrustType'] = entrustType
2204
- params = self.omit(params, 'triggerPrice')
2205
- if market['linear']:
2206
- response = await self.privateLinearPostFutureTradeV1EntrustCreatePlan(self.extend(request, params))
2207
- elif market['inverse']:
2208
- response = await self.privateInversePostFutureTradeV1EntrustCreatePlan(self.extend(request, params))
2209
- elif isStopLoss or isTakeProfit:
2210
- if isStopLoss:
2211
- request['triggerStopPrice'] = self.price_to_precision(symbol, stopLoss)
2212
- else:
2213
- request['triggerProfitPrice'] = self.price_to_precision(symbol, takeProfit)
2214
- params = self.omit(params, ['stopLoss', 'takeProfit'])
2215
- if market['linear']:
2216
- response = await self.privateLinearPostFutureTradeV1EntrustCreateProfit(self.extend(request, params))
2217
- elif market['inverse']:
2218
- response = await self.privateInversePostFutureTradeV1EntrustCreateProfit(self.extend(request, params))
2219
- else:
2220
- request['orderSide'] = side.upper()
2221
- request['orderType'] = type.upper()
2222
- if market['linear']:
2223
- response = await self.privateLinearPostFutureTradeV1OrderCreate(self.extend(request, params))
2224
- elif market['inverse']:
2225
- response = await self.privateInversePostFutureTradeV1OrderCreate(self.extend(request, params))
2226
- #
2227
- # {
2228
- # "returnCode": 0,
2229
- # "msgInfo": "success",
2230
- # "error": null,
2231
- # "result": "206410760006650176"
2232
- # }
2233
- #
2234
- return self.parse_order(response, market)
2235
-
2236
- async def fetch_order(self, id: str, symbol: Optional[str] = None, params={}):
2237
- """
2238
- fetches information on an order made by the user
2239
- see https://doc.xt.com/#orderorderGet
2240
- see https://doc.xt.com/#futures_ordergetById
2241
- see https://doc.xt.com/#futures_entrustgetPlanById
2242
- see https://doc.xt.com/#futures_entrustgetProfitById
2243
- :param str id: order id
2244
- :param str|None symbol: unified symbol of the market the order was made in
2245
- :param dict params: extra parameters specific to the xt api endpoint
2246
- :param bool|None params['stop']: if the order is a stop trigger order or not
2247
- :param bool|None params['stopLossTakeProfit']: if the order is a stop-loss or take-profit order
2248
- :returns dict: An `order structure <https://docs.ccxt.com/en/latest/manual.html#order-structure>`
2249
- """
2250
- await self.load_markets()
2251
- market = None
2252
- if symbol is not None:
2253
- market = self.market(symbol)
2254
- request = {}
2255
- type = None
2256
- subType = None
2257
- response = None
2258
- type, params = self.handle_market_type_and_params('fetchOrder', market, params)
2259
- subType, params = self.handle_sub_type_and_params('fetchOrder', market, params)
2260
- stop = self.safe_value(params, 'stop')
2261
- stopLossTakeProfit = self.safe_value(params, 'stopLossTakeProfit')
2262
- if stop:
2263
- request['entrustId'] = id
2264
- elif stopLossTakeProfit:
2265
- request['profitId'] = id
2266
- else:
2267
- request['orderId'] = id
2268
- if stop:
2269
- params = self.omit(params, 'stop')
2270
- if subType == 'inverse':
2271
- response = await self.privateInverseGetFutureTradeV1EntrustPlanDetail(self.extend(request, params))
2272
- else:
2273
- response = await self.privateLinearGetFutureTradeV1EntrustPlanDetail(self.extend(request, params))
2274
- elif stopLossTakeProfit:
2275
- params = self.omit(params, 'stopLossTakeProfit')
2276
- if subType == 'inverse':
2277
- response = await self.privateInverseGetFutureTradeV1EntrustProfitDetail(self.extend(request, params))
2278
- else:
2279
- response = await self.privateLinearGetFutureTradeV1EntrustProfitDetail(self.extend(request, params))
2280
- elif subType == 'inverse':
2281
- response = await self.privateInverseGetFutureTradeV1OrderDetail(self.extend(request, params))
2282
- elif (subType == 'linear') or (type == 'swap') or (type == 'future'):
2283
- response = await self.privateLinearGetFutureTradeV1OrderDetail(self.extend(request, params))
2284
- else:
2285
- response = await self.privateSpotGetOrderOrderId(self.extend(request, params))
2286
- #
2287
- # spot
2288
- #
2289
- # {
2290
- # "rc": 0,
2291
- # "mc": "SUCCESS",
2292
- # "ma": [],
2293
- # "result": {
2294
- # "symbol": "btc_usdt",
2295
- # "orderId": "207505997850909952",
2296
- # "clientOrderId": null,
2297
- # "baseCurrency": "btc",
2298
- # "quoteCurrency": "usdt",
2299
- # "side": "BUY",
2300
- # "type": "LIMIT",
2301
- # "timeInForce": "GTC",
2302
- # "price": "20000.00",
2303
- # "origQty": "0.001000",
2304
- # "origQuoteQty": "20.00",
2305
- # "executedQty": "0.000000",
2306
- # "leavingQty": "0.001000",
2307
- # "tradeBase": "0.000000",
2308
- # "tradeQuote": "0.00",
2309
- # "avgPrice": null,
2310
- # "fee": null,
2311
- # "feeCurrency": null,
2312
- # "closed": False,
2313
- # "state": "NEW",
2314
- # "time": 1679175285162,
2315
- # "updatedTime": 1679175285255
2316
- # }
2317
- # }
2318
- #
2319
- # swap and future
2320
- #
2321
- # {
2322
- # "returnCode": 0,
2323
- # "msgInfo": "success",
2324
- # "error": null,
2325
- # "result": {
2326
- # "orderId": "211451874783183936",
2327
- # "clientOrderId": null,
2328
- # "symbol": "btc_usdt",
2329
- # "orderType": "LIMIT",
2330
- # "orderSide": "BUY",
2331
- # "positionSide": "LONG",
2332
- # "timeInForce": "GTC",
2333
- # "closePosition": False,
2334
- # "price": "20000",
2335
- # "origQty": "10",
2336
- # "avgPrice": "0",
2337
- # "executedQty": "0",
2338
- # "marginFrozen": "1.34533334",
2339
- # "remark": null,
2340
- # "triggerProfitPrice": null,
2341
- # "triggerStopPrice": null,
2342
- # "sourceId": null,
2343
- # "sourceType": "DEFAULT",
2344
- # "forceClose": False,
2345
- # "closeProfit": null,
2346
- # "state": "NEW",
2347
- # "createdTime": 1680116055693,
2348
- # "updatedTime": 1680116055693
2349
- # }
2350
- # }
2351
- #
2352
- # trigger
2353
- #
2354
- # {
2355
- # "returnCode": 0,
2356
- # "msgInfo": "success",
2357
- # "error": null,
2358
- # "result": {
2359
- # "entrustId": "216300248132756992",
2360
- # "symbol": "btc_usdt",
2361
- # "entrustType": "STOP",
2362
- # "orderSide": "SELL",
2363
- # "positionSide": "SHORT",
2364
- # "timeInForce": "GTC",
2365
- # "closePosition": null,
2366
- # "price": "20000",
2367
- # "origQty": "1",
2368
- # "stopPrice": "19000",
2369
- # "triggerPriceType": "LATEST_PRICE",
2370
- # "state": "NOT_TRIGGERED",
2371
- # "marketOrderLevel": null,
2372
- # "createdTime": 1681271998064,
2373
- # "updatedTime": 1681271998064,
2374
- # "ordinary": False
2375
- # }
2376
- # }
2377
- #
2378
- # stop-loss and take-profit
2379
- #
2380
- # {
2381
- # "returnCode": 0,
2382
- # "msgInfo": "success",
2383
- # "error": null,
2384
- # "result": {
2385
- # "profitId": "216306213226230400",
2386
- # "symbol": "btc_usdt",
2387
- # "positionSide": "LONG",
2388
- # "origQty": "1",
2389
- # "triggerPriceType": "LATEST_PRICE",
2390
- # "triggerProfitPrice": null,
2391
- # "triggerStopPrice": "20000",
2392
- # "entryPrice": null,
2393
- # "positionSize": null,
2394
- # "isolatedMargin": null,
2395
- # "executedQty": null,
2396
- # "avgPrice": null,
2397
- # "positionType": "ISOLATED",
2398
- # "state": "NOT_TRIGGERED",
2399
- # "createdTime": 1681273420039
2400
- # }
2401
- # }
2402
- #
2403
- order = self.safe_value(response, 'result', {})
2404
- return self.parse_order(order, market)
2405
-
2406
- async def fetch_orders(self, symbol: Optional[str] = None, since: Optional[int] = None, limit: Optional[int] = None, params={}):
2407
- """
2408
- fetches information on multiple orders made by the user
2409
- see https://doc.xt.com/#orderhistoryOrderGet
2410
- see https://doc.xt.com/#futures_ordergetHistory
2411
- see https://doc.xt.com/#futures_entrustgetPlanHistory
2412
- :param str|None symbol: unified market symbol of the market the orders were made in
2413
- :param int|None since: timestamp in ms of the earliest order
2414
- :param int|None limit: the maximum number of order structures to retrieve
2415
- :param dict params: extra parameters specific to the xt api endpoint
2416
- :param bool|None params['stop']: if the order is a stop trigger order or not
2417
- :returns [dict]: a list of `order structures <https://docs.ccxt.com/en/latest/manual.html#order-structure>`
2418
- """
2419
- await self.load_markets()
2420
- request = {}
2421
- market = None
2422
- if symbol is not None:
2423
- market = self.market(symbol)
2424
- request['symbol'] = market['id']
2425
- if since is not None:
2426
- request['startTime'] = since
2427
- if limit is not None:
2428
- request['limit'] = limit
2429
- type = None
2430
- subType = None
2431
- response = None
2432
- type, params = self.handle_market_type_and_params('fetchOrders', market, params)
2433
- subType, params = self.handle_sub_type_and_params('fetchOrders', market, params)
2434
- stop = self.safe_value(params, 'stop')
2435
- if stop:
2436
- params = self.omit(params, 'stop')
2437
- if subType == 'inverse':
2438
- response = await self.privateInverseGetFutureTradeV1EntrustPlanListHistory(self.extend(request, params))
2439
- else:
2440
- response = await self.privateLinearGetFutureTradeV1EntrustPlanListHistory(self.extend(request, params))
2441
- elif subType == 'inverse':
2442
- response = await self.privateInverseGetFutureTradeV1OrderListHistory(self.extend(request, params))
2443
- elif (subType == 'linear') or (type == 'swap') or (type == 'future'):
2444
- response = await self.privateLinearGetFutureTradeV1OrderListHistory(self.extend(request, params))
2445
- else:
2446
- marginMode = None
2447
- marginMode, params = self.handle_margin_mode_and_params('fetchOrders', params)
2448
- marginOrSpotRequest = 'LEVER' if (marginMode is not None) else 'SPOT'
2449
- request['bizType'] = marginOrSpotRequest
2450
- response = await self.privateSpotGetHistoryOrder(self.extend(request, params))
2451
- #
2452
- # spot and margin
2453
- #
2454
- # {
2455
- # "rc": 0,
2456
- # "mc": "SUCCESS",
2457
- # "ma": [],
2458
- # "result": {
2459
- # "hasPrev": False,
2460
- # "hasNext": True,
2461
- # "items": [
2462
- # {
2463
- # "symbol": "btc_usdt",
2464
- # "orderId": "207505997850909952",
2465
- # "clientOrderId": null,
2466
- # "baseCurrency": "btc",
2467
- # "quoteCurrency": "usdt",
2468
- # "side": "BUY",
2469
- # "type": "LIMIT",
2470
- # "timeInForce": "GTC",
2471
- # "price": "20000.00",
2472
- # "origQty": "0.001000",
2473
- # "origQuoteQty": "20.00",
2474
- # "executedQty": "0.000000",
2475
- # "leavingQty": "0.000000",
2476
- # "tradeBase": "0.000000",
2477
- # "tradeQuote": "0.00",
2478
- # "avgPrice": null,
2479
- # "fee": null,
2480
- # "feeCurrency": null,
2481
- # "closed": True,
2482
- # "state": "CANCELED",
2483
- # "time": 1679175285162,
2484
- # "updatedTime": 1679175488492
2485
- # },
2486
- # ]
2487
- # }
2488
- # }
2489
- #
2490
- # swap and future
2491
- #
2492
- # {
2493
- # "returnCode": 0,
2494
- # "msgInfo": "success",
2495
- # "error": null,
2496
- # "result": {
2497
- # "hasPrev": False,
2498
- # "hasNext": True,
2499
- # "items": [
2500
- # {
2501
- # "orderId": "207519546930995456",
2502
- # "clientOrderId": null,
2503
- # "symbol": "btc_usdt",
2504
- # "orderType": "LIMIT",
2505
- # "orderSide": "BUY",
2506
- # "positionSide": "LONG",
2507
- # "timeInForce": "GTC",
2508
- # "closePosition": False,
2509
- # "price": "20000",
2510
- # "origQty": "100",
2511
- # "avgPrice": "0",
2512
- # "executedQty": "0",
2513
- # "marginFrozen": "4.12",
2514
- # "remark": null,
2515
- # "triggerProfitPrice": null,
2516
- # "triggerStopPrice": null,
2517
- # "sourceId": null,
2518
- # "sourceType": "DEFAULT",
2519
- # "forceClose": False,
2520
- # "closeProfit": null,
2521
- # "state": "CANCELED",
2522
- # "createdTime": 1679178515689,
2523
- # "updatedTime": 1679180096172
2524
- # },
2525
- # ]
2526
- # }
2527
- # }
2528
- #
2529
- # stop
2530
- #
2531
- # {
2532
- # "returnCode": 0,
2533
- # "msgInfo": "success",
2534
- # "error": null,
2535
- # "result": {
2536
- # "hasPrev": False,
2537
- # "hasNext": False,
2538
- # "items": [
2539
- # {
2540
- # "entrustId": "216300248132756992",
2541
- # "symbol": "btc_usdt",
2542
- # "entrustType": "STOP",
2543
- # "orderSide": "SELL",
2544
- # "positionSide": "SHORT",
2545
- # "timeInForce": "GTC",
2546
- # "closePosition": null,
2547
- # "price": "20000",
2548
- # "origQty": "1",
2549
- # "stopPrice": "19000",
2550
- # "triggerPriceType": "LATEST_PRICE",
2551
- # "state": "USER_REVOCATION",
2552
- # "marketOrderLevel": null,
2553
- # "createdTime": 1681271998064,
2554
- # "updatedTime": 1681273188674,
2555
- # "ordinary": False
2556
- # },
2557
- # ]
2558
- # }
2559
- # }
2560
- #
2561
- data = self.safe_value(response, 'result', {})
2562
- orders = self.safe_value(data, 'items', [])
2563
- return self.parse_orders(orders, market, since, limit)
2564
-
2565
- async def fetch_orders_by_status(self, status, symbol: Optional[str] = None, since: Optional[int] = None, limit: Optional[int] = None, params={}):
2566
- await self.load_markets()
2567
- request = {}
2568
- market = None
2569
- if symbol is not None:
2570
- market = self.market(symbol)
2571
- request['symbol'] = market['id']
2572
- type = None
2573
- subType = None
2574
- response = None
2575
- type, params = self.handle_market_type_and_params('fetchOrdersByStatus', market, params)
2576
- subType, params = self.handle_sub_type_and_params('fetchOrdersByStatus', market, params)
2577
- stop = self.safe_value(params, 'stop')
2578
- stopLossTakeProfit = self.safe_value(params, 'stopLossTakeProfit')
2579
- if status == 'open':
2580
- if stop or stopLossTakeProfit:
2581
- request['state'] = 'NOT_TRIGGERED'
2582
- elif subType is not None:
2583
- request['state'] = 'NEW'
2584
- elif status == 'closed':
2585
- if stop or stopLossTakeProfit:
2586
- request['state'] = 'TRIGGERED'
2587
- else:
2588
- request['state'] = 'FILLED'
2589
- elif status == 'canceled':
2590
- if stop or stopLossTakeProfit:
2591
- request['state'] = 'USER_REVOCATION'
2592
- else:
2593
- request['state'] = 'CANCELED'
2594
- else:
2595
- request['state'] = status
2596
- if stop or stopLossTakeProfit or (subType is not None) or (type == 'swap') or (type == 'future'):
2597
- if since is not None:
2598
- request['startTime'] = since
2599
- if limit is not None:
2600
- request['size'] = limit
2601
- if stop:
2602
- params = self.omit(params, 'stop')
2603
- if subType == 'inverse':
2604
- response = await self.privateInverseGetFutureTradeV1EntrustPlanList(self.extend(request, params))
2605
- else:
2606
- response = await self.privateLinearGetFutureTradeV1EntrustPlanList(self.extend(request, params))
2607
- elif stopLossTakeProfit:
2608
- params = self.omit(params, 'stopLossTakeProfit')
2609
- if subType == 'inverse':
2610
- response = await self.privateInverseGetFutureTradeV1EntrustProfitList(self.extend(request, params))
2611
- else:
2612
- response = await self.privateLinearGetFutureTradeV1EntrustProfitList(self.extend(request, params))
2613
- elif (subType is not None) or (type == 'swap') or (type == 'future'):
2614
- if subType == 'inverse':
2615
- response = await self.privateInverseGetFutureTradeV1OrderList(self.extend(request, params))
2616
- else:
2617
- response = await self.privateLinearGetFutureTradeV1OrderList(self.extend(request, params))
2618
- else:
2619
- marginMode = None
2620
- marginMode, params = self.handle_margin_mode_and_params('fetchOrdersByStatus', params)
2621
- marginOrSpotRequest = 'LEVER' if (marginMode is not None) else 'SPOT'
2622
- request['bizType'] = marginOrSpotRequest
2623
- if status != 'open':
2624
- if since is not None:
2625
- request['startTime'] = since
2626
- if limit is not None:
2627
- request['limit'] = limit
2628
- response = await self.privateSpotGetHistoryOrder(self.extend(request, params))
2629
- else:
2630
- response = await self.privateSpotGetOpenOrder(self.extend(request, params))
2631
- #
2632
- # spot and margin
2633
- #
2634
- # {
2635
- # "rc": 0,
2636
- # "mc": "SUCCESS",
2637
- # "ma": [],
2638
- # "result": {
2639
- # "hasPrev": False,
2640
- # "hasNext": True,
2641
- # "items": [
2642
- # {
2643
- # "symbol": "btc_usdt",
2644
- # "orderId": "207505997850909952",
2645
- # "clientOrderId": null,
2646
- # "baseCurrency": "btc",
2647
- # "quoteCurrency": "usdt",
2648
- # "side": "BUY",
2649
- # "type": "LIMIT",
2650
- # "timeInForce": "GTC",
2651
- # "price": "20000.00",
2652
- # "origQty": "0.001000",
2653
- # "origQuoteQty": "20.00",
2654
- # "executedQty": "0.000000",
2655
- # "leavingQty": "0.000000",
2656
- # "tradeBase": "0.000000",
2657
- # "tradeQuote": "0.00",
2658
- # "avgPrice": null,
2659
- # "fee": null,
2660
- # "feeCurrency": null,
2661
- # "closed": True,
2662
- # "state": "CANCELED",
2663
- # "time": 1679175285162,
2664
- # "updatedTime": 1679175488492
2665
- # },
2666
- # ]
2667
- # }
2668
- # }
2669
- #
2670
- # spot and margin: fetchOpenOrders
2671
- #
2672
- # {
2673
- # "rc": 0,
2674
- # "mc": "SUCCESS",
2675
- # "ma": [],
2676
- # "result": [
2677
- # {
2678
- # "symbol": "eth_usdt",
2679
- # "orderId": "208249323222264320",
2680
- # "clientOrderId": null,
2681
- # "baseCurrency": "eth",
2682
- # "quoteCurrency": "usdt",
2683
- # "side": "BUY",
2684
- # "type": "LIMIT",
2685
- # "timeInForce": "GTC",
2686
- # "price": "1300.00",
2687
- # "origQty": "0.0032",
2688
- # "origQuoteQty": "4.16",
2689
- # "executedQty": "0.0000",
2690
- # "leavingQty": "0.0032",
2691
- # "tradeBase": "0.0000",
2692
- # "tradeQuote": "0.00",
2693
- # "avgPrice": null,
2694
- # "fee": null,
2695
- # "feeCurrency": null,
2696
- # "closed": False,
2697
- # "state": "NEW",
2698
- # "time": 1679352507741,
2699
- # "updatedTime": 1679352507869
2700
- # },
2701
- # ]
2702
- # }
2703
- #
2704
- # swap and future
2705
- #
2706
- # {
2707
- # "returnCode": 0,
2708
- # "msgInfo": "success",
2709
- # "error": null,
2710
- # "result": {
2711
- # "page": 1,
2712
- # "ps": 10,
2713
- # "total": 25,
2714
- # "items": [
2715
- # {
2716
- # "orderId": "207519546930995456",
2717
- # "clientOrderId": null,
2718
- # "symbol": "btc_usdt",
2719
- # "orderType": "LIMIT",
2720
- # "orderSide": "BUY",
2721
- # "positionSide": "LONG",
2722
- # "timeInForce": "GTC",
2723
- # "closePosition": False,
2724
- # "price": "20000",
2725
- # "origQty": "100",
2726
- # "avgPrice": "0",
2727
- # "executedQty": "0",
2728
- # "marginFrozen": "4.12",
2729
- # "remark": null,
2730
- # "triggerProfitPrice": null,
2731
- # "triggerStopPrice": null,
2732
- # "sourceId": null,
2733
- # "sourceType": "DEFAULT",
2734
- # "forceClose": False,
2735
- # "closeProfit": null,
2736
- # "state": "CANCELED",
2737
- # "createdTime": 1679178515689,
2738
- # "updatedTime": 1679180096172
2739
- # },
2740
- # ]
2741
- # }
2742
- # }
2743
- #
2744
- # stop
2745
- #
2746
- # {
2747
- # "returnCode": 0,
2748
- # "msgInfo": "success",
2749
- # "error": null,
2750
- # "result": {
2751
- # "page": 1,
2752
- # "ps": 3,
2753
- # "total": 8,
2754
- # "items": [
2755
- # {
2756
- # "entrustId": "216300248132756992",
2757
- # "symbol": "btc_usdt",
2758
- # "entrustType": "STOP",
2759
- # "orderSide": "SELL",
2760
- # "positionSide": "SHORT",
2761
- # "timeInForce": "GTC",
2762
- # "closePosition": null,
2763
- # "price": "20000",
2764
- # "origQty": "1",
2765
- # "stopPrice": "19000",
2766
- # "triggerPriceType": "LATEST_PRICE",
2767
- # "state": "USER_REVOCATION",
2768
- # "marketOrderLevel": null,
2769
- # "createdTime": 1681271998064,
2770
- # "updatedTime": 1681273188674,
2771
- # "ordinary": False
2772
- # },
2773
- # ]
2774
- # }
2775
- # }
2776
- #
2777
- # stop-loss and take-profit
2778
- #
2779
- # {
2780
- # "returnCode": 0,
2781
- # "msgInfo": "success",
2782
- # "error": null,
2783
- # "result": {
2784
- # "page": 1,
2785
- # "ps": 3,
2786
- # "total": 2,
2787
- # "items": [
2788
- # {
2789
- # "profitId": "216306213226230400",
2790
- # "symbol": "btc_usdt",
2791
- # "positionSide": "LONG",
2792
- # "origQty": "1",
2793
- # "triggerPriceType": "LATEST_PRICE",
2794
- # "triggerProfitPrice": null,
2795
- # "triggerStopPrice": "20000",
2796
- # "entryPrice": "0",
2797
- # "positionSize": "0",
2798
- # "isolatedMargin": "0",
2799
- # "executedQty": "0",
2800
- # "avgPrice": null,
2801
- # "positionType": "ISOLATED",
2802
- # "state": "USER_REVOCATION",
2803
- # "createdTime": 1681273420039
2804
- # },
2805
- # ]
2806
- # }
2807
- # }
2808
- #
2809
- isSpotOpenOrders = ((status == 'open') and (subType is None))
2810
- data = self.safe_value(response, 'result', {})
2811
- orders = self.safe_value(response, 'result', []) if isSpotOpenOrders else self.safe_value(data, 'items', [])
2812
- return self.parse_orders(orders, market, since, limit)
2813
-
2814
- async def fetch_open_orders(self, symbol: Optional[str] = None, since: Optional[int] = None, limit: Optional[int] = None, params={}):
2815
- """
2816
- fetch all unfilled currently open orders
2817
- see https://doc.xt.com/#orderopenOrderGet
2818
- see https://doc.xt.com/#futures_ordergetOrders
2819
- see https://doc.xt.com/#futures_entrustgetPlan
2820
- see https://doc.xt.com/#futures_entrustgetProfit
2821
- :param str|None symbol: unified market symbol of the market the orders were made in
2822
- :param int|None since: timestamp in ms of the earliest order
2823
- :param int|None limit: the maximum number of open order structures to retrieve
2824
- :param dict params: extra parameters specific to the xt api endpoint
2825
- :param bool|None params['stop']: if the order is a stop trigger order or not
2826
- :param bool|None params['stopLossTakeProfit']: if the order is a stop-loss or take-profit order
2827
- :returns [dict]: a list of `order structures <https://docs.ccxt.com/en/latest/manual.html#order-structure>`
2828
- """
2829
- return await self.fetch_orders_by_status('open', symbol, since, limit, params)
2830
-
2831
- async def fetch_closed_orders(self, symbol: Optional[str] = None, since: Optional[int] = None, limit: Optional[int] = None, params={}):
2832
- """
2833
- fetches information on multiple closed orders made by the user
2834
- see https://doc.xt.com/#orderhistoryOrderGet
2835
- see https://doc.xt.com/#futures_ordergetOrders
2836
- see https://doc.xt.com/#futures_entrustgetPlan
2837
- see https://doc.xt.com/#futures_entrustgetProfit
2838
- :param str|None symbol: unified market symbol of the market the orders were made in
2839
- :param int|None since: timestamp in ms of the earliest order
2840
- :param int|None limit: the maximum number of order structures to retrieve
2841
- :param dict params: extra parameters specific to the xt api endpoint
2842
- :param bool|None params['stop']: if the order is a stop trigger order or not
2843
- :param bool|None params['stopLossTakeProfit']: if the order is a stop-loss or take-profit order
2844
- :returns [dict]: a list of `order structures <https://docs.ccxt.com/en/latest/manual.html#order-structure>`
2845
- """
2846
- return await self.fetch_orders_by_status('closed', symbol, since, limit, params)
2847
-
2848
- async def fetch_canceled_orders(self, symbol: Optional[str] = None, since: Optional[int] = None, limit: Optional[int] = None, params={}):
2849
- """
2850
- fetches information on multiple canceled orders made by the user
2851
- see https://doc.xt.com/#orderhistoryOrderGet
2852
- see https://doc.xt.com/#futures_ordergetOrders
2853
- see https://doc.xt.com/#futures_entrustgetPlan
2854
- see https://doc.xt.com/#futures_entrustgetProfit
2855
- :param str|None symbol: unified market symbol of the market the orders were made in
2856
- :param int|None since: timestamp in ms of the earliest order
2857
- :param int|None limit: the maximum number of order structures to retrieve
2858
- :param dict params: extra parameters specific to the xt api endpoint
2859
- :param bool|None params['stop']: if the order is a stop trigger order or not
2860
- :param bool|None params['stopLossTakeProfit']: if the order is a stop-loss or take-profit order
2861
- :returns dict: a list of `order structures <https://docs.ccxt.com/en/latest/manual.html#order-structure>`
2862
- """
2863
- return await self.fetch_orders_by_status('canceled', symbol, since, limit, params)
2864
-
2865
- async def cancel_order(self, id: str, symbol: Optional[str] = None, params={}):
2866
- """
2867
- cancels an open order
2868
- see https://doc.xt.com/#orderorderDel
2869
- see https://doc.xt.com/#futures_ordercancel
2870
- see https://doc.xt.com/#futures_entrustcancelPlan
2871
- see https://doc.xt.com/#futures_entrustcancelProfit
2872
- :param str id: order id
2873
- :param str|None symbol: unified symbol of the market the order was made in
2874
- :param dict params: extra parameters specific to the xt api endpoint
2875
- :param bool|None params['stop']: if the order is a stop trigger order or not
2876
- :param bool|None params['stopLossTakeProfit']: if the order is a stop-loss or take-profit order
2877
- :returns dict: An `order structure <https://docs.ccxt.com/en/latest/manual.html#order-structure>`
2878
- """
2879
- await self.load_markets()
2880
- market = None
2881
- if symbol is not None:
2882
- market = self.market(symbol)
2883
- request = {}
2884
- type = None
2885
- subType = None
2886
- response = None
2887
- type, params = self.handle_market_type_and_params('cancelOrder', market, params)
2888
- subType, params = self.handle_sub_type_and_params('cancelOrder', market, params)
2889
- stop = self.safe_value(params, 'stop')
2890
- stopLossTakeProfit = self.safe_value(params, 'stopLossTakeProfit')
2891
- if stop:
2892
- request['entrustId'] = id
2893
- elif stopLossTakeProfit:
2894
- request['profitId'] = id
2895
- else:
2896
- request['orderId'] = id
2897
- if stop:
2898
- params = self.omit(params, 'stop')
2899
- if subType == 'inverse':
2900
- response = await self.privateInversePostFutureTradeV1EntrustCancelPlan(self.extend(request, params))
2901
- else:
2902
- response = await self.privateLinearPostFutureTradeV1EntrustCancelPlan(self.extend(request, params))
2903
- elif stopLossTakeProfit:
2904
- params = self.omit(params, 'stopLossTakeProfit')
2905
- if subType == 'inverse':
2906
- response = await self.privateInversePostFutureTradeV1EntrustCancelProfitStop(self.extend(request, params))
2907
- else:
2908
- response = await self.privateLinearPostFutureTradeV1EntrustCancelProfitStop(self.extend(request, params))
2909
- elif subType == 'inverse':
2910
- response = await self.privateInversePostFutureTradeV1OrderCancel(self.extend(request, params))
2911
- elif (subType == 'linear') or (type == 'swap') or (type == 'future'):
2912
- response = await self.privateLinearPostFutureTradeV1OrderCancel(self.extend(request, params))
2913
- else:
2914
- response = await self.privateSpotDeleteOrderOrderId(self.extend(request, params))
2915
- #
2916
- # spot
2917
- #
2918
- # {
2919
- # "rc": 0,
2920
- # "mc": "SUCCESS",
2921
- # "ma": [],
2922
- # "result": {
2923
- # "cancelId": "208322474307982720"
2924
- # }
2925
- # }
2926
- #
2927
- # swap and future
2928
- #
2929
- # {
2930
- # "returnCode": 0,
2931
- # "msgInfo": "success",
2932
- # "error": null,
2933
- # "result": "208319789679471616"
2934
- # }
2935
- #
2936
- isContractResponse = ((subType is not None) or (type == 'swap') or (type == 'future'))
2937
- order = response if isContractResponse else self.safe_value(response, 'result', {})
2938
- return self.parse_order(order, market)
2939
-
2940
- async def cancel_all_orders(self, symbol: Optional[str] = None, params={}):
2941
- """
2942
- cancel all open orders in a market
2943
- see https://doc.xt.com/#orderopenOrderDel
2944
- see https://doc.xt.com/#futures_ordercancelBatch
2945
- see https://doc.xt.com/#futures_entrustcancelPlanBatch
2946
- see https://doc.xt.com/#futures_entrustcancelProfitBatch
2947
- :param str|None symbol: unified market symbol of the market to cancel orders in
2948
- :param dict params: extra parameters specific to the xt api endpoint
2949
- :param bool|None params['stop']: if the order is a stop trigger order or not
2950
- :param bool|None params['stopLossTakeProfit']: if the order is a stop-loss or take-profit order
2951
- :returns [dict]: a list of `order structures <https://docs.ccxt.com/en/latest/manual.html#order-structure>`
2952
- """
2953
- await self.load_markets()
2954
- request = {}
2955
- market = None
2956
- if symbol is not None:
2957
- market = self.market(symbol)
2958
- request['symbol'] = market['id']
2959
- type = None
2960
- subType = None
2961
- response = None
2962
- type, params = self.handle_market_type_and_params('cancelAllOrders', market, params)
2963
- subType, params = self.handle_sub_type_and_params('cancelAllOrders', market, params)
2964
- stop = self.safe_value(params, 'stop')
2965
- stopLossTakeProfit = self.safe_value(params, 'stopLossTakeProfit')
2966
- if stop:
2967
- params = self.omit(params, 'stop')
2968
- if subType == 'inverse':
2969
- response = await self.privateInversePostFutureTradeV1EntrustCancelAllPlan(self.extend(request, params))
2970
- else:
2971
- response = await self.privateLinearPostFutureTradeV1EntrustCancelAllPlan(self.extend(request, params))
2972
- elif stopLossTakeProfit:
2973
- params = self.omit(params, 'stopLossTakeProfit')
2974
- if subType == 'inverse':
2975
- response = await self.privateInversePostFutureTradeV1EntrustCancelAllProfitStop(self.extend(request, params))
2976
- else:
2977
- response = await self.privateLinearPostFutureTradeV1EntrustCancelAllProfitStop(self.extend(request, params))
2978
- elif subType == 'inverse':
2979
- response = await self.privateInversePostFutureTradeV1OrderCancelAll(self.extend(request, params))
2980
- elif (subType == 'linear') or (type == 'swap') or (type == 'future'):
2981
- response = await self.privateLinearPostFutureTradeV1OrderCancelAll(self.extend(request, params))
2982
- else:
2983
- marginMode = None
2984
- marginMode, params = self.handle_margin_mode_and_params('cancelAllOrders', params)
2985
- marginOrSpotRequest = 'LEVER' if (marginMode is not None) else 'SPOT'
2986
- request['bizType'] = marginOrSpotRequest
2987
- response = await self.privateSpotDeleteOpenOrder(self.extend(request, params))
2988
- #
2989
- # spot and margin
2990
- #
2991
- # {
2992
- # "rc": 0,
2993
- # "mc": "SUCCESS",
2994
- # "ma": [],
2995
- # "result": null
2996
- # }
2997
- #
2998
- # swap and future
2999
- #
3000
- # {
3001
- # "returnCode": 0,
3002
- # "msgInfo": "success",
3003
- # "error": null,
3004
- # "result": True
3005
- # }
3006
- #
3007
- return response
3008
-
3009
- async def cancel_orders(self, ids: List[str], symbol: Optional[str] = None, params={}):
3010
- """
3011
- cancel multiple orders
3012
- see https://doc.xt.com/#orderbatchOrderDel
3013
- :param [str] ids: order ids
3014
- :param str|None symbol: unified market symbol of the market to cancel orders in
3015
- :param dict params: extra parameters specific to the xt api endpoint
3016
- :returns [dict]: a list of `order structures <https://docs.ccxt.com/en/latest/manual.html#order-structure>`
3017
- """
3018
- await self.load_markets()
3019
- request = {
3020
- 'orderIds': ids,
3021
- }
3022
- market = None
3023
- if symbol is not None:
3024
- market = self.market(symbol)
3025
- subType = None
3026
- subType, params = self.handle_sub_type_and_params('cancelOrders', market, params)
3027
- if subType is not None:
3028
- raise NotSupported(self.id + ' cancelOrders() does not support swap and future orders, only spot orders are accepted')
3029
- response = await self.privateSpotDeleteBatchOrder(self.extend(request, params))
3030
- #
3031
- # spot
3032
- #
3033
- # {
3034
- # "rc": 0,
3035
- # "mc": "SUCCESS",
3036
- # "ma": [],
3037
- # "result": null
3038
- # }
3039
- #
3040
- return response
3041
-
3042
- def parse_order(self, order, market=None):
3043
- #
3044
- # spot: createOrder
3045
- #
3046
- # {
3047
- # "orderId": "204371980095156544"
3048
- # }
3049
- #
3050
- # spot: cancelOrder
3051
- #
3052
- # {
3053
- # "cancelId": "208322474307982720"
3054
- # }
3055
- #
3056
- # swap and future: createOrder, cancelOrder
3057
- #
3058
- # {
3059
- # "returnCode": 0,
3060
- # "msgInfo": "success",
3061
- # "error": null,
3062
- # "result": "206410760006650176"
3063
- # }
3064
- #
3065
- # spot: fetchOrder, fetchOrders, fetchOpenOrders, fetchClosedOrders, fetchCanceledOrders, fetchOrdersByStatus
3066
- #
3067
- # {
3068
- # "symbol": "btc_usdt",
3069
- # "orderId": "207505997850909952",
3070
- # "clientOrderId": null,
3071
- # "baseCurrency": "btc",
3072
- # "quoteCurrency": "usdt",
3073
- # "side": "BUY",
3074
- # "type": "LIMIT",
3075
- # "timeInForce": "GTC",
3076
- # "price": "20000.00",
3077
- # "origQty": "0.001000",
3078
- # "origQuoteQty": "20.00",
3079
- # "executedQty": "0.000000",
3080
- # "leavingQty": "0.001000",
3081
- # "tradeBase": "0.000000",
3082
- # "tradeQuote": "0.00",
3083
- # "avgPrice": null,
3084
- # "fee": null,
3085
- # "feeCurrency": null,
3086
- # "closed": False,
3087
- # "state": "NEW",
3088
- # "time": 1679175285162,
3089
- # "updatedTime": 1679175285255
3090
- # }
3091
- #
3092
- # swap and future: fetchOrder, fetchOrders, fetchOpenOrders, fetchClosedOrders, fetchCanceledOrders, fetchOrdersByStatus
3093
- #
3094
- # {
3095
- # "orderId": "207519546930995456",
3096
- # "clientOrderId": null,
3097
- # "symbol": "btc_usdt",
3098
- # "orderType": "LIMIT",
3099
- # "orderSide": "BUY",
3100
- # "positionSide": "LONG",
3101
- # "timeInForce": "GTC",
3102
- # "closePosition": False,
3103
- # "price": "20000",
3104
- # "origQty": "100",
3105
- # "avgPrice": "0",
3106
- # "executedQty": "0",
3107
- # "marginFrozen": "4.12",
3108
- # "remark": null,
3109
- # "triggerProfitPrice": null,
3110
- # "triggerStopPrice": null,
3111
- # "sourceId": null,
3112
- # "sourceType": "DEFAULT",
3113
- # "forceClose": False,
3114
- # "closeProfit": null,
3115
- # "state": "CANCELED",
3116
- # "createdTime": 1679178515689,
3117
- # "updatedTime": 1679180096172
3118
- # }
3119
- #
3120
- # trigger: fetchOrder, fetchOrders, fetchOpenOrders, fetchClosedOrders, fetchCanceledOrders, fetchOrdersByStatus
3121
- #
3122
- # {
3123
- # "entrustId": "216300248132756992",
3124
- # "symbol": "btc_usdt",
3125
- # "entrustType": "STOP",
3126
- # "orderSide": "SELL",
3127
- # "positionSide": "SHORT",
3128
- # "timeInForce": "GTC",
3129
- # "closePosition": null,
3130
- # "price": "20000",
3131
- # "origQty": "1",
3132
- # "stopPrice": "19000",
3133
- # "triggerPriceType": "LATEST_PRICE",
3134
- # "state": "NOT_TRIGGERED",
3135
- # "marketOrderLevel": null,
3136
- # "createdTime": 1681271998064,
3137
- # "updatedTime": 1681271998064,
3138
- # "ordinary": False
3139
- # }
3140
- #
3141
- # stop-loss and take-profit: fetchOrder, fetchOpenOrders, fetchClosedOrders, fetchCanceledOrders, fetchOrdersByStatus
3142
- #
3143
- # {
3144
- # "profitId": "216306213226230400",
3145
- # "symbol": "btc_usdt",
3146
- # "positionSide": "LONG",
3147
- # "origQty": "1",
3148
- # "triggerPriceType": "LATEST_PRICE",
3149
- # "triggerProfitPrice": null,
3150
- # "triggerStopPrice": "20000",
3151
- # "entryPrice": null,
3152
- # "positionSize": null,
3153
- # "isolatedMargin": null,
3154
- # "executedQty": null,
3155
- # "avgPrice": null,
3156
- # "positionType": "ISOLATED",
3157
- # "state": "NOT_TRIGGERED",
3158
- # "createdTime": 1681273420039
3159
- # }
3160
- #
3161
- marketId = self.safe_string(order, 'symbol')
3162
- marketType = ('result' in order) or 'contract' if ('positionSide' in order) else 'spot'
3163
- market = self.safe_market(marketId, market, None, marketType)
3164
- symbol = self.safe_symbol(marketId, market, None, marketType)
3165
- timestamp = self.safe_integer_2(order, 'time', 'createdTime')
3166
- quantity = self.safe_number(order, 'origQty')
3167
- amount = quantity if (marketType == 'spot') else Precise.string_mul(self.number_to_string(quantity), self.number_to_string(market['contractSize']))
3168
- filledQuantity = self.safe_number(order, 'executedQty')
3169
- filled = filledQuantity if (marketType == 'spot') else Precise.string_mul(self.number_to_string(filledQuantity), self.number_to_string(market['contractSize']))
3170
- lastUpdatedTimestamp = self.safe_integer(order, 'updatedTime')
3171
- return self.safe_order({
3172
- 'info': order,
3173
- 'id': self.safe_string_n(order, ['orderId', 'result', 'cancelId', 'entrustId', 'profitId']),
3174
- 'clientOrderId': self.safe_string(order, 'clientOrderId'),
3175
- 'timestamp': timestamp,
3176
- 'datetime': self.iso8601(timestamp),
3177
- 'lastTradeTimestamp': lastUpdatedTimestamp,
3178
- 'lastUpdateTimestamp': lastUpdatedTimestamp,
3179
- 'symbol': symbol,
3180
- 'type': self.safe_string_lower_2(order, 'type', 'orderType'),
3181
- 'timeInForce': self.safe_string(order, 'timeInForce'),
3182
- 'postOnly': None,
3183
- 'side': self.safe_string_lower_2(order, 'side', 'orderSide'),
3184
- 'price': self.safe_number(order, 'price'),
3185
- 'stopPrice': self.safe_number(order, 'stopPrice'),
3186
- 'stopLoss': self.safe_number(order, 'triggerStopPrice'),
3187
- 'takeProfit': self.safe_number(order, 'triggerProfitPrice'),
3188
- 'amount': amount,
3189
- 'filled': filled,
3190
- 'remaining': self.safe_number(order, 'leavingQty'),
3191
- 'cost': None,
3192
- 'average': self.safe_number(order, 'avgPrice'),
3193
- 'status': self.parse_order_status(self.safe_string(order, 'state')),
3194
- 'fee': {
3195
- 'currency': self.safe_currency_code(self.safe_string(order, 'feeCurrency')),
3196
- 'cost': self.safe_number(order, 'fee'),
3197
- },
3198
- 'trades': None,
3199
- }, market)
3200
-
3201
- def parse_order_status(self, status):
3202
- statuses = {
3203
- 'NEW': 'open',
3204
- 'PARTIALLY_FILLED': 'open',
3205
- 'FILLED': 'closed',
3206
- 'CANCELED': 'canceled',
3207
- 'REJECTED': 'rejected',
3208
- 'EXPIRED': 'expired',
3209
- 'UNFINISHED': 'open',
3210
- 'NOT_TRIGGERED': 'open',
3211
- 'TRIGGERING': 'open',
3212
- 'TRIGGERED': 'closed',
3213
- 'USER_REVOCATION': 'canceled',
3214
- 'PLATFORM_REVOCATION': 'rejected',
3215
- 'HISTORY': 'expired',
3216
- }
3217
- return self.safe_string(statuses, status, status)
3218
-
3219
- async def fetch_ledger(self, code: Optional[str] = None, since: Optional[int] = None, limit: Optional[int] = None, params={}):
3220
- """
3221
- fetch the history of changes, actions done by the user or operations that altered the balance of the user
3222
- see https://doc.xt.com/#futures_usergetBalanceBill
3223
- :param str|None code: unified currency code
3224
- :param int|None since: timestamp in ms of the earliest ledger entry
3225
- :param int|None limit: max number of ledger entries to return
3226
- :param dict params: extra parameters specific to the xt api endpoint
3227
- :returns dict: a `ledger structure <https://docs.ccxt.com/en/latest/manual.html#ledger-structure>`
3228
- """
3229
- await self.load_markets()
3230
- request = {}
3231
- currency = None
3232
- if code is not None:
3233
- currency = self.currency(code)
3234
- if since is not None:
3235
- request['startTime'] = since
3236
- if limit is not None:
3237
- request['limit'] = limit
3238
- type = None
3239
- subType = None
3240
- response = None
3241
- type, params = self.handle_market_type_and_params('fetchLedger', None, params)
3242
- subType, params = self.handle_sub_type_and_params('fetchLedger', None, params)
3243
- if subType == 'inverse':
3244
- response = await self.privateInverseGetFutureUserV1BalanceBills(self.extend(request, params))
3245
- elif (subType == 'linear') or (type == 'swap') or (type == 'future'):
3246
- response = await self.privateLinearGetFutureUserV1BalanceBills(self.extend(request, params))
3247
- else:
3248
- raise NotSupported(self.id + ' fetchLedger() does not support spot transactions, only swap and future wallet transactions are supported')
3249
- #
3250
- # {
3251
- # "returnCode": 0,
3252
- # "msgInfo": "success",
3253
- # "error": null,
3254
- # "result": {
3255
- # "hasPrev": False,
3256
- # "hasNext": False,
3257
- # "items": [
3258
- # {
3259
- # "id": "207260567109387524",
3260
- # "coin": "usdt",
3261
- # "symbol": "btc_usdt",
3262
- # "type": "FEE",
3263
- # "amount": "-0.0213",
3264
- # "side": "SUB",
3265
- # "afterAmount": null,
3266
- # "createdTime": 1679116769914
3267
- # },
3268
- # ]
3269
- # }
3270
- # }
3271
- #
3272
- data = self.safe_value(response, 'result', {})
3273
- ledger = self.safe_value(data, 'items', [])
3274
- return self.parse_ledger(ledger, currency, since, limit)
3275
-
3276
- def parse_ledger_entry(self, item, currency=None):
3277
- #
3278
- # {
3279
- # "id": "207260567109387524",
3280
- # "coin": "usdt",
3281
- # "symbol": "btc_usdt",
3282
- # "type": "FEE",
3283
- # "amount": "-0.0213",
3284
- # "side": "SUB",
3285
- # "afterAmount": null,
3286
- # "createdTime": 1679116769914
3287
- # }
3288
- #
3289
- side = self.safe_string(item, 'side')
3290
- direction = 'in' if (side == 'ADD') else 'out'
3291
- currencyId = self.safe_string(item, 'coin')
3292
- timestamp = self.safe_integer(item, 'createdTime')
3293
- return {
3294
- 'id': self.safe_string(item, 'id'),
3295
- 'direction': direction,
3296
- 'account': None,
3297
- 'referenceId': None,
3298
- 'referenceAccount': None,
3299
- 'type': self.parse_ledger_entry_type(self.safe_string(item, 'type')),
3300
- 'currency': self.safe_currency_code(currencyId, currency),
3301
- 'amount': self.safe_number(item, 'amount'),
3302
- 'timestamp': timestamp,
3303
- 'datetime': self.iso8601(timestamp),
3304
- 'before': None,
3305
- 'after': self.safe_number(item, 'afterAmount'),
3306
- 'status': None,
3307
- 'fee': {
3308
- 'currency': None,
3309
- 'cost': None,
3310
- },
3311
- 'info': item,
3312
- }
3313
-
3314
- def parse_ledger_entry_type(self, type):
3315
- ledgerType = {
3316
- 'EXCHANGE': 'transfer',
3317
- 'CLOSE_POSITION': 'trade',
3318
- 'TAKE_OVER': 'trade',
3319
- 'MERGE': 'trade',
3320
- 'QIANG_PING_MANAGER': 'fee',
3321
- 'FUND': 'fee',
3322
- 'FEE': 'fee',
3323
- 'ADL': 'auto-deleveraging',
3324
- }
3325
- return self.safe_string(ledgerType, type, type)
3326
-
3327
- async def fetch_deposit_address(self, code: str, params={}):
3328
- """
3329
- fetch the deposit address for a currency associated with self account
3330
- see https://doc.xt.com/#deposit_withdrawaldepositAddressGet
3331
- :param str code: unified currency code
3332
- :param dict params: extra parameters specific to the xt api endpoint
3333
- :param str params['network']: required network id
3334
- :returns dict: an `address structure <https://docs.ccxt.com/en/latest/manual.html#address-structure>`
3335
- """
3336
- await self.load_markets()
3337
- networkCode = None
3338
- networkCode, params = self.handle_network_code_and_params(params)
3339
- currency = self.currency(code)
3340
- networkId = self.network_code_to_id(networkCode, code)
3341
- self.check_required_argument('fetchDepositAddress', networkId, 'network')
3342
- request = {
3343
- 'currency': currency['id'],
3344
- 'chain': networkId,
3345
- }
3346
- response = await self.privateSpotGetDepositAddress(self.extend(request, params))
3347
- #
3348
- # {
3349
- # "rc": 0,
3350
- # "mc": "SUCCESS",
3351
- # "ma": [],
3352
- # "result": {
3353
- # "address": "0x7f7173cf29d3846d20ca5a3aec1120b93dbd157a",
3354
- # "memo": ""
3355
- # }
3356
- # }
3357
- #
3358
- result = self.safe_value(response, 'result', {})
3359
- return self.parse_deposit_address(result, currency)
3360
-
3361
- def parse_deposit_address(self, depositAddress, currency=None):
3362
- #
3363
- # {
3364
- # "address": "0x7f7173cf29d3846d20ca5a3aec1120b93dbd157a",
3365
- # "memo": ""
3366
- # }
3367
- #
3368
- address = self.safe_string(depositAddress, 'address')
3369
- self.check_address(address)
3370
- return {
3371
- 'currency': self.safe_currency_code(None, currency),
3372
- 'address': address,
3373
- 'tag': self.safe_string(depositAddress, 'memo'),
3374
- 'network': None,
3375
- 'info': depositAddress,
3376
- }
3377
-
3378
- async def fetch_deposits(self, code: Optional[str] = None, since: Optional[int] = None, limit: Optional[int] = None, params={}):
3379
- """
3380
- fetch all deposits made to an account
3381
- see https://doc.xt.com/#deposit_withdrawalhistoryDepositGet
3382
- :param str|None code: unified currency code
3383
- :param int|None since: the earliest time in ms to fetch deposits for
3384
- :param int|None limit: the maximum number of transaction structures to retrieve
3385
- :param dict params: extra parameters specific to the xt api endpoint
3386
- :returns [dict]: a list of `transaction structures <https://docs.ccxt.com/en/latest/manual.html#transaction-structure>`
3387
- """
3388
- await self.load_markets()
3389
- request = {}
3390
- currency = None
3391
- if code is not None:
3392
- currency = self.currency(code)
3393
- request['currency'] = currency['id']
3394
- if since is not None:
3395
- request['startTime'] = since
3396
- if limit is not None:
3397
- request['limit'] = limit # default 10, max 200
3398
- response = await self.privateSpotGetDepositHistory(self.extend(request, params))
3399
- #
3400
- # {
3401
- # "rc": 0,
3402
- # "mc": "SUCCESS",
3403
- # "ma": [],
3404
- # "result": {
3405
- # "hasPrev": False,
3406
- # "hasNext": False,
3407
- # "items": [
3408
- # {
3409
- # "id": 170368702,
3410
- # "currency": "usdt",
3411
- # "chain": "Ethereum",
3412
- # "memo": "",
3413
- # "status": "SUCCESS",
3414
- # "amount": "31.792528",
3415
- # "confirmations": 12,
3416
- # "transactionId": "0x90b8487c258b81b85e15e461b1839c49d4d8e6e9de4c1adb658cd47d4f5c5321",
3417
- # "address": "0x7f7172cf29d3846d30ca5a3aec1120b92dbd150b",
3418
- # "fromAddr": "0x7830c87c02e56aff27fa9ab1241711331fa86f58",
3419
- # "createdTime": 1678491442000
3420
- # },
3421
- # ]
3422
- # }
3423
- # }
3424
- #
3425
- data = self.safe_value(response, 'result', {})
3426
- deposits = self.safe_value(data, 'items', [])
3427
- return self.parse_transactions(deposits, currency, since, limit, params)
3428
-
3429
- async def fetch_withdrawals(self, code: Optional[str] = None, since: Optional[int] = None, limit: Optional[int] = None, params={}):
3430
- """
3431
- fetch all withdrawals made from an account
3432
- see https://doc.xt.com/#deposit_withdrawalwithdrawHistory
3433
- :param str|None code: unified currency code
3434
- :param int|None since: the earliest time in ms to fetch withdrawals for
3435
- :param int|None limit: the maximum number of transaction structures to retrieve
3436
- :param dict params: extra parameters specific to the xt api endpoint
3437
- :returns [dict]: a list of `transaction structures <https://docs.ccxt.com/en/latest/manual.html#transaction-structure>`
3438
- """
3439
- await self.load_markets()
3440
- request = {}
3441
- currency = None
3442
- if code is not None:
3443
- currency = self.currency(code)
3444
- request['currency'] = currency['id']
3445
- if since is not None:
3446
- request['startTime'] = since
3447
- if limit is not None:
3448
- request['limit'] = limit # default 10, max 200
3449
- response = await self.privateSpotGetWithdrawHistory(self.extend(request, params))
3450
- #
3451
- # {
3452
- # "rc": 0,
3453
- # "mc": "SUCCESS",
3454
- # "ma": [],
3455
- # "result": {
3456
- # "hasPrev": False,
3457
- # "hasNext": False,
3458
- # "items": [
3459
- # {
3460
- # "id": 950898,
3461
- # "currency": "usdt",
3462
- # "chain": "Tron",
3463
- # "address": "TGB2vxTjiqraVZBy7YHXF8V3CSMVhQKcaf",
3464
- # "memo": "",
3465
- # "status": "SUCCESS",
3466
- # "amount": "5",
3467
- # "fee": "2",
3468
- # "confirmations": 6,
3469
- # "transactionId": "c36e230b879842b1d7afd19d15ee1a866e26eaa0626e367d6f545d2932a15156",
3470
- # "createdTime": 1680049062000
3471
- # }
3472
- # ]
3473
- # }
3474
- # }
3475
- #
3476
- data = self.safe_value(response, 'result', {})
3477
- withdrawals = self.safe_value(data, 'items', [])
3478
- return self.parse_transactions(withdrawals, currency, since, limit, params)
3479
-
3480
- async def withdraw(self, code: str, amount, address, tag=None, params={}):
3481
- """
3482
- make a withdrawal
3483
- see https://doc.xt.com/#deposit_withdrawalwithdraw
3484
- :param str code: unified currency code
3485
- :param float amount: the amount to withdraw
3486
- :param str address: the address to withdraw to
3487
- :param str|None tag:
3488
- :param dict params: extra parameters specific to the xt api endpoint
3489
- :returns dict: a `transaction structure <https://docs.ccxt.com/en/latest/manual.html#transaction-structure>`
3490
- """
3491
- self.check_address(address)
3492
- await self.load_markets()
3493
- currency = self.currency(code)
3494
- tag, params = self.handle_withdraw_tag_and_params(tag, params)
3495
- networkCode = None
3496
- networkCode, params = self.handle_network_code_and_params(params)
3497
- networkIdsByCodes = self.safe_value(self.options, 'networks', {})
3498
- networkId = self.safe_string_2(networkIdsByCodes, networkCode, code, code)
3499
- request = {
3500
- 'currency': currency['id'],
3501
- 'chain': networkId,
3502
- 'amount': self.currency_to_precision(code, amount),
3503
- 'address': address,
3504
- }
3505
- if tag is not None:
3506
- request['memo'] = tag
3507
- response = await self.privateSpotPostWithdraw(self.extend(request, params))
3508
- #
3509
- # {
3510
- # "rc": 0,
3511
- # "mc": "SUCCESS",
3512
- # "ma": [],
3513
- # "result": {
3514
- # "id": 950898
3515
- # }
3516
- # }
3517
- #
3518
- result = self.safe_value(response, 'result', {})
3519
- return self.parse_transaction(result, currency)
3520
-
3521
- def parse_transaction(self, transaction, currency=None):
3522
- #
3523
- # fetchDeposits
3524
- #
3525
- # {
3526
- # "id": 170368702,
3527
- # "currency": "usdt",
3528
- # "chain": "Ethereum",
3529
- # "memo": "",
3530
- # "status": "SUCCESS",
3531
- # "amount": "31.792528",
3532
- # "confirmations": 12,
3533
- # "transactionId": "0x90b8487c258b81b85e15e461b1839c49d4d8e6e9de4c1adb658cd47d4f5c5321",
3534
- # "address": "0x7f7172cf29d3846d30ca5a3aec1120b92dbd150b",
3535
- # "fromAddr": "0x7830c87c02e56aff27fa9ab1241711331fa86f58",
3536
- # "createdTime": 1678491442000
3537
- # }
3538
- #
3539
- # fetchWithdrawals
3540
- #
3541
- # {
3542
- # "id": 950898,
3543
- # "currency": "usdt",
3544
- # "chain": "Tron",
3545
- # "address": "TGB2vxTjiqraVZBy7YHXF8V3CSMVhQKcaf",
3546
- # "memo": "",
3547
- # "status": "SUCCESS",
3548
- # "amount": "5",
3549
- # "fee": "2",
3550
- # "confirmations": 6,
3551
- # "transactionId": "c36e230b879842b1d7afd19d15ee1a866e26eaa0626e367d6f545d2932a15156",
3552
- # "createdTime": 1680049062000
3553
- # }
3554
- #
3555
- # withdraw
3556
- #
3557
- # {
3558
- # "id": 950898
3559
- # }
3560
- #
3561
- type = 'deposit' if ('fromAddr' in transaction) else 'withdraw'
3562
- timestamp = self.safe_integer(transaction, 'createdTime')
3563
- address = self.safe_string(transaction, 'address')
3564
- memo = self.safe_string(transaction, 'memo')
3565
- currencyCode = self.safe_currency_code(self.safe_string(transaction, 'currency'), currency)
3566
- fee = self.safe_number(transaction, 'fee')
3567
- feeCurrency = currencyCode if (fee is not None) else None
3568
- networkId = self.safe_string(transaction, 'chain')
3569
- return {
3570
- 'info': transaction,
3571
- 'id': self.safe_string(transaction, 'id'),
3572
- 'txid': self.safe_string(transaction, 'transactionId'),
3573
- 'timestamp': timestamp,
3574
- 'datetime': self.iso8601(timestamp),
3575
- 'updated': None,
3576
- 'addressFrom': self.safe_string(transaction, 'fromAddr'),
3577
- 'addressTo': address,
3578
- 'address': address,
3579
- 'tagFrom': None,
3580
- 'tagTo': None,
3581
- 'tag': memo,
3582
- 'type': type,
3583
- 'amount': self.safe_number(transaction, 'amount'),
3584
- 'currency': currencyCode,
3585
- 'network': self.network_id_to_code(networkId, currencyCode),
3586
- 'status': self.parse_transaction_status(self.safe_string(transaction, 'status')),
3587
- 'comment': memo,
3588
- 'fee': {
3589
- 'currency': feeCurrency,
3590
- 'cost': fee,
3591
- 'rate': None,
3592
- },
3593
- }
3594
-
3595
- def parse_transaction_status(self, status):
3596
- statuses = {
3597
- 'SUBMIT': 'pending',
3598
- 'REVIEW': 'pending',
3599
- 'AUDITED': 'pending',
3600
- 'PENDING': 'pending',
3601
- 'CANCEL': 'canceled',
3602
- 'FAIL': 'failed',
3603
- 'SUCCESS': 'ok',
3604
- }
3605
- return self.safe_string(statuses, status, status)
3606
-
3607
- async def set_leverage(self, leverage, symbol: Optional[str] = None, params={}):
3608
- """
3609
- set the level of leverage for a market
3610
- see https://doc.xt.com/#futures_useradjustLeverage
3611
- :param float leverage: the rate of leverage
3612
- :param str symbol: unified market symbol
3613
- :param dict params: extra parameters specific to the xt api endpoint
3614
- :param str params['positionSide']: 'LONG' or 'SHORT'
3615
- :returns dict: response from the exchange
3616
- """
3617
- self.check_required_symbol('setLeverage', symbol)
3618
- positionSide = self.safe_string(params, 'positionSide')
3619
- self.check_required_argument('setLeverage', positionSide, 'positionSide', ['LONG', 'SHORT'])
3620
- if (leverage < 1) or (leverage > 125):
3621
- raise BadRequest(self.id + ' setLeverage() leverage should be between 1 and 125')
3622
- await self.load_markets()
3623
- market = self.market(symbol)
3624
- if not (market['contract']):
3625
- raise BadSymbol(self.id + ' setLeverage() supports contract markets only')
3626
- request = {
3627
- 'symbol': market['id'],
3628
- 'positionSide': positionSide,
3629
- 'leverage': leverage,
3630
- }
3631
- subType = None
3632
- subType, params = self.handle_sub_type_and_params('setLeverage', market, params)
3633
- response = None
3634
- if subType == 'inverse':
3635
- response = await self.privateInversePostFutureUserV1PositionAdjustLeverage(self.extend(request, params))
3636
- else:
3637
- response = await self.privateLinearPostFutureUserV1PositionAdjustLeverage(self.extend(request, params))
3638
- #
3639
- # {
3640
- # "returnCode": 0,
3641
- # "msgInfo": "success",
3642
- # "error": null,
3643
- # "result": null
3644
- # }
3645
- #
3646
- return response
3647
-
3648
- async def add_margin(self, symbol: str, amount, params={}):
3649
- """
3650
- add margin to a position
3651
- see https://doc.xt.com/#futures_useradjustMargin
3652
- :param str symbol: unified market symbol
3653
- :param float amount: amount of margin to add
3654
- :param dict params: extra parameters specific to the xt api endpoint
3655
- :param str params['positionSide']: 'LONG' or 'SHORT'
3656
- :returns dict: a `margin structure <https://docs.ccxt.com/#/?id=add-margin-structure>`
3657
- """
3658
- return await self.modify_margin_helper(symbol, amount, 'ADD', params)
3659
-
3660
- async def reduce_margin(self, symbol: str, amount, params={}):
3661
- """
3662
- remove margin from a position
3663
- see https://doc.xt.com/#futures_useradjustMargin
3664
- :param str symbol: unified market symbol
3665
- :param float amount: the amount of margin to remove
3666
- :param dict params: extra parameters specific to the xt api endpoint
3667
- :param str params['positionSide']: 'LONG' or 'SHORT'
3668
- :returns dict: a `margin structure <https://docs.ccxt.com/#/?id=reduce-margin-structure>`
3669
- """
3670
- return await self.modify_margin_helper(symbol, amount, 'SUB', params)
3671
-
3672
- async def modify_margin_helper(self, symbol: str, amount, addOrReduce, params={}):
3673
- positionSide = self.safe_string(params, 'positionSide')
3674
- self.check_required_argument('setLeverage', positionSide, 'positionSide', ['LONG', 'SHORT'])
3675
- await self.load_markets()
3676
- market = self.market(symbol)
3677
- request = {
3678
- 'symbol': market['id'],
3679
- 'margin': amount,
3680
- 'type': addOrReduce,
3681
- 'positionSide': positionSide,
3682
- }
3683
- subType = None
3684
- subType, params = self.handle_sub_type_and_params('modifyMarginHelper', market, params)
3685
- response = None
3686
- if subType == 'inverse':
3687
- response = await self.privateInversePostFutureUserV1PositionMargin(self.extend(request, params))
3688
- else:
3689
- response = await self.privateLinearPostFutureUserV1PositionMargin(self.extend(request, params))
3690
- #
3691
- # {
3692
- # "returnCode": 0,
3693
- # "msgInfo": "success",
3694
- # "error": null,
3695
- # "result": null
3696
- # }
3697
- #
3698
- return self.parse_margin_modification(response, market)
3699
-
3700
- def parse_margin_modification(self, data, market=None):
3701
- return {
3702
- 'info': data,
3703
- 'type': None,
3704
- 'amount': None,
3705
- 'code': None,
3706
- 'symbol': self.safe_symbol(None, market),
3707
- 'status': None,
3708
- }
3709
-
3710
- async def fetch_leverage_tiers(self, symbols: Optional[List[str]] = None, params={}):
3711
- """
3712
- see https://doc.xt.com/#futures_quotesgetLeverageBrackets
3713
- retrieve information on the maximum leverage for different trade sizes
3714
- :param [str]|None symbols: a list of unified market symbols
3715
- :param dict params: extra parameters specific to the xt api endpoint
3716
- :returns dict: a dictionary of `leverage tiers structures <https://docs.ccxt.com/#/?id=leverage-tiers-structure>`
3717
- """
3718
- await self.load_markets()
3719
- subType = None
3720
- subType, params = self.handle_sub_type_and_params('fetchLeverageTiers', None, params)
3721
- response = None
3722
- if subType == 'inverse':
3723
- response = await self.publicInverseGetFutureMarketV1PublicLeverageBracketList(params)
3724
- else:
3725
- response = await self.publicLinearGetFutureMarketV1PublicLeverageBracketList(params)
3726
- #
3727
- # {
3728
- # "returnCode": 0,
3729
- # "msgInfo": "success",
3730
- # "error": null,
3731
- # "result": [
3732
- # {
3733
- # "symbol": "rad_usdt",
3734
- # "leverageBrackets": [
3735
- # {
3736
- # "symbol": "rad_usdt",
3737
- # "bracket": 1,
3738
- # "maxNominalValue": "5000",
3739
- # "maintMarginRate": "0.025",
3740
- # "startMarginRate": "0.05",
3741
- # "maxStartMarginRate": null,
3742
- # "maxLeverage": "20",
3743
- # "minLeverage": "1"
3744
- # },
3745
- # ]
3746
- # },
3747
- # ]
3748
- # }
3749
- #
3750
- data = self.safe_value(response, 'result', [])
3751
- symbols = self.market_symbols(symbols)
3752
- return self.parse_leverage_tiers(data, symbols, 'symbol')
3753
-
3754
- def parse_leverage_tiers(self, response, symbols=None, marketIdKey=None):
3755
- #
3756
- # {
3757
- # "symbol": "rad_usdt",
3758
- # "leverageBrackets": [
3759
- # {
3760
- # "symbol": "rad_usdt",
3761
- # "bracket": 1,
3762
- # "maxNominalValue": "5000",
3763
- # "maintMarginRate": "0.025",
3764
- # "startMarginRate": "0.05",
3765
- # "maxStartMarginRate": null,
3766
- # "maxLeverage": "20",
3767
- # "minLeverage": "1"
3768
- # },
3769
- # ]
3770
- # }
3771
- #
3772
- result = {}
3773
- for i in range(0, len(response)):
3774
- entry = response[i]
3775
- marketId = self.safe_string(entry, 'symbol')
3776
- market = self.safe_market(marketId, None, '_', 'contract')
3777
- symbol = self.safe_symbol(marketId, market)
3778
- if symbols is not None:
3779
- if self.in_array(symbol, symbols):
3780
- result[symbol] = self.parse_market_leverage_tiers(entry, market)
3781
- else:
3782
- result[symbol] = self.parse_market_leverage_tiers(response[i], market)
3783
- return result
3784
-
3785
- async def fetch_market_leverage_tiers(self, symbol: str, params={}):
3786
- """
3787
- see https://doc.xt.com/#futures_quotesgetLeverageBracket
3788
- retrieve information on the maximum leverage for different trade sizes of a single market
3789
- :param str symbol: unified market symbol
3790
- :param dict params: extra parameters specific to the xt api endpoint
3791
- :returns dict: a `leverage tiers structure <https://docs.ccxt.com/#/?id=leverage-tiers-structure>`
3792
- """
3793
- await self.load_markets()
3794
- market = self.market(symbol)
3795
- request = {
3796
- 'symbol': market['id'],
3797
- }
3798
- subType = None
3799
- subType, params = self.handle_sub_type_and_params('fetchMarketLeverageTiers', market, params)
3800
- response = None
3801
- if subType == 'inverse':
3802
- response = await self.publicInverseGetFutureMarketV1PublicLeverageBracketDetail(self.extend(request, params))
3803
- else:
3804
- response = await self.publicLinearGetFutureMarketV1PublicLeverageBracketDetail(self.extend(request, params))
3805
- #
3806
- # {
3807
- # "returnCode": 0,
3808
- # "msgInfo": "success",
3809
- # "error": null,
3810
- # "result": {
3811
- # "symbol": "btc_usdt",
3812
- # "leverageBrackets": [
3813
- # {
3814
- # "symbol": "btc_usdt",
3815
- # "bracket": 1,
3816
- # "maxNominalValue": "500000",
3817
- # "maintMarginRate": "0.004",
3818
- # "startMarginRate": "0.008",
3819
- # "maxStartMarginRate": null,
3820
- # "maxLeverage": "125",
3821
- # "minLeverage": "1"
3822
- # },
3823
- # ]
3824
- # }
3825
- # }
3826
- #
3827
- data = self.safe_value(response, 'result', {})
3828
- return self.parse_market_leverage_tiers(data, market)
3829
-
3830
- def parse_market_leverage_tiers(self, info, market=None):
3831
- #
3832
- # {
3833
- # "symbol": "rad_usdt",
3834
- # "leverageBrackets": [
3835
- # {
3836
- # "symbol": "rad_usdt",
3837
- # "bracket": 1,
3838
- # "maxNominalValue": "5000",
3839
- # "maintMarginRate": "0.025",
3840
- # "startMarginRate": "0.05",
3841
- # "maxStartMarginRate": null,
3842
- # "maxLeverage": "20",
3843
- # "minLeverage": "1"
3844
- # },
3845
- # ]
3846
- # }
3847
- #
3848
- tiers = []
3849
- brackets = self.safe_value(info, 'leverageBrackets', [])
3850
- for i in range(0, len(brackets)):
3851
- tier = brackets[i]
3852
- marketId = self.safe_string(info, 'symbol')
3853
- market = self.safe_market(marketId, market, '_', 'contract')
3854
- tiers.append({
3855
- 'tier': self.safe_integer(tier, 'bracket'),
3856
- 'currency': market['settle'],
3857
- 'minNotional': self.safe_number(brackets[i - 1], 'maxNominalValue', 0),
3858
- 'maxNotional': self.safe_number(tier, 'maxNominalValue'),
3859
- 'maintenanceMarginRate': self.safe_number(tier, 'maintMarginRate'),
3860
- 'maxLeverage': self.safe_number(tier, 'maxLeverage'),
3861
- 'info': tier,
3862
- })
3863
- return tiers
3864
-
3865
- async def fetch_funding_rate_history(self, symbol: Optional[str] = None, since: Optional[int] = None, limit: Optional[int] = None, params={}):
3866
- """
3867
- fetches historical funding rates
3868
- see https://doc.xt.com/#futures_quotesgetFundingRateRecord
3869
- :param str|None symbol: unified symbol of the market to fetch the funding rate history for
3870
- :param int|None since: timestamp in ms of the earliest funding rate to fetch
3871
- :param int|None limit: the maximum amount of [funding rate structures] to fetch
3872
- :param dict params: extra parameters specific to the xt api endpoint
3873
- :returns [dict]: a list of `funding rate structures <https://docs.ccxt.com/en/latest/manual.html?#funding-rate-history-structure>`
3874
- """
3875
- self.check_required_symbol('fetchFundingRateHistory', symbol)
3876
- await self.load_markets()
3877
- market = self.market(symbol)
3878
- if not market['swap']:
3879
- raise BadSymbol(self.id + ' fetchFundingRateHistory() supports swap contracts only')
3880
- request = {
3881
- 'symbol': market['id'],
3882
- }
3883
- if limit is not None:
3884
- request['limit'] = limit
3885
- subType = None
3886
- subType, params = self.handle_sub_type_and_params('fetchFundingRateHistory', market, params)
3887
- response = None
3888
- if subType == 'inverse':
3889
- response = await self.publicInverseGetFutureMarketV1PublicQFundingRateRecord(self.extend(request, params))
3890
- else:
3891
- response = await self.publicLinearGetFutureMarketV1PublicQFundingRateRecord(self.extend(request, params))
3892
- #
3893
- # {
3894
- # "returnCode": 0,
3895
- # "msgInfo": "success",
3896
- # "error": null,
3897
- # "result": {
3898
- # "hasPrev": False,
3899
- # "hasNext": True,
3900
- # "items": [
3901
- # {
3902
- # "id": "210441653482221888",
3903
- # "symbol": "btc_usdt",
3904
- # "fundingRate": "0.000057",
3905
- # "createdTime": 1679875200000,
3906
- # "collectionInternal": 28800
3907
- # },
3908
- # ]
3909
- # }
3910
- # }
3911
- #
3912
- result = self.safe_value(response, 'result', {})
3913
- items = self.safe_value(result, 'items', [])
3914
- rates = []
3915
- for i in range(0, len(items)):
3916
- entry = items[i]
3917
- marketId = self.safe_string(entry, 'symbol')
3918
- symbolInner = self.safe_symbol(marketId, market)
3919
- timestamp = self.safe_integer(entry, 'createdTime')
3920
- rates.append({
3921
- 'info': entry,
3922
- 'symbol': symbolInner,
3923
- 'fundingRate': self.safe_number(entry, 'fundingRate'),
3924
- 'timestamp': timestamp,
3925
- 'datetime': self.iso8601(timestamp),
3926
- })
3927
- sorted = self.sort_by(rates, 'timestamp')
3928
- return self.filter_by_symbol_since_limit(sorted, market['symbol'], since, limit)
3929
-
3930
- async def fetch_funding_rate(self, symbol: str, params={}):
3931
- """
3932
- fetch the current funding rate
3933
- see https://doc.xt.com/#futures_quotesgetFundingRate
3934
- :param str symbol: unified market symbol
3935
- :param dict params: extra parameters specific to the xt api endpoint
3936
- :returns dict: a `funding rate structure <https://docs.ccxt.com/#/?id=funding-rate-structure>`
3937
- """
3938
- await self.load_markets()
3939
- market = self.market(symbol)
3940
- if not market['swap']:
3941
- raise BadSymbol(self.id + ' fetchFundingRate() supports swap contracts only')
3942
- request = {
3943
- 'symbol': market['id'],
3944
- }
3945
- subType = None
3946
- subType, params = self.handle_sub_type_and_params('fetchFundingRate', market, params)
3947
- response = None
3948
- if subType == 'inverse':
3949
- response = await self.publicInverseGetFutureMarketV1PublicQFundingRate(self.extend(request, params))
3950
- else:
3951
- response = await self.publicLinearGetFutureMarketV1PublicQFundingRate(self.extend(request, params))
3952
- #
3953
- # {
3954
- # "returnCode": 0,
3955
- # "msgInfo": "success",
3956
- # "error": null,
3957
- # "result": {
3958
- # "symbol": "btc_usdt",
3959
- # "fundingRate": "0.000086",
3960
- # "nextCollectionTime": 1680307200000,
3961
- # "collectionInternal": 8
3962
- # }
3963
- # }
3964
- #
3965
- result = self.safe_value(response, 'result', {})
3966
- return self.parse_funding_rate(result, market)
3967
-
3968
- def parse_funding_rate(self, contract, market=None):
3969
- #
3970
- # {
3971
- # "symbol": "btc_usdt",
3972
- # "fundingRate": "0.000086",
3973
- # "nextCollectionTime": 1680307200000,
3974
- # "collectionInternal": 8
3975
- # }
3976
- #
3977
- marketId = self.safe_string(contract, 'symbol')
3978
- symbol = self.safe_symbol(marketId, market, '_', 'swap')
3979
- timestamp = self.safe_integer(contract, 'nextCollectionTime')
3980
- return {
3981
- 'info': contract,
3982
- 'symbol': symbol,
3983
- 'markPrice': None,
3984
- 'indexPrice': None,
3985
- 'interestRate': None,
3986
- 'estimatedSettlePrice': None,
3987
- 'timestamp': None,
3988
- 'datetime': None,
3989
- 'fundingRate': self.safe_number(contract, 'fundingRate'),
3990
- 'fundingTimestamp': timestamp,
3991
- 'fundingDatetime': self.iso8601(timestamp),
3992
- 'nextFundingRate': None,
3993
- 'nextFundingTimestamp': None,
3994
- 'nextFundingDatetime': None,
3995
- 'previousFundingRate': None,
3996
- 'previousFundingTimestamp': None,
3997
- 'previousFundingDatetime': None,
3998
- }
3999
-
4000
- async def fetch_funding_history(self, symbol: str, since: Optional[int] = None, limit: Optional[int] = None, params={}):
4001
- """
4002
- fetch the funding history
4003
- see https://doc.xt.com/#futures_usergetFunding
4004
- :param str symbol: unified market symbol
4005
- :param int|None since: the starting timestamp in milliseconds
4006
- :param int|None limit: the number of entries to return
4007
- :param dict params: extra parameters specific to the xt api endpoint
4008
- :returns [dict]: a list of `funding history structures <https://docs.ccxt.com/#/?id=funding-history-structure>`
4009
- """
4010
- await self.load_markets()
4011
- market = self.market(symbol)
4012
- if not market['swap']:
4013
- raise BadSymbol(self.id + ' fetchFundingHistory() supports swap contracts only')
4014
- request = {
4015
- 'symbol': market['id'],
4016
- }
4017
- if since is not None:
4018
- request['startTime'] = since
4019
- if limit is not None:
4020
- request['limit'] = limit
4021
- subType = None
4022
- subType, params = self.handle_sub_type_and_params('fetchFundingHistory', market, params)
4023
- response = None
4024
- if subType == 'inverse':
4025
- response = await self.privateInverseGetFutureUserV1BalanceFundingRateList(self.extend(request, params))
4026
- else:
4027
- response = await self.privateLinearGetFutureUserV1BalanceFundingRateList(self.extend(request, params))
4028
- #
4029
- # {
4030
- # "returnCode": 0,
4031
- # "msgInfo": "success",
4032
- # "error": null,
4033
- # "result": {
4034
- # "hasPrev": False,
4035
- # "hasNext": False,
4036
- # "items": [
4037
- # {
4038
- # "id": "210804044057280512",
4039
- # "symbol": "btc_usdt",
4040
- # "cast": "-0.0013",
4041
- # "coin": "usdt",
4042
- # "positionSide": "SHORT",
4043
- # "createdTime": 1679961600653
4044
- # },
4045
- # ]
4046
- # }
4047
- # }
4048
- #
4049
- data = self.safe_value(response, 'result', {})
4050
- items = self.safe_value(data, 'items', [])
4051
- result = []
4052
- for i in range(0, len(items)):
4053
- entry = items[i]
4054
- result.append(self.parse_funding_history(entry, market))
4055
- sorted = self.sort_by(result, 'timestamp')
4056
- return self.filter_by_since_limit(sorted, since, limit)
4057
-
4058
- def parse_funding_history(self, contract, market=None):
4059
- #
4060
- # {
4061
- # "id": "210804044057280512",
4062
- # "symbol": "btc_usdt",
4063
- # "cast": "-0.0013",
4064
- # "coin": "usdt",
4065
- # "positionSide": "SHORT",
4066
- # "createdTime": 1679961600653
4067
- # }
4068
- #
4069
- marketId = self.safe_string(contract, 'symbol')
4070
- symbol = self.safe_symbol(marketId, market, '_', 'swap')
4071
- currencyId = self.safe_string(contract, 'coin')
4072
- code = self.safe_currency_code(currencyId)
4073
- timestamp = self.safe_integer(contract, 'createdTime')
4074
- return {
4075
- 'info': contract,
4076
- 'symbol': symbol,
4077
- 'code': code,
4078
- 'timestamp': timestamp,
4079
- 'datetime': self.iso8601(timestamp),
4080
- 'id': self.safe_string(contract, 'id'),
4081
- 'amount': self.safe_number(contract, 'cast'),
4082
- }
4083
-
4084
- async def fetch_position(self, symbol: str, params={}):
4085
- """
4086
- fetch data on a single open contract trade position
4087
- see https://doc.xt.com/#futures_usergetPosition
4088
- :param str symbol: unified market symbol of the market the position is held in
4089
- :param dict params: extra parameters specific to the xt api endpoint
4090
- :returns dict: a `position structure <https://docs.ccxt.com/#/?id=position-structure>`
4091
- """
4092
- await self.load_markets()
4093
- market = self.market(symbol)
4094
- request = {
4095
- 'symbol': market['id'],
4096
- }
4097
- subType = None
4098
- subType, params = self.handle_sub_type_and_params('fetchPosition', market, params)
4099
- response = None
4100
- if subType == 'inverse':
4101
- response = await self.privateInverseGetFutureUserV1PositionList(self.extend(request, params))
4102
- else:
4103
- response = await self.privateLinearGetFutureUserV1PositionList(self.extend(request, params))
4104
- #
4105
- # {
4106
- # "returnCode": 0,
4107
- # "msgInfo": "success",
4108
- # "error": null,
4109
- # "result": [
4110
- # {
4111
- # "symbol": "btc_usdt",
4112
- # "positionType": "ISOLATED",
4113
- # "positionSide": "SHORT",
4114
- # "contractType": "PERPETUAL",
4115
- # "positionSize": "10",
4116
- # "closeOrderSize": "0",
4117
- # "availableCloseSize": "10",
4118
- # "entryPrice": "27060",
4119
- # "openOrderSize": "0",
4120
- # "isolatedMargin": "1.0824",
4121
- # "openOrderMarginFrozen": "0",
4122
- # "realizedProfit": "-0.00130138",
4123
- # "autoMargin": False,
4124
- # "leverage": 25
4125
- # },
4126
- # ]
4127
- # }
4128
- #
4129
- positions = self.safe_value(response, 'result', [])
4130
- for i in range(0, len(positions)):
4131
- entry = positions[i]
4132
- marketId = self.safe_string(entry, 'symbol')
4133
- marketInner = self.safe_market(marketId, None, None, 'contract')
4134
- positionSize = self.safe_string(entry, 'positionSize')
4135
- if positionSize != '0':
4136
- return self.parse_position(entry, marketInner)
4137
- return None
4138
-
4139
- async def fetch_positions(self, symbols: Optional[List[str]] = None, params={}):
4140
- """
4141
- fetch all open positions
4142
- see https://doc.xt.com/#futures_usergetPosition
4143
- :param [str]|None symbols: list of unified market symbols, not supported with xt
4144
- :param dict params: extra parameters specific to the xt api endpoint
4145
- :returns [dict]: a list of `position structure <https://docs.ccxt.com/#/?id=position-structure>`
4146
- """
4147
- await self.load_markets()
4148
- if symbols is not None:
4149
- raise BadRequest(self.id + ' fetchPositions() only supports the symbols argument')
4150
- subType = None
4151
- subType, params = self.handle_sub_type_and_params('fetchPositions', None, params)
4152
- response = None
4153
- if subType == 'inverse':
4154
- response = await self.privateInverseGetFutureUserV1PositionList(params)
4155
- else:
4156
- response = await self.privateLinearGetFutureUserV1PositionList(params)
4157
- #
4158
- # {
4159
- # "returnCode": 0,
4160
- # "msgInfo": "success",
4161
- # "error": null,
4162
- # "result": [
4163
- # {
4164
- # "symbol": "btc_usdt",
4165
- # "positionType": "ISOLATED",
4166
- # "positionSide": "SHORT",
4167
- # "contractType": "PERPETUAL",
4168
- # "positionSize": "10",
4169
- # "closeOrderSize": "0",
4170
- # "availableCloseSize": "10",
4171
- # "entryPrice": "27060",
4172
- # "openOrderSize": "0",
4173
- # "isolatedMargin": "1.0824",
4174
- # "openOrderMarginFrozen": "0",
4175
- # "realizedProfit": "-0.00130138",
4176
- # "autoMargin": False,
4177
- # "leverage": 25
4178
- # },
4179
- # ]
4180
- # }
4181
- #
4182
- positions = self.safe_value(response, 'result', [])
4183
- result = []
4184
- for i in range(0, len(positions)):
4185
- entry = positions[i]
4186
- marketId = self.safe_string(entry, 'symbol')
4187
- marketInner = self.safe_market(marketId, None, None, 'contract')
4188
- result.append(self.parse_position(entry, marketInner))
4189
- return self.filter_by_array(result, 'symbol', None, False)
4190
-
4191
- def parse_position(self, position, market=None):
4192
- #
4193
- # {
4194
- # "symbol": "btc_usdt",
4195
- # "positionType": "ISOLATED",
4196
- # "positionSide": "SHORT",
4197
- # "contractType": "PERPETUAL",
4198
- # "positionSize": "10",
4199
- # "closeOrderSize": "0",
4200
- # "availableCloseSize": "10",
4201
- # "entryPrice": "27060",
4202
- # "openOrderSize": "0",
4203
- # "isolatedMargin": "1.0824",
4204
- # "openOrderMarginFrozen": "0",
4205
- # "realizedProfit": "-0.00130138",
4206
- # "autoMargin": False,
4207
- # "leverage": 25
4208
- # }
4209
- #
4210
- marketId = self.safe_string(position, 'symbol')
4211
- market = self.safe_market(marketId, market, None, 'contract')
4212
- symbol = self.safe_symbol(marketId, market, None, 'contract')
4213
- positionType = self.safe_string(position, 'positionType')
4214
- marginMode = 'cross' if (positionType == 'CROSSED') else 'isolated'
4215
- collateral = self.safe_number(position, 'isolatedMargin')
4216
- return self.safe_position({
4217
- 'info': position,
4218
- 'id': None,
4219
- 'symbol': symbol,
4220
- 'timestamp': None,
4221
- 'datetime': None,
4222
- 'hedged': None,
4223
- 'side': self.safe_string_lower(position, 'positionSide'),
4224
- 'contracts': self.safe_number(position, 'positionSize'),
4225
- 'contractSize': market['contractSize'],
4226
- 'entryPrice': self.safe_number(position, 'entryPrice'),
4227
- 'markPrice': None,
4228
- 'notional': None,
4229
- 'leverage': self.safe_integer(position, 'leverage'),
4230
- 'collateral': collateral,
4231
- 'initialMargin': collateral,
4232
- 'maintenanceMargin': None,
4233
- 'initialMarginPercentage': None,
4234
- 'maintenanceMarginPercentage': None,
4235
- 'unrealizedPnl': None,
4236
- 'liquidationPrice': None,
4237
- 'marginMode': marginMode,
4238
- 'percentage': None,
4239
- 'marginRatio': None,
4240
- })
4241
-
4242
- async def transfer(self, code: str, amount, fromAccount, toAccount, params={}):
4243
- """
4244
- transfer currency internally between wallets on the same account
4245
- see https://doc.xt.com/#transfersubTransferPost
4246
- :param str code: unified currency code
4247
- :param float amount: amount to transfer
4248
- :param str fromAccount: account to transfer from - spot, swap, leverage, finance
4249
- :param str toAccount: account to transfer to - spot, swap, leverage, finance
4250
- :param dict params: extra parameters specific to the whitebit api endpoint
4251
- :returns dict: a `transfer structure <https://docs.ccxt.com/#/?id=transfer-structure>`
4252
- """
4253
- await self.load_markets()
4254
- currency = self.currency(code)
4255
- accountsByType = self.safe_value(self.options, 'accountsById')
4256
- fromAccountId = self.safe_string(accountsByType, fromAccount, fromAccount)
4257
- toAccountId = self.safe_string(accountsByType, toAccount, toAccount)
4258
- amountString = self.currency_to_precision(code, amount)
4259
- request = {
4260
- 'bizId': self.uuid(),
4261
- 'currency': currency['id'],
4262
- 'amount': amountString,
4263
- 'from': fromAccountId,
4264
- 'to': toAccountId,
4265
- }
4266
- response = await self.privateSpotPostBalanceTransfer(self.extend(request, params))
4267
- #
4268
- # {
4269
- # info: {rc: '0', mc: 'SUCCESS', ma: [], result: '226971333791398656'},
4270
- # id: '226971333791398656',
4271
- # timestamp: None,
4272
- # datetime: None,
4273
- # currency: None,
4274
- # amount: None,
4275
- # fromAccount: None,
4276
- # toAccount: None,
4277
- # status: None
4278
- # }
4279
- #
4280
- return self.parse_transfer(response, currency)
4281
-
4282
- def parse_transfer(self, transfer, currency=None):
4283
- return {
4284
- 'info': transfer,
4285
- 'id': self.safe_string(transfer, 'result'),
4286
- 'timestamp': None,
4287
- 'datetime': None,
4288
- 'currency': None,
4289
- 'amount': None,
4290
- 'fromAccount': None,
4291
- 'toAccount': None,
4292
- 'status': None,
4293
- }
4294
-
4295
- def handle_errors(self, code, reason, url, method, headers, body, response, requestHeaders, requestBody):
4296
- #
4297
- # spot: error
4298
- #
4299
- # {
4300
- # "rc": 1,
4301
- # "mc": "AUTH_103",
4302
- # "ma": [],
4303
- # "result": null
4304
- # }
4305
- #
4306
- # spot: success
4307
- #
4308
- # {
4309
- # "returnCode": 0,
4310
- # "msgInfo": "success",
4311
- # "error": null,
4312
- # "result": []
4313
- # }
4314
- #
4315
- # swap and future: error
4316
- #
4317
- # {
4318
- # "returnCode": 1,
4319
- # "msgInfo": "failure",
4320
- # "error": {
4321
- # "code": "403",
4322
- # "msg": "invalid signature"
4323
- # },
4324
- # "result": null
4325
- # }
4326
- #
4327
- # swap and future: success
4328
- #
4329
- # {
4330
- # "returnCode": 0,
4331
- # "msgInfo": "success",
4332
- # "error": null,
4333
- # "result": null
4334
- # }
4335
- #
4336
- # other:
4337
- #
4338
- # {
4339
- # "rc": 0,
4340
- # "mc": "SUCCESS",
4341
- # "ma": [],
4342
- # "result": {}
4343
- # }
4344
- #
4345
- status = self.safe_string_upper_2(response, 'msgInfo', 'mc')
4346
- if status is not None and status != 'SUCCESS':
4347
- feedback = self.id + ' ' + body
4348
- error = self.safe_value(response, 'error', {})
4349
- spotErrorCode = self.safe_string(response, 'mc')
4350
- errorCode = self.safe_string(error, 'code', spotErrorCode)
4351
- spotMessage = self.safe_string(response, 'msgInfo')
4352
- message = self.safe_string(error, 'msg', spotMessage)
4353
- self.throw_exactly_matched_exception(self.exceptions['exact'], errorCode, feedback)
4354
- self.throw_broadly_matched_exception(self.exceptions['broad'], message, feedback)
4355
- raise ExchangeError(feedback)
4356
- return None
4357
-
4358
- def sign(self, path, api=[], method='GET', params={}, headers=None, body=None):
4359
- signed = api[0] == 'private'
4360
- endpoint = api[1]
4361
- request = '/' + self.implode_params(path, params)
4362
- payload = None
4363
- if (endpoint == 'spot') or (endpoint == 'user'):
4364
- if signed:
4365
- payload = '/' + self.version + request
4366
- else:
4367
- payload = '/' + self.version + '/public' + request
4368
- else:
4369
- payload = request
4370
- url = self.urls['api'][endpoint] + payload
4371
- query = self.omit(params, self.extract_params(path))
4372
- urlencoded = self.urlencode(self.keysort(query))
4373
- headers = {
4374
- 'Content-Type': 'application/json',
4375
- }
4376
- if signed:
4377
- self.check_required_credentials()
4378
- defaultRecvWindow = self.safe_string(self.options, 'recvWindow')
4379
- recvWindow = self.safe_string(query, 'recvWindow', defaultRecvWindow)
4380
- timestamp = self.number_to_string(self.nonce())
4381
- body = query
4382
- if (payload == '/v4/order') or (payload == '/future/trade/v1/order/create') or (payload == '/future/trade/v1/entrust/create-plan') or (payload == '/future/trade/v1/entrust/create-profit') or (payload == '/future/trade/v1/order/create-batch'):
4383
- id = 'CCXT'
4384
- if payload.find('future') > -1:
4385
- body['clientMedia'] = id
4386
- else:
4387
- body['media'] = id
4388
- isUndefinedBody = ((method == 'GET') or (path == 'order/{orderId}'))
4389
- body = None if isUndefinedBody else self.json(body)
4390
- payloadString = None
4391
- if (endpoint == 'spot') or (endpoint == 'user'):
4392
- payloadString = 'xt-validate-algorithms=HmacSHA256&xt-validate-appkey=' + self.apiKey + '&xt-validate-recvwindow=' + recvWindow + '&xt-validate-t' + 'imestamp=' + timestamp
4393
- if isUndefinedBody:
4394
- if urlencoded:
4395
- url += '?' + urlencoded
4396
- payloadString += '#' + method + '#' + payload + '#' + urlencoded
4397
- else:
4398
- payloadString += '#' + method + '#' + payload
4399
- else:
4400
- payloadString += '#' + method + '#' + payload + '#' + body
4401
- headers['xt-validate-algorithms'] = 'HmacSHA256'
4402
- headers['xt-validate-recvwindow'] = recvWindow
4403
- else:
4404
- payloadString = 'xt-validate-appkey=' + self.apiKey + '&xt-validate-t' + 'imestamp=' + timestamp # we can't glue timestamp, breaks in php
4405
- if method == 'GET':
4406
- if urlencoded:
4407
- url += '?' + urlencoded
4408
- payloadString += '#' + payload + '#' + urlencoded
4409
- else:
4410
- payloadString += '#' + payload
4411
- else:
4412
- payloadString += '#' + payload + '#' + body
4413
- signature = self.hmac(self.encode(payloadString), self.encode(self.secret), hashlib.sha256)
4414
- headers['xt-validate-appkey'] = self.apiKey
4415
- headers['xt-validate-timestamp'] = timestamp
4416
- headers['xt-validate-signature'] = signature
4417
- else:
4418
- if urlencoded:
4419
- url += '?' + urlencoded
4420
- return {'url': url, 'method': method, 'body': body, 'headers': headers}