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/zb.py DELETED
@@ -1,4127 +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
- import asyncio
8
- import hashlib
9
- from ccxt.base.types import OrderSide
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 AccountSuspended
15
- from ccxt.base.errors import ArgumentsRequired
16
- from ccxt.base.errors import BadRequest
17
- from ccxt.base.errors import BadSymbol
18
- from ccxt.base.errors import BadResponse
19
- from ccxt.base.errors import InsufficientFunds
20
- from ccxt.base.errors import InvalidAddress
21
- from ccxt.base.errors import InvalidOrder
22
- from ccxt.base.errors import OrderNotFound
23
- from ccxt.base.errors import DuplicateOrderId
24
- from ccxt.base.errors import NotSupported
25
- from ccxt.base.errors import NetworkError
26
- from ccxt.base.errors import DDoSProtection
27
- from ccxt.base.errors import RateLimitExceeded
28
- from ccxt.base.errors import ExchangeNotAvailable
29
- from ccxt.base.errors import OnMaintenance
30
- from ccxt.base.errors import RequestTimeout
31
- from ccxt.base.errors import AuthenticationError
32
- from ccxt.base.decimal_to_precision import TICK_SIZE
33
- from ccxt.base.precise import Precise
34
-
35
-
36
- class zb(Exchange):
37
-
38
- def describe(self):
39
- return self.deep_extend(super(zb, self).describe(), {
40
- 'id': 'zb',
41
- 'name': 'ZB',
42
- 'countries': ['CN'],
43
- # previously rateLimit = 100
44
- # Trading and Margin 10 000 per minute(IP) => 10000 / 60 = 166.66666... per second => rateLimit = 1000/166.66666 = 6
45
- # Trade and Margin 60 per second(apiKey) => weight = 166.666 / 60 = 2.778(2.7777777...)
46
- # Kline 1 per second => weight = 166.667
47
- # v2 Futures API 100 per 2 seconds => 50 per second => weight = 3.334(3.3333333...)
48
- # for endpoints not mentioned in docs
49
- # previous rateLimit was 100 translating to 10 requests per second => weight = 166.666 / 10 = 16.667(16.666666...)
50
- 'rateLimit': 6,
51
- 'version': 'v1',
52
- 'pro': True,
53
- 'has': {
54
- 'CORS': None,
55
- 'spot': True,
56
- 'margin': True,
57
- 'swap': True,
58
- 'future': None,
59
- 'option': None,
60
- 'addMargin': True,
61
- 'borrowMargin': True,
62
- 'cancelAllOrders': True,
63
- 'cancelOrder': True,
64
- 'createMarketOrder': False,
65
- 'createOrder': True,
66
- 'createReduceOnlyOrder': False,
67
- 'createStopLimitOrder': True,
68
- 'createStopMarketOrder': True,
69
- 'createStopOrder': True,
70
- 'fetchBalance': True,
71
- 'fetchBorrowRate': True,
72
- 'fetchBorrowRateHistories': False,
73
- 'fetchBorrowRateHistory': False,
74
- 'fetchBorrowRates': True,
75
- 'fetchCanceledOrders': True,
76
- 'fetchClosedOrders': True,
77
- 'fetchCurrencies': True,
78
- 'fetchDepositAddress': True,
79
- 'fetchDepositAddresses': True,
80
- 'fetchDeposits': True,
81
- 'fetchFundingHistory': False,
82
- 'fetchFundingRate': True,
83
- 'fetchFundingRateHistory': True,
84
- 'fetchFundingRates': True,
85
- 'fetchIndexOHLCV': True,
86
- 'fetchLedger': True,
87
- 'fetchLeverage': False,
88
- 'fetchLeverageTiers': False,
89
- 'fetchMarketLeverageTiers': False,
90
- 'fetchMarkets': True,
91
- 'fetchMarkOHLCV': True,
92
- 'fetchOHLCV': True,
93
- 'fetchOpenOrders': True,
94
- 'fetchOrder': True,
95
- 'fetchOrderBook': True,
96
- 'fetchOrders': True,
97
- 'fetchPosition': True,
98
- 'fetchPositions': True,
99
- 'fetchPositionsRisk': False,
100
- 'fetchPremiumIndexOHLCV': False,
101
- 'fetchTicker': True,
102
- 'fetchTickers': True,
103
- 'fetchTrades': True,
104
- 'fetchTradingFee': False,
105
- 'fetchTradingFees': False,
106
- 'fetchWithdrawals': True,
107
- 'reduceMargin': True,
108
- 'setLeverage': True,
109
- 'setMarginMode': False,
110
- 'setPositionMode': False,
111
- 'transfer': True,
112
- 'withdraw': True,
113
- },
114
- 'timeframes': {
115
- '1m': '1m',
116
- '3m': '3m',
117
- '5m': '5m',
118
- '15m': '15m',
119
- '30m': '30m',
120
- '1h': '1h',
121
- '2h': '2h',
122
- '4h': '4h',
123
- '6h': '6h',
124
- '12h': '12h',
125
- '1d': '1d',
126
- '3d': '3d',
127
- '5d': '5d',
128
- '1w': '1w',
129
- },
130
- 'hostname': 'zb.com', # zb.cafe for users in China
131
- 'urls': {
132
- 'logo': 'https://user-images.githubusercontent.com/1294454/32859187-cd5214f0-ca5e-11e7-967d-96568e2e2bd1.jpg',
133
- 'api': {
134
- 'spot': {
135
- 'v1': {
136
- 'public': 'https://api.{hostname}/data',
137
- 'private': 'https://trade.{hostname}/api',
138
- },
139
- },
140
- 'contract': {
141
- 'v1': {
142
- 'public': 'https://fapi.{hostname}/api/public',
143
- },
144
- 'v2': {
145
- 'public': 'https://fapi.{hostname}/Server/api',
146
- 'private': 'https://fapi.{hostname}/Server/api',
147
- },
148
- },
149
- },
150
- 'www': 'https://www.zb.com',
151
- 'doc': 'https://www.zb.com/i/developer',
152
- 'fees': 'https://www.zb.com/i/rate',
153
- 'referral': {
154
- 'url': 'https://www.zb.com/en/register?ref=4301lera',
155
- 'discount': 0.16,
156
- },
157
- },
158
- 'api': {
159
- 'spot': {
160
- 'v1': {
161
- 'public': {
162
- 'get': {
163
- 'markets': 16.667,
164
- 'ticker': 16.667,
165
- 'allTicker': 16.667,
166
- 'depth': 16.667,
167
- 'trades': 16.667,
168
- 'kline': 166.667, # Kline 1 per second
169
- 'getGroupMarkets': 16.667,
170
- 'getFeeInfo': 16.667,
171
- },
172
- },
173
- 'private': {
174
- 'get': {
175
- # spot API
176
- 'order': 1, # Trade API
177
- 'orderMoreV2': 1, # Trade API
178
- 'cancelOrder': 1, # Trade API
179
- 'cancelAllOrdersAfter': 1, # Trade API TODO add cancelAllOrders
180
- 'getOrder': 1, # Trade API
181
- 'getOrders': 1, # Trade API
182
- 'getOrdersNew': 16.667,
183
- 'getOrdersIgnoreTradeType': 1, # Trade API
184
- 'getUnfinishedOrdersIgnoreTradeType': 1, # Trade API
185
- 'getFinishedAndPartialOrders': 1, # Trade API
186
- 'getAccountInfo': 16.667,
187
- 'getUserAddress': 16.667,
188
- 'getPayinAddress': 16.667,
189
- 'getWithdrawAddress': 16.667,
190
- 'getWithdrawRecord': 16.667,
191
- 'getChargeRecord': 16.667,
192
- 'getCnyWithdrawRecord': 16.667,
193
- 'getCnyChargeRecord': 16.667,
194
- 'withdraw': 16.667,
195
- # sub accounts
196
- 'addSubUser': 16.667,
197
- 'getSubUserList': 16.667,
198
- 'doTransferFunds': 16.667,
199
- 'createSubUserKey': 16.667, # removed on 2021-03-16 according to the update log in the API doc
200
- # leverage API
201
- 'getLeverAssetsInfo': 16.667,
202
- 'getLeverBills': 16.667,
203
- 'transferInLever': 16.667,
204
- 'transferOutLever': 16.667,
205
- 'loan': 16.667,
206
- 'cancelLoan': 16.667,
207
- 'getLoans': 16.667,
208
- 'getLoanRecords': 16.667,
209
- 'borrow': 16.667,
210
- 'autoBorrow': 16.667,
211
- 'repay': 16.667,
212
- 'doAllRepay': 16.667,
213
- 'getRepayments': 16.667,
214
- 'getFinanceRecords': 16.667,
215
- 'changeInvestMark': 16.667,
216
- 'changeLoop': 16.667,
217
- # cross API
218
- 'getCrossAssets': 16.667,
219
- 'getCrossBills': 16.667,
220
- 'transferInCross': 16.667,
221
- 'transferOutCross': 16.667,
222
- 'doCrossLoan': 16.667,
223
- 'doCrossRepay': 16.667,
224
- 'getCrossRepayRecords': 16.667,
225
- },
226
- },
227
- },
228
- },
229
- 'contract': {
230
- 'v1': {
231
- 'public': {
232
- 'get': {
233
- 'depth': 16.667,
234
- 'fundingRate': 16.667,
235
- 'indexKline': 16.667,
236
- 'indexPrice': 16.667,
237
- 'kline': 16.667,
238
- 'markKline': 16.667,
239
- 'markPrice': 16.667,
240
- 'ticker': 16.667,
241
- 'trade': 16.667,
242
- },
243
- },
244
- },
245
- 'v2': {
246
- 'public': {
247
- 'get': {
248
- 'allForceOrders': 3.334,
249
- 'config/marketList': 3.334,
250
- 'topLongShortAccountRatio': 3.334,
251
- 'topLongShortPositionRatio': 3.334,
252
- 'fundingRate': 3.334,
253
- 'premiumIndex': 3.334,
254
- },
255
- },
256
- 'private': {
257
- 'get': {
258
- 'Fund/balance': 3.334,
259
- 'Fund/getAccount': 3.334,
260
- 'Fund/getBill': 3.334,
261
- 'Fund/getBillTypeList': 3.334,
262
- 'Fund/marginHistory': 3.334,
263
- 'Positions/getPositions': 3.334,
264
- 'Positions/getNominalValue': 3.334,
265
- 'Positions/marginInfo': 3.334,
266
- 'setting/get': 3.334,
267
- 'trade/getAllOrders': 3.334,
268
- 'trade/getOrder': 3.334,
269
- 'trade/getOrderAlgos': 3.334,
270
- 'trade/getTradeList': 3.334,
271
- 'trade/getUndoneOrders': 3.334,
272
- 'trade/tradeHistory': 3.334,
273
- },
274
- 'post': {
275
- 'activity/buyTicket': 3.334,
276
- 'Fund/transferFund': 3.334,
277
- 'Positions/setMarginCoins': 3.334,
278
- 'Positions/updateAppendUSDValue': 3.334,
279
- 'Positions/updateMargin': 3.334,
280
- 'setting/setLeverage': 3.334,
281
- 'setting/setPositionsMode': 3.334,
282
- 'trade/batchOrder': 3.334,
283
- 'trade/batchCancelOrder': 3.334,
284
- 'trade/cancelAlgos': 3.334,
285
- 'trade/cancelAllOrders': 3.334,
286
- 'trade/cancelOrder': 3.334,
287
- 'trade/order': 3.334,
288
- 'trade/orderAlgo': 3.334,
289
- 'trade/updateOrderAlgo': 3.334,
290
- },
291
- },
292
- },
293
- },
294
- },
295
- 'fees': {
296
- 'funding': {
297
- 'withdraw': {},
298
- },
299
- 'trading': {
300
- 'maker': self.parse_number('0.002'),
301
- 'taker': self.parse_number('0.002'),
302
- },
303
- },
304
- 'commonCurrencies': {
305
- 'ANG': 'Anagram',
306
- 'ENT': 'ENTCash',
307
- 'BCHABC': 'BCHABC', # conflict with BCH / BCHA
308
- 'BCHSV': 'BCHSV', # conflict with BCH / BSV
309
- },
310
- 'options': {
311
- 'timeframes': {
312
- 'spot': {
313
- '1m': '1min',
314
- '3m': '3min',
315
- '5m': '5min',
316
- '15m': '15min',
317
- '30m': '30min',
318
- '1h': '1hour',
319
- '2h': '2hour',
320
- '4h': '4hour',
321
- '6h': '6hour',
322
- '12h': '12hour',
323
- '1d': '1day',
324
- '3d': '3day',
325
- '1w': '1week',
326
- },
327
- 'swap': {
328
- '1m': '1M',
329
- '5m': '5M',
330
- '15m': '15M',
331
- '30m': '30M',
332
- '1h': '1H',
333
- '6h': '6H',
334
- '1d': '1D',
335
- '5d': '5D',
336
- },
337
- },
338
- },
339
- 'precisionMode': TICK_SIZE,
340
- 'exceptions': {
341
- 'ws': {
342
- # '1000': ExchangeError, # The call is successful.
343
- '1001': ExchangeError, # General error prompt
344
- '1002': ExchangeError, # Internal Error
345
- '1003': AuthenticationError, # Fail to verify
346
- '1004': AuthenticationError, # The transaction password is locked
347
- '1005': AuthenticationError, # Wrong transaction password, please check it and re-enter。
348
- '1006': PermissionDenied, # Real-name authentication is pending approval or unapproved
349
- '1007': ExchangeError, # Channel does not exist
350
- '1009': OnMaintenance, # This interface is under maintenance
351
- '1010': ExchangeNotAvailable, # Not available now
352
- '1012': PermissionDenied, # Insufficient permissions
353
- '1013': ExchangeError, # Cannot trade, please contact email: support@zb.cn for support.
354
- '1014': ExchangeError, # Cannot sell during the pre-sale period
355
- '2001': InsufficientFunds, # Insufficient CNY account balance
356
- '2002': InsufficientFunds, # Insufficient BTC account balance
357
- '2003': InsufficientFunds, # Insufficient LTC account balance
358
- '2005': InsufficientFunds, # Insufficient ETH account balance
359
- '2006': InsufficientFunds, # ETCInsufficient account balance
360
- '2007': InsufficientFunds, # BTSInsufficient account balance
361
- '2008': InsufficientFunds, # EOSInsufficient account balance
362
- '2009': InsufficientFunds, # BCCInsufficient account balance
363
- '3001': OrderNotFound, # Order not found or is completed
364
- '3002': InvalidOrder, # Invalid amount
365
- '3003': InvalidOrder, # Invalid quantity
366
- '3004': AuthenticationError, # User does not exist
367
- '3005': BadRequest, # Invalid parameter
368
- '3006': PermissionDenied, # Invalid IP or not consistent with the bound IP
369
- '3007': RequestTimeout, # The request time has expired
370
- '3008': ExchangeError, # Transaction not found
371
- '3009': InvalidOrder, # The price exceeds the limit
372
- '3010': PermissionDenied, # It fails to place an order, due to you have set up to prohibit trading of self market.
373
- '3011': InvalidOrder, # The entrusted price is abnormal, please modify it and place order again
374
- '3012': InvalidOrder, # Duplicate custom customerOrderId
375
- '4001': AccountSuspended, # APIThe interface is locked for one hour
376
- '4002': RateLimitExceeded, # Request too frequently
377
- },
378
- 'exact': {
379
- # '1000': 'Successful operation',
380
- '10001': ExchangeError, # Operation failed
381
- '10002': PermissionDenied, # Operation is forbidden
382
- '10003': BadResponse, # Data existed
383
- '10004': BadResponse, # Date not exist
384
- '10005': PermissionDenied, # Forbidden to access the interface
385
- '10006': BadRequest, # Currency invalid or expired
386
- '10007': ExchangeError, # {0}
387
- '10008': ExchangeError, # Operation failed: {0}
388
- '10009': ExchangeError, # URL error
389
- '1001': ExchangeError, # 'General error message',
390
- '10010': AuthenticationError, # API KEY not exist
391
- '10011': AuthenticationError, # API KEY CLOSED
392
- '10012': AccountSuspended, # User API has been frozen, please contact customer service for processing
393
- '10013': AuthenticationError, # API verification failed
394
- '10014': AuthenticationError, # Invalid signature(1001)
395
- '10015': AuthenticationError, # Invalid signature(1002)
396
- '10016': AuthenticationError, # Invalid ip
397
- '10017': PermissionDenied, # Permission denied
398
- '10018': AccountSuspended, # User has been frozen, please contact customer service
399
- '10019': RequestTimeout, # Request time has expired
400
- '1002': ExchangeError, # 'Internal error',
401
- '10020': BadRequest, # {0}Parameter cannot be empty
402
- '10021': BadRequest, # {0}Invalid parameter
403
- '10022': BadRequest, # Request method error
404
- '10023': RateLimitExceeded, # Request frequency is too fast, exceeding the limit allowed by the interface
405
- '10024': AuthenticationError, # Login failed
406
- '10025': ExchangeError, # Non-personal operation
407
- '10026': NetworkError, # Failed to request interface, please try again
408
- '10027': RequestTimeout, # Timed out, please try again later
409
- '10028': ExchangeNotAvailable, # System busy, please try again later
410
- '10029': DDoSProtection, # Frequent operation, please try again later
411
- '1003': AuthenticationError, # 'Verification does not pass',
412
- '10030': BadRequest, # Currency already exist
413
- '10031': BadRequest, # Currency does not exist
414
- '10032': BadRequest, # Market existed
415
- '10033': BadRequest, # Market not exist
416
- '10034': BadRequest, # Currency error
417
- '10035': BadRequest, # Market not open
418
- '10036': BadRequest, # Ineffective market type
419
- '10037': ArgumentsRequired, # User id cannot be empty
420
- '10038': BadRequest, # Market id cannot be empty
421
- '10039': BadResponse, # Failed to get mark price
422
- '1004': AuthenticationError, # 'Funding security password lock',
423
- '10040': BadResponse, # Failed to obtain the opening margin configuration
424
- '10041': BadResponse, # Failed to obtain maintenance margin allocation
425
- '10042': ExchangeError, # Avg. price error
426
- '10043': ExchangeError, # Abnormal acquisition of liquidation price
427
- '10044': ExchangeError, # Unrealized profit and loss acquisition exception
428
- '10045': ExchangeError, # jdbcData source acquisition failed
429
- '10046': ExchangeError, # Invalid position opening direction
430
- '10047': ExchangeError, # The maximum position allowed by the current leverage multiple has been exceeded
431
- '10048': ExchangeError, # The maximum allowable order quantity has been exceeded
432
- '10049': NetworkError, # Failed to get the latest price
433
- '1005': AuthenticationError, # 'Funds security password is incorrect, please confirm and re-enter.',
434
- '1006': AuthenticationError, # 'Real-name certification pending approval or audit does not pass',
435
- '1009': ExchangeNotAvailable, # 'This interface is under maintenance',
436
- '1010': ExchangeNotAvailable, # Not available now
437
- '10100': OnMaintenance, # Sorry! System maintenance, stop operation
438
- '1012': PermissionDenied, # Insufficient permissions
439
- '1013': ExchangeError, # Cannot trade, please contact email: support@zb.cn for support.
440
- '1014': ExchangeError, # Cannot sell during the pre-sale period
441
- '11000': ExchangeError, # Funding change failed
442
- '11001': ExchangeError, # Position change failed
443
- '110011': ExchangeError, # Exceeds the maximum leverage allowed by the position
444
- '11002': ExchangeError, # Funding not exist
445
- '11003': ExchangeError, # Freeze records not exist
446
- '11004': InsufficientFunds, # Insufficient frozen funds
447
- '11005': InvalidOrder, # Insufficient positions
448
- '11006': InsufficientFunds, # Insufficient frozen positions
449
- '11007': OrderNotFound, # Position not exist
450
- '11008': ExchangeError, # The contract have positions, cannot be modified
451
- '11009': ExchangeError, # Failed to query data
452
- '110110': ExchangeError, # Exceed the market's maximum leverage
453
- '11012': InsufficientFunds, # Insufficient margin
454
- '11013': ExchangeError, # Exceeding accuracy limit
455
- '11014': ExchangeError, # Invalid bill type
456
- '11015': AuthenticationError, # Failed to add default account
457
- '11016': AuthenticationError, # Account not exist
458
- '11017': ExchangeError, # Funds are not frozen or unfrozen
459
- '11018': InsufficientFunds, # Insufficient funds
460
- '11019': ExchangeError, # Bill does not exist
461
- '11021': InsufficientFunds, # Inconsistent currency for funds transfer
462
- '11023': ExchangeError, # Same transaction currency
463
- '11030': PermissionDenied, # Position is locked, the operation is prohibited
464
- '11031': ExchangeError, # The number of bill changes is zero
465
- '11032': ExchangeError, # The same request is being processed, please do not submit it repeatedly
466
- '11033': ArgumentsRequired, # Position configuration data is empty
467
- '11034': ExchangeError, # Funding fee is being settled, please do not operate
468
- '12000': InvalidOrder, # Invalid order price
469
- '12001': InvalidOrder, # Invalid order amount
470
- '12002': InvalidOrder, # Invalid order type
471
- '12003': InvalidOrder, # Invalid price accuracy
472
- '12004': InvalidOrder, # Invalid quantity precision
473
- '12005': InvalidOrder, # order value less than the minimum or greater than the maximum
474
- '12006': InvalidOrder, # Customize's order number format is wrong
475
- '12007': InvalidOrder, # Direction error
476
- '12008': InvalidOrder, # Order type error
477
- '12009': InvalidOrder, # Commission type error
478
- '12010': InvalidOrder, # Failed to place the order, the loss of the order placed at self price will exceed margin
479
- '12011': InvalidOrder, # it's not a buz order
480
- '12012': OrderNotFound, # order not exist
481
- '12013': InvalidOrder, # Order user does not match
482
- '12014': InvalidOrder, # Order is still in transaction
483
- '12015': InvalidOrder, # Order preprocessing failed
484
- '12016': InvalidOrder, # Order cannot be canceled
485
- '12017': InvalidOrder, # Transaction Record not exist
486
- '12018': InvalidOrder, # Order failed
487
- '12019': ArgumentsRequired, # self.extend parameter cannot be empty
488
- '12020': ExchangeError, # self.extend Parameter error
489
- '12021': InvalidOrder, # The order price is not within the price limit rules!
490
- '12022': InvalidOrder, # Stop placing an order while the system is calculating the fund fee
491
- '12023': OrderNotFound, # There are no positions to close
492
- '12024': InvalidOrder, # Orders are prohibited, stay tuned!
493
- '12025': InvalidOrder, # Order cancellation is prohibited, so stay tuned!
494
- '12026': DuplicateOrderId, # Order failed, customize order number exists
495
- '12027': ExchangeNotAvailable, # System busy, please try again later
496
- '12028': InvalidOrder, # The market has banned trading
497
- '12029': InvalidOrder, # Forbidden place order, stay tuned
498
- '12201': InvalidOrder, # Delegation strategy does not exist or the status has changed
499
- '12202': InvalidOrder, # Delegation strategy has been changed, cannot be canceled
500
- '12203': InvalidOrder, # Wrong order type
501
- '12204': InvalidOrder, # Invalid trigger price
502
- '12205': InvalidOrder, # The trigger price must be greater than the market’s selling price or lower than the buying price.
503
- '12206': InvalidOrder, # Direction and order type do not match
504
- '12207': RateLimitExceeded, # Submission failed, exceeding the allowed limit
505
- '13001': AuthenticationError, # User not exist
506
- '13002': PermissionDenied, # User did not activate futures
507
- # '13003': AuthenticationError, # User is locked
508
- '13003': InvalidOrder, # Margin gear is not continuous
509
- '13004': InvalidOrder, # The margin quick calculation amount is less than 0
510
- '13005': RateLimitExceeded, # You have exceeded the number of exports that day
511
- '13006': ExchangeError, # No markets are bookmarked
512
- '13007': ExchangeError, # Market not favorited
513
- '13008': ExchangeError, # Not in any market user whitelist
514
- '13009': ExchangeError, # Not in the whitelist of users in self market
515
- '14000': ExchangeError, # {0}not support
516
- '14001': AuthenticationError, # Already logged in, no need to log in multiple times
517
- '14002': AuthenticationError, # Not logged in yet, please log in before subscribing
518
- '14003': ExchangeError, # This is a channel for one-time queries, no need to unsubscribe
519
- '14100': ExchangeError, # Accuracy does not support
520
- '14101': RateLimitExceeded, # Request exceeded frequency limit
521
- '14200': ArgumentsRequired, # id empty
522
- '14300': ExchangeError, # activity not exist
523
- '14301': ExchangeError, # The event has been opened and cannot be admitted
524
- '14302': ExchangeError, # The purchase time has passed and cannot be admitted
525
- '14303': ExchangeError, # Not yet open for the purchase
526
- '14305': ExchangeError, # Cannot enter, the maximum number of returns has been exceeded
527
- '14306': ExchangeError, # Cannot repeat admission
528
- '14307': InvalidOrder, # Unable to cancel, status has been changed
529
- '14308': InvalidOrder, # Unable to cancel, the amount does not match
530
- '14309': ExchangeError, # Activity has not started
531
- '14310': NotSupported, # Activity is over
532
- '14311': NotSupported, # The activity does not support orders placed in self market
533
- '14312': ExchangeError, # You have not participated in self activity
534
- '14313': PermissionDenied, # Sorry! The purchase failed, the maximum number of participants has been reached
535
- '14314': ExchangeError, # Active period id error
536
- '2001': InsufficientFunds, # 'Insufficient CNY Balance',
537
- '2002': InsufficientFunds, # 'Insufficient BTC Balance',
538
- '2003': InsufficientFunds, # 'Insufficient LTC Balance',
539
- '2005': InsufficientFunds, # 'Insufficient ETH Balance',
540
- '2006': InsufficientFunds, # 'Insufficient ETC Balance',
541
- '2007': InsufficientFunds, # 'Insufficient BTS Balance',
542
- '2008': InsufficientFunds, # EOSInsufficient account balance
543
- '2009': InsufficientFunds, # 'Account balance is not enough',
544
- '3001': OrderNotFound, # 'Pending orders not found',
545
- '3002': InvalidOrder, # 'Invalid price',
546
- '3003': InvalidOrder, # 'Invalid amount',
547
- '3004': AuthenticationError, # 'User does not exist',
548
- '3005': BadRequest, # 'Invalid parameter',
549
- '3006': AuthenticationError, # 'Invalid IP or inconsistent with the bound IP',
550
- '3007': AuthenticationError, # 'The request time has expired',
551
- '3008': OrderNotFound, # 'Transaction records not found',
552
- '3009': InvalidOrder, # 'The price exceeds the limit',
553
- '3010': PermissionDenied, # It fails to place an order, due to you have set up to prohibit trading of self market.
554
- '3011': InvalidOrder, # 'The entrusted price is abnormal, please modify it and place order again',
555
- '3012': InvalidOrder, # Duplicate custom customerOrderId
556
- '4001': ExchangeNotAvailable, # 'API interface is locked or not enabled',
557
- '4002': RateLimitExceeded, # 'Request too often',
558
- '9999': ExchangeError, # Unknown error
559
- },
560
- 'broad': {
561
- '提币地址有误, 请先添加提币地址。': InvalidAddress, # {"code":1001,"message":"提币地址有误,请先添加提币地址。"}
562
- '资金不足,无法划账': InsufficientFunds, # {"code":1001,"message":"资金不足,无法划账"}
563
- '响应超时': RequestTimeout, # {"code":1001,"message":"响应超时"}
564
- },
565
- },
566
- })
567
-
568
- async def fetch_markets(self, params={}):
569
- """
570
- retrieves data on all markets for zb
571
- :param dict params: extra parameters specific to the exchange api endpoint
572
- :returns [dict]: an array of objects representing market data
573
- """
574
- #
575
- # {
576
- # "zb_qc":{
577
- # "amountScale":2,
578
- # "minAmount":0.01,
579
- # "minSize":5,
580
- # "priceScale":4,
581
- # },
582
- # }
583
- #
584
- promises = [self.spotV1PublicGetMarkets(params), self.contractV2PublicGetConfigMarketList(params)]
585
- promises = await asyncio.gather(*promises)
586
- markets = promises[0]
587
- contracts = promises[1]
588
- #
589
- # {
590
- # BTC_USDT: {
591
- # symbol: 'BTC_USDT',
592
- # buyerCurrencyId: '6',
593
- # contractType: '1',
594
- # defaultMarginMode: '1',
595
- # marketType: '2',
596
- # historyDBName: 'trade_history_readonly.dbc',
597
- # defaultLeverage: '20',
598
- # id: '100',
599
- # canCancelOrder: True,
600
- # area: '1',
601
- # mixMarginCoinName: 'usdt',
602
- # fundingRateRatio: '0.25',
603
- # marginCurrencyName: 'usdt',
604
- # minTradeMoney: '0.0001',
605
- # enableTime: '1638954000000',
606
- # maxTradeMoney: '10000000',
607
- # canTrade: True,
608
- # maxLeverage: '125',
609
- # defaultPositionsMode: '2',
610
- # onlyWhitelistVisible: False,
611
- # riskWarnRatio: '0.8',
612
- # marginDecimal: '8',
613
- # spot: False,
614
- # status: '1',
615
- # amountDecimal: '3',
616
- # leverage: False,
617
- # minAmount: '0.001',
618
- # canOrder: True,
619
- # duration: '1',
620
- # feeDecimal: '8',
621
- # sellerCurrencyId: '1',
622
- # maxAmount: '1000',
623
- # canOpenPosition: True,
624
- # isSupportMixMargin: False,
625
- # markPriceLimitRate: '0.05',
626
- # marginCurrencyId: '6',
627
- # stopFundingFee: False,
628
- # priceDecimal: '2',
629
- # lightenUpFeeRate: '0',
630
- # futures: True,
631
- # sellerCurrencyName: 'btc',
632
- # marketPriceLimitRate: '0.05',
633
- # canRebate: True,
634
- # marketName: 'BTC_USDT',
635
- # depth: [0.01, 0.1, 1],
636
- # createTime: '1607590430094',
637
- # mixMarginCoinIds: [6],
638
- # buyerCurrencyName: 'usdt',
639
- # stopService: False
640
- # },
641
- # }
642
- #
643
- contractsData = self.safe_value(contracts, 'data', [])
644
- contractsById = self.index_by(contractsData, 'marketName')
645
- dataById = self.deep_extend(contractsById, markets)
646
- keys = list(dataById.keys())
647
- result = []
648
- for i in range(0, len(keys)):
649
- id = keys[i]
650
- market = dataById[id]
651
- baseId, quoteId = id.split('_')
652
- base = self.safe_currency_code(baseId)
653
- quote = self.safe_currency_code(quoteId)
654
- settleId = self.safe_value(market, 'marginCurrencyName')
655
- settle = self.safe_currency_code(settleId)
656
- spot = settle is None
657
- swap = self.safe_value(market, 'futures', False)
658
- linear = True if swap else None
659
- active = True
660
- symbol = base + '/' + quote
661
- if swap:
662
- status = self.safe_string(market, 'status')
663
- active = (status == '1')
664
- symbol = base + '/' + quote + ':' + settle
665
- result.append({
666
- 'id': id,
667
- 'symbol': symbol,
668
- 'base': base,
669
- 'quote': quote,
670
- 'settle': settle,
671
- 'baseId': baseId,
672
- 'quoteId': quoteId,
673
- 'settleId': settleId,
674
- 'type': 'swap' if swap else 'spot',
675
- 'spot': spot,
676
- 'margin': False,
677
- 'swap': swap,
678
- 'future': False,
679
- 'option': False,
680
- 'active': active,
681
- 'contract': swap,
682
- 'linear': linear,
683
- 'inverse': not linear if swap else None,
684
- 'contractSize': None,
685
- 'expiry': None,
686
- 'expiryDatetime': None,
687
- 'strike': None,
688
- 'optionType': None,
689
- 'precision': {
690
- 'amount': self.parse_number(self.parse_precision(self.safe_string_2(market, 'amountScale', 'amountDecimal'))),
691
- 'price': self.parse_number(self.parse_precision(self.safe_string_2(market, 'priceScale', 'priceDecimal'))),
692
- },
693
- 'limits': {
694
- 'leverage': {
695
- 'min': None,
696
- 'max': self.safe_number(market, 'maxLeverage'),
697
- },
698
- 'amount': {
699
- 'min': self.safe_number(market, 'minAmount'),
700
- 'max': self.safe_number(market, 'maxAmount'),
701
- },
702
- 'price': {
703
- 'min': None,
704
- 'max': None,
705
- },
706
- 'cost': {
707
- 'min': self.safe_number_2(market, 'minSize', 'minTradeMoney'),
708
- 'max': self.safe_number(market, 'maxTradeMoney'),
709
- },
710
- },
711
- 'info': market,
712
- })
713
- return result
714
-
715
- async def fetch_currencies(self, params={}):
716
- """
717
- fetches all available currencies on an exchange
718
- :param dict params: extra parameters specific to the zb api endpoint
719
- :returns dict: an associative dictionary of currencies
720
- """
721
- response = await self.spotV1PublicGetGetFeeInfo(params)
722
- #
723
- # {
724
- # "code":1000,
725
- # "message":"success",
726
- # "result":{
727
- # "USDT":[
728
- # {
729
- # "chainName":"TRC20",
730
- # "canWithdraw":true,
731
- # "fee":1.0,
732
- # "mainChainName":"TRX",
733
- # "canDeposit":true
734
- # },
735
- # {
736
- # "chainName":"OMNI",
737
- # "canWithdraw":true,
738
- # "fee":5.0,
739
- # "mainChainName":"BTC",
740
- # "canDeposit":true
741
- # },
742
- # {
743
- # "chainName":"ERC20",
744
- # "canWithdraw":true,
745
- # "fee":15.0,
746
- # "mainChainName":"ETH",
747
- # "canDeposit":true
748
- # }
749
- # ],
750
- # }
751
- # }
752
- #
753
- currencies = self.safe_value(response, 'result', {})
754
- ids = list(currencies.keys())
755
- result = {}
756
- for i in range(0, len(ids)):
757
- id = ids[i]
758
- currency = currencies[id]
759
- code = self.safe_currency_code(id)
760
- isWithdrawEnabled = True
761
- isDepositEnabled = True
762
- fees = {}
763
- for j in range(0, len(currency)):
764
- networkItem = currency[j]
765
- network = self.safe_string_2(networkItem, 'chainName', 'mainChainName')
766
- # name = self.safe_string(networkItem, 'name')
767
- withdrawFee = self.safe_number(networkItem, 'fee')
768
- depositEnable = self.safe_value(networkItem, 'canDeposit')
769
- withdrawEnable = self.safe_value(networkItem, 'canWithdraw')
770
- isDepositEnabled = isDepositEnabled or depositEnable
771
- isWithdrawEnabled = isWithdrawEnabled or withdrawEnable
772
- fees[network] = withdrawFee
773
- active = (isWithdrawEnabled and isDepositEnabled)
774
- result[code] = {
775
- 'id': id,
776
- 'name': None,
777
- 'code': code,
778
- 'precision': None,
779
- 'info': currency,
780
- 'active': active,
781
- 'deposit': isDepositEnabled,
782
- 'withdraw': isWithdrawEnabled,
783
- 'fee': None,
784
- 'fees': fees,
785
- 'limits': self.limits,
786
- }
787
- return result
788
-
789
- def parse_balance(self, response):
790
- balances = self.safe_value(response['result'], 'coins')
791
- result = {
792
- 'info': response,
793
- }
794
- for i in range(0, len(balances)):
795
- balance = balances[i]
796
- # { enName: "BTC",
797
- # freez: "0.00000000",
798
- # unitDecimal: 8, # always 8
799
- # cnName: "BTC",
800
- # isCanRecharge: True, # TODO: should use self
801
- # unitTag: "฿",
802
- # isCanWithdraw: True, # TODO: should use self
803
- # available: "0.00000000",
804
- # key: "btc" }
805
- account = self.account()
806
- currencyId = self.safe_string(balance, 'key')
807
- code = self.safe_currency_code(currencyId)
808
- account['free'] = self.safe_string(balance, 'available')
809
- account['used'] = self.safe_string(balance, 'freez')
810
- result[code] = account
811
- return self.safe_balance(result)
812
-
813
- def parse_swap_balance(self, response):
814
- result = {
815
- 'info': response,
816
- }
817
- data = self.safe_value(response, 'data', {})
818
- for i in range(0, len(data)):
819
- balance = data[i]
820
- #
821
- # {
822
- # "userId": "6896693805014120448",
823
- # "currencyId": "6",
824
- # "currencyName": "usdt",
825
- # "amount": "30.56585118",
826
- # "freezeAmount": "0",
827
- # "contractType": 1,
828
- # "id": "6899113714763638819",
829
- # "createTime": "1644876888934",
830
- # "modifyTime": "1645787446037",
831
- # "accountBalance": "30.56585118",
832
- # "allMargin": "0",
833
- # "allowTransferOutAmount": "30.56585118"
834
- # },
835
- #
836
- code = self.safe_currency_code(self.safe_string(balance, 'currencyName'))
837
- account = self.account()
838
- account['total'] = self.safe_string(balance, 'accountBalance')
839
- account['free'] = self.safe_string(balance, 'allowTransferOutAmount')
840
- account['used'] = self.safe_string(balance, 'freezeAmount')
841
- result[code] = account
842
- return self.safe_balance(result)
843
-
844
- def parse_margin_balance(self, response, marginMode):
845
- result = {
846
- 'info': response,
847
- }
848
- levers = None
849
- if marginMode == 'isolated':
850
- message = self.safe_value(response, 'message', {})
851
- data = self.safe_value(message, 'datas', {})
852
- levers = self.safe_value(data, 'levers', [])
853
- else:
854
- crossResponse = self.safe_value(response, 'result', {})
855
- levers = self.safe_value(crossResponse, 'list', [])
856
- for i in range(0, len(levers)):
857
- balance = levers[i]
858
- #
859
- # Isolated Margin
860
- #
861
- # {
862
- # "cNetUSD": "0.00",
863
- # "repayLeverShow": "-",
864
- # "cCanLoanIn": "0.002115400000000",
865
- # "fNetCNY": "147.76081161",
866
- # "fLoanIn": "0.00",
867
- # "repayLevel": 0,
868
- # "level": 1,
869
- # "netConvertCNY": "147.760811613032",
870
- # "cFreeze": "0.00",
871
- # "cUnitTag": "BTC",
872
- # "version": 1646783178609,
873
- # "cAvailableUSD": "0.00",
874
- # "cNetCNY": "0.00",
875
- # "riskRate": "-",
876
- # "fAvailableUSD": "20.49273433",
877
- # "fNetUSD": "20.49273432",
878
- # "cShowName": "BTC",
879
- # "leverMultiple": "5.00",
880
- # "couldTransferOutFiat": "20.49273433",
881
- # "noticeLine": "1.13",
882
- # "fFreeze": "0.00",
883
- # "cUnitDecimal": 8,
884
- # "fCanLoanIn": "81.970937320000000",
885
- # "cAvailable": "0.00",
886
- # "repayLock": False,
887
- # "status": 1,
888
- # "forbidType": 0,
889
- # "totalConvertCNY": "147.760811613032",
890
- # "cAvailableCNY": "0.00",
891
- # "unwindPrice": "0.00",
892
- # "fOverdraft": "0.00",
893
- # "fShowName": "USDT",
894
- # "statusShow": "%E6%AD%A3%E5%B8%B8",
895
- # "cOverdraft": "0.00",
896
- # "netConvertUSD": "20.49273433",
897
- # "cNetBtc": "0.00",
898
- # "loanInConvertCNY": "0.00",
899
- # "fAvailableCNY": "147.760811613032",
900
- # "key": "btcusdt",
901
- # "fNetBtc": "0.0005291",
902
- # "fUnitDecimal": 8,
903
- # "loanInConvertUSD": "0.00",
904
- # "showName": "BTC/USDT",
905
- # "startLine": "1.25",
906
- # "totalConvertUSD": "20.49273433",
907
- # "couldTransferOutCoin": "0.00",
908
- # "cEnName": "BTC",
909
- # "leverMultipleInterest": "3.00",
910
- # "fAvailable": "20.49273433",
911
- # "fEnName": "USDT",
912
- # "forceRepayLine": "1.08",
913
- # "cLoanIn": "0.00"
914
- # }
915
- #
916
- # Cross Margin
917
- #
918
- # [
919
- # {
920
- # "fundType": 2,
921
- # "loanIn": 0,
922
- # "amount": 0,
923
- # "freeze": 0,
924
- # "overdraft": 0,
925
- # "key": "BTC",
926
- # "canTransferOut": 0
927
- # },
928
- # ],
929
- #
930
- account = self.account()
931
- if marginMode == 'isolated':
932
- code = self.safe_currency_code(self.safe_string(balance, 'fShowName'))
933
- account['total'] = self.safe_string(balance, 'fAvailableUSD') # total amount in USD
934
- account['free'] = self.safe_string(balance, 'couldTransferOutFiat')
935
- account['used'] = self.safe_string(balance, 'fFreeze')
936
- result[code] = account
937
- else:
938
- code = self.safe_currency_code(self.safe_string(balance, 'key'))
939
- account['total'] = self.safe_string(balance, 'amount')
940
- account['free'] = self.safe_string(balance, 'canTransferOut')
941
- account['used'] = self.safe_string(balance, 'freeze')
942
- result[code] = account
943
- return self.safe_balance(result)
944
-
945
- async def fetch_balance(self, params={}):
946
- """
947
- query for balance and get the amount of funds available for trading or funds locked in orders
948
- :param dict params: extra parameters specific to the zb api endpoint
949
- :param str params['marginMode']: 'cross' or 'isolated'
950
- :returns dict: a `balance structure <https://docs.ccxt.com/en/latest/manual.html?#balance-structure>`
951
- """
952
- await self.load_markets()
953
- marketType, marketTypeQuery = self.handle_market_type_and_params('fetchBalance', None, params)
954
- marginMode, query = self.handle_margin_mode_and_params('fetchBalance', marketTypeQuery)
955
- swap = (marketType == 'swap')
956
- marginMethod = 'spotV1PrivateGetGetCrossAssets' if (marginMode == 'cross') else 'spotV1PrivateGetGetLeverAssetsInfo'
957
- method = self.get_supported_mapping(marketType, {
958
- 'spot': 'spotV1PrivateGetGetAccountInfo',
959
- 'swap': 'contractV2PrivateGetFundBalance',
960
- 'margin': marginMethod,
961
- })
962
- if marginMode == 'isolated':
963
- method = 'spotV1PrivateGetGetLeverAssetsInfo'
964
- elif marginMode == 'cross':
965
- method = 'spotV1PrivateGetGetCrossAssets'
966
- request = {
967
- # 'futuresAccountType': 1, # SWAP
968
- # 'currencyId': currency['id'], # SWAP
969
- # 'currencyName': 'usdt', # SWAP
970
- }
971
- if swap:
972
- request['futuresAccountType'] = 1
973
- response = await getattr(self, method)(self.extend(request, query))
974
- #
975
- # Spot
976
- #
977
- # {
978
- # "result": {
979
- # "coins": [
980
- # {
981
- # "isCanWithdraw": "true",
982
- # "canLoan": False,
983
- # "fundstype": 51,
984
- # "showName": "ZB",
985
- # "isCanRecharge": "true",
986
- # "cnName": "ZB",
987
- # "enName": "ZB",
988
- # "available": "0",
989
- # "freez": "0",
990
- # "unitTag": "ZB",
991
- # "key": "zb",
992
- # "unitDecimal": 8
993
- # },
994
- # ],
995
- # "version": 1645856691340,
996
- # "base": {
997
- # "auth_google_enabled": True,
998
- # "auth_mobile_enabled": False,
999
- # "trade_password_enabled": True,
1000
- # "username": "blank@gmail.com"
1001
- # }
1002
- # },
1003
- # "leverPerm": True,
1004
- # "otcPerm": False,
1005
- # "assetPerm": True,
1006
- # "moneyPerm": True,
1007
- # "subUserPerm": True,
1008
- # "entrustPerm": True
1009
- # }
1010
- #
1011
- # Swap
1012
- #
1013
- # {
1014
- # "code": 10000,
1015
- # "data": [
1016
- # {
1017
- # "userId": "6896693805014120448",
1018
- # "currencyId": "6",
1019
- # "currencyName": "usdt",
1020
- # "amount": "30.56585118",
1021
- # "freezeAmount": "0",
1022
- # "contractType": 1,
1023
- # "id": "6899113714763638819",
1024
- # "createTime": "1644876888934",
1025
- # "modifyTime": "1645787446037",
1026
- # "accountBalance": "30.56585118",
1027
- # "allMargin": "0",
1028
- # "allowTransferOutAmount": "30.56585118"
1029
- # },
1030
- # ],
1031
- # "desc": "操作成功"
1032
- # }
1033
- #
1034
- # Isolated Margin
1035
- #
1036
- # {
1037
- # "code": 1000,
1038
- # "message": {
1039
- # "des": "success",
1040
- # "isSuc": True,
1041
- # "datas": {
1042
- # "leverPerm": True,
1043
- # "levers": [
1044
- # {
1045
- # "cNetUSD": "0.00",
1046
- # "repayLeverShow": "-",
1047
- # "cCanLoanIn": "0.002115400000000",
1048
- # "fNetCNY": "147.76081161",
1049
- # "fLoanIn": "0.00",
1050
- # "repayLevel": 0,
1051
- # "level": 1,
1052
- # "netConvertCNY": "147.760811613032",
1053
- # "cFreeze": "0.00",
1054
- # "cUnitTag": "BTC",
1055
- # "version": 1646783178609,
1056
- # "cAvailableUSD": "0.00",
1057
- # "cNetCNY": "0.00",
1058
- # "riskRate": "-",
1059
- # "fAvailableUSD": "20.49273433",
1060
- # "fNetUSD": "20.49273432",
1061
- # "cShowName": "BTC",
1062
- # "leverMultiple": "5.00",
1063
- # "couldTransferOutFiat": "20.49273433",
1064
- # "noticeLine": "1.13",
1065
- # "fFreeze": "0.00",
1066
- # "cUnitDecimal": 8,
1067
- # "fCanLoanIn": "81.970937320000000",
1068
- # "cAvailable": "0.00",
1069
- # "repayLock": False,
1070
- # "status": 1,
1071
- # "forbidType": 0,
1072
- # "totalConvertCNY": "147.760811613032",
1073
- # "cAvailableCNY": "0.00",
1074
- # "unwindPrice": "0.00",
1075
- # "fOverdraft": "0.00",
1076
- # "fShowName": "USDT",
1077
- # "statusShow": "%E6%AD%A3%E5%B8%B8",
1078
- # "cOverdraft": "0.00",
1079
- # "netConvertUSD": "20.49273433",
1080
- # "cNetBtc": "0.00",
1081
- # "loanInConvertCNY": "0.00",
1082
- # "fAvailableCNY": "147.760811613032",
1083
- # "key": "btcusdt",
1084
- # "fNetBtc": "0.0005291",
1085
- # "fUnitDecimal": 8,
1086
- # "loanInConvertUSD": "0.00",
1087
- # "showName": "BTC/USDT",
1088
- # "startLine": "1.25",
1089
- # "totalConvertUSD": "20.49273433",
1090
- # "couldTransferOutCoin": "0.00",
1091
- # "cEnName": "BTC",
1092
- # "leverMultipleInterest": "3.00",
1093
- # "fAvailable": "20.49273433",
1094
- # "fEnName": "USDT",
1095
- # "forceRepayLine": "1.08",
1096
- # "cLoanIn": "0.00"
1097
- # }
1098
- # ]
1099
- # }
1100
- # }
1101
- # }
1102
- #
1103
- # Cross Margin
1104
- #
1105
- # {
1106
- # "code": 1000,
1107
- # "message": "操作成功",
1108
- # "result": {
1109
- # "loanIn": 0,
1110
- # "total": 71.167,
1111
- # "riskRate": "-",
1112
- # "list" :[
1113
- # {
1114
- # "fundType": 2,
1115
- # "loanIn": 0,
1116
- # "amount": 0,
1117
- # "freeze": 0,
1118
- # "overdraft": 0,
1119
- # "key": "BTC",
1120
- # "canTransferOut": 0
1121
- # },
1122
- # ],
1123
- # "net": 71.167
1124
- # }
1125
- # }
1126
- #
1127
- # todo: use self somehow
1128
- # permissions = response['result']['base']
1129
- if swap:
1130
- return self.parse_swap_balance(response)
1131
- elif marginMode is not None:
1132
- return self.parse_margin_balance(response, marginMode)
1133
- else:
1134
- return self.parse_balance(response)
1135
-
1136
- def parse_deposit_address(self, depositAddress, currency=None):
1137
- #
1138
- # fetchDepositAddress
1139
- #
1140
- # {
1141
- # "key": "0x0af7f36b8f09410f3df62c81e5846da673d4d9a9"
1142
- # }
1143
- #
1144
- # fetchDepositAddresses
1145
- #
1146
- # {
1147
- # "blockChain": "btc",
1148
- # "isUseMemo": False,
1149
- # "address": "1LL5ati6pXHZnTGzHSA3rWdqi4mGGXudwM",
1150
- # "canWithdraw": True,
1151
- # "canDeposit": True
1152
- # }
1153
- # {
1154
- # "blockChain": "bts",
1155
- # "isUseMemo": True,
1156
- # "account": "btstest",
1157
- # "memo": "123",
1158
- # "canWithdraw": True,
1159
- # "canDeposit": True
1160
- # }
1161
- #
1162
- address = self.safe_string_2(depositAddress, 'key', 'address')
1163
- tag = None
1164
- memo = self.safe_string(depositAddress, 'memo')
1165
- if memo is not None:
1166
- tag = memo
1167
- elif address.find('_') >= 0:
1168
- parts = address.split('_')
1169
- address = parts[0] # WARNING: MAY BE tag_address INSTEAD OF address_tag FOR SOME CURRENCIESnot !
1170
- tag = parts[1]
1171
- self.check_address(address)
1172
- currencyId = self.safe_string(depositAddress, 'blockChain')
1173
- code = self.safe_currency_code(currencyId, currency)
1174
- return {
1175
- 'currency': code,
1176
- 'address': address,
1177
- 'tag': tag,
1178
- 'network': None,
1179
- 'info': depositAddress,
1180
- }
1181
-
1182
- async def fetch_deposit_addresses(self, codes=None, params={}):
1183
- await self.load_markets()
1184
- response = await self.spotV1PrivateGetGetPayinAddress(params)
1185
- #
1186
- # {
1187
- # "code": 1000,
1188
- # "message": {
1189
- # "des": "success",
1190
- # "isSuc": True,
1191
- # "datas": [
1192
- # {
1193
- # "blockChain": "btc",
1194
- # "isUseMemo": False,
1195
- # "address": "1LL5ati6pXHZnTGzHSA3rWdqi4mGGXudwM",
1196
- # "canWithdraw": True,
1197
- # "canDeposit": True
1198
- # },
1199
- # {
1200
- # "blockChain": "bts",
1201
- # "isUseMemo": True,
1202
- # "account": "btstest",
1203
- # "memo": "123",
1204
- # "canWithdraw": True,
1205
- # "canDeposit": True
1206
- # },
1207
- # ]
1208
- # }
1209
- # }
1210
- #
1211
- message = self.safe_value(response, 'message', {})
1212
- datas = self.safe_value(message, 'datas', [])
1213
- return self.parse_deposit_addresses(datas, codes)
1214
-
1215
- async def fetch_deposit_address(self, code: str, params={}):
1216
- """
1217
- fetch the deposit address for a currency associated with self account
1218
- :param str code: unified currency code
1219
- :param dict params: extra parameters specific to the zb api endpoint
1220
- :returns dict: an `address structure <https://docs.ccxt.com/#/?id=address-structure>`
1221
- """
1222
- await self.load_markets()
1223
- currency = self.currency(code)
1224
- request = {
1225
- 'currency': currency['id'],
1226
- }
1227
- response = await self.spotV1PrivateGetGetUserAddress(self.extend(request, params))
1228
- #
1229
- # {
1230
- # "code": 1000,
1231
- # "message": {
1232
- # "des": "success",
1233
- # "isSuc": True,
1234
- # "datas": {
1235
- # "key": "0x0af7f36b8f09410f3df62c81e5846da673d4d9a9"
1236
- # }
1237
- # }
1238
- # }
1239
- #
1240
- message = self.safe_value(response, 'message', {})
1241
- datas = self.safe_value(message, 'datas', {})
1242
- return self.parse_deposit_address(datas, currency)
1243
-
1244
- async def fetch_order_book(self, symbol: str, limit: Optional[int] = None, params={}):
1245
- """
1246
- fetches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
1247
- :param str symbol: unified symbol of the market to fetch the order book for
1248
- :param int|None limit: the maximum amount of order book entries to return
1249
- :param dict params: extra parameters specific to the zb api endpoint
1250
- :returns dict: A dictionary of `order book structures <https://docs.ccxt.com/#/?id=order-book-structure>` indexed by market symbols
1251
- """
1252
- await self.load_markets()
1253
- market = self.market(symbol)
1254
- request = {
1255
- # 'market': market['id'], # only applicable to SPOT
1256
- # 'symbol': market['id'], # only applicable to SWAP
1257
- # 'size': limit, # 1-50 applicable to SPOT and SWAP
1258
- # 'merge': 5.0, # float default depth only applicable to SPOT
1259
- # 'scale': 5, # int accuracy, only applicable to SWAP
1260
- }
1261
- marketIdField = 'symbol' if market['swap'] else 'market'
1262
- request[marketIdField] = market['id']
1263
- method = self.get_supported_mapping(market['type'], {
1264
- 'spot': 'spotV1PublicGetDepth',
1265
- 'swap': 'contractV1PublicGetDepth',
1266
- })
1267
- if limit is not None:
1268
- request['size'] = limit
1269
- response = await getattr(self, method)(self.extend(request, params))
1270
- #
1271
- # Spot
1272
- #
1273
- # {
1274
- # "asks":[
1275
- # [35000.0,0.2741],
1276
- # [34949.0,0.0173],
1277
- # [34900.0,0.5004],
1278
- # ],
1279
- # "bids":[
1280
- # [34119.32,0.0030],
1281
- # [34107.83,0.1500],
1282
- # [34104.42,0.1500],
1283
- # ],
1284
- # "timestamp":1624536510
1285
- # }
1286
- #
1287
- # Swap
1288
- #
1289
- # {
1290
- # "code": 10000,
1291
- # "desc": "操作成功",
1292
- # "data": {
1293
- # "asks": [
1294
- # [43416.6,0.02],
1295
- # [43418.25,0.04],
1296
- # [43425.82,0.02]
1297
- # ],
1298
- # "bids": [
1299
- # [43414.61,0.1],
1300
- # [43414.18,0.04],
1301
- # [43413.03,0.05]
1302
- # ],
1303
- # "time": 1645087743071
1304
- # }
1305
- # }
1306
- #
1307
- result = None
1308
- timestamp = None
1309
- if market['type'] == 'swap':
1310
- result = self.safe_value(response, 'data')
1311
- timestamp = self.safe_integer(result, 'time')
1312
- else:
1313
- result = response
1314
- timestamp = self.safe_timestamp(response, 'timestamp')
1315
- return self.parse_order_book(result, symbol, timestamp)
1316
-
1317
- async def fetch_tickers(self, symbols: Optional[List[str]] = None, params={}):
1318
- """
1319
- fetches price tickers for multiple markets, statistical calculations with the information calculated over the past 24 hours each market
1320
- :param [str]|None symbols: unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
1321
- :param dict params: extra parameters specific to the zb api endpoint
1322
- :returns dict: a dictionary of `ticker structures <https://docs.ccxt.com/#/?id=ticker-structure>`
1323
- """
1324
- await self.load_markets()
1325
- symbols = self.market_symbols(symbols)
1326
- response = await self.spotV1PublicGetAllTicker(params)
1327
- result = {}
1328
- marketsByIdWithoutUnderscore = {}
1329
- marketIds = self.ids
1330
- for i in range(0, len(marketIds)):
1331
- marketId = marketIds[i]
1332
- tickerId = marketId.replace('_', '')
1333
- marketsByIdWithoutUnderscore[tickerId] = marketId
1334
- ids = list(response.keys())
1335
- for i in range(0, len(ids)):
1336
- marketId = self.safe_value(marketsByIdWithoutUnderscore, ids[i])
1337
- market = self.safe_market(marketId, None, '_')
1338
- if market is not None:
1339
- symbol = market['symbol']
1340
- ticker = self.safe_value(response, ids[i])
1341
- if ticker is not None:
1342
- result[symbol] = self.parse_ticker(ticker, market)
1343
- return self.filter_by_array(result, 'symbol', symbols)
1344
-
1345
- async def fetch_ticker(self, symbol: str, params={}):
1346
- """
1347
- fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
1348
- :param str symbol: unified symbol of the market to fetch the ticker for
1349
- :param dict params: extra parameters specific to the zb api endpoint
1350
- :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
1351
- """
1352
- await self.load_markets()
1353
- market = self.market(symbol)
1354
- request = {
1355
- # 'market': market['id'], # only applicable to SPOT
1356
- # 'symbol': market['id'], # only applicable to SWAP
1357
- }
1358
- marketIdField = 'symbol' if market['swap'] else 'market'
1359
- request[marketIdField] = market['id']
1360
- method = self.get_supported_mapping(market['type'], {
1361
- 'spot': 'spotV1PublicGetTicker',
1362
- 'swap': 'contractV1PublicGetTicker',
1363
- })
1364
- response = await getattr(self, method)(self.extend(request, params))
1365
- #
1366
- # Spot
1367
- #
1368
- # {
1369
- # "date":"1624399623587",
1370
- # "ticker":{
1371
- # "high":"33298.38",
1372
- # "vol":"56152.9012",
1373
- # "last":"32578.55",
1374
- # "low":"28808.19",
1375
- # "buy":"32572.68",
1376
- # "sell":"32615.37",
1377
- # "turnover":"1764201303.6100",
1378
- # "open":"31664.85",
1379
- # "riseRate":"2.89"
1380
- # }
1381
- # }
1382
- #
1383
- # Swap
1384
- #
1385
- # {
1386
- # "code": 10000,
1387
- # "desc": "操作成功",
1388
- # "data": {
1389
- # "BTC_USDT": [44053.47,44357.77,42911.54,43297.79,53471.264,-1.72,1645093002,302201.255084]
1390
- # }
1391
- # }
1392
- #
1393
- ticker = None
1394
- if market['type'] == 'swap':
1395
- ticker = {}
1396
- data = self.safe_value(response, 'data')
1397
- values = self.safe_value(data, market['id'], [])
1398
- for i in range(0, len(values)):
1399
- ticker['open'] = self.safe_value(values, 0)
1400
- ticker['high'] = self.safe_value(values, 1)
1401
- ticker['low'] = self.safe_value(values, 2)
1402
- ticker['last'] = self.safe_value(values, 3)
1403
- ticker['vol'] = self.safe_value(values, 4)
1404
- ticker['riseRate'] = self.safe_value(values, 5)
1405
- else:
1406
- ticker = self.safe_value(response, 'ticker', {})
1407
- ticker['date'] = self.safe_value(response, 'date')
1408
- return self.parse_ticker(ticker, market)
1409
-
1410
- def parse_ticker(self, ticker, market=None):
1411
- #
1412
- # Spot
1413
- #
1414
- # {
1415
- # "date":"1624399623587", # injected from outside
1416
- # "high":"33298.38",
1417
- # "vol":"56152.9012",
1418
- # "last":"32578.55",
1419
- # "low":"28808.19",
1420
- # "buy":"32572.68",
1421
- # "sell":"32615.37",
1422
- # "turnover":"1764201303.6100",
1423
- # "open":"31664.85",
1424
- # "riseRate":"2.89"
1425
- # }
1426
- #
1427
- # Swap
1428
- #
1429
- # {
1430
- # open: 44083.82,
1431
- # high: 44357.77,
1432
- # low: 42911.54,
1433
- # last: 43097.87,
1434
- # vol: 53451.641,
1435
- # riseRate: -2.24
1436
- # }
1437
- #
1438
- timestamp = self.safe_integer(ticker, 'date', self.milliseconds())
1439
- last = self.safe_string(ticker, 'last')
1440
- return self.safe_ticker({
1441
- 'symbol': self.safe_symbol(None, market),
1442
- 'timestamp': timestamp,
1443
- 'datetime': self.iso8601(timestamp),
1444
- 'high': self.safe_string(ticker, 'high'),
1445
- 'low': self.safe_string(ticker, 'low'),
1446
- 'bid': self.safe_string(ticker, 'buy'),
1447
- 'bidVolume': None,
1448
- 'ask': self.safe_string(ticker, 'sell'),
1449
- 'askVolume': None,
1450
- 'vwap': None,
1451
- 'open': self.safe_string(ticker, 'open'),
1452
- 'close': last,
1453
- 'last': last,
1454
- 'previousClose': None,
1455
- 'change': None,
1456
- 'percentage': None,
1457
- 'average': None,
1458
- 'baseVolume': self.safe_string(ticker, 'vol'),
1459
- 'quoteVolume': None,
1460
- 'info': ticker,
1461
- }, market)
1462
-
1463
- def parse_ohlcv(self, ohlcv, market=None):
1464
- if market['swap']:
1465
- ohlcvLength = len(ohlcv)
1466
- if ohlcvLength > 5:
1467
- return [
1468
- self.safe_timestamp(ohlcv, 5),
1469
- self.safe_number(ohlcv, 0),
1470
- self.safe_number(ohlcv, 1),
1471
- self.safe_number(ohlcv, 2),
1472
- self.safe_number(ohlcv, 3),
1473
- self.safe_number(ohlcv, 4),
1474
- ]
1475
- else:
1476
- return [
1477
- self.safe_timestamp(ohlcv, 4),
1478
- self.safe_number(ohlcv, 0),
1479
- self.safe_number(ohlcv, 1),
1480
- self.safe_number(ohlcv, 2),
1481
- self.safe_number(ohlcv, 3),
1482
- None,
1483
- ]
1484
- else:
1485
- return [
1486
- self.safe_integer(ohlcv, 0),
1487
- self.safe_number(ohlcv, 1),
1488
- self.safe_number(ohlcv, 2),
1489
- self.safe_number(ohlcv, 3),
1490
- self.safe_number(ohlcv, 4),
1491
- self.safe_number(ohlcv, 5),
1492
- ]
1493
-
1494
- async def fetch_ohlcv(self, symbol: str, timeframe='1m', since: Optional[int] = None, limit: Optional[int] = None, params={}):
1495
- """
1496
- fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
1497
- :param str symbol: unified symbol of the market to fetch OHLCV data for
1498
- :param str timeframe: the length of time each candle represents
1499
- :param int|None since: timestamp in ms of the earliest candle to fetch
1500
- :param int|None limit: the maximum amount of candles to fetch
1501
- :param dict params: extra parameters specific to the zb api endpoint
1502
- :returns [[int]]: A list of candles ordered, open, high, low, close, volume
1503
- """
1504
- await self.load_markets()
1505
- market = self.market(symbol)
1506
- swap = market['swap']
1507
- spot = market['spot']
1508
- options = self.safe_value(self.options, 'timeframes', {})
1509
- timeframes = self.safe_value(options, market['type'], {})
1510
- timeframeValue = self.safe_string(timeframes, timeframe)
1511
- if timeframeValue is None:
1512
- raise NotSupported(self.id + ' fetchOHLCV() does not support ' + timeframe + ' timeframe for ' + market['type'] + ' markets')
1513
- if limit is None:
1514
- limit = 1000
1515
- request = {
1516
- 'size': limit,
1517
- # 'market': market['id'], # spot only
1518
- # 'symbol': market['id'], # swap only
1519
- # 'type': timeframeValue, # spot only
1520
- # 'period': timeframeValue, # swap only
1521
- # 'since': since, # spot only
1522
- # 'size': limit, # spot and swap
1523
- }
1524
- marketIdField = 'symbol' if swap else 'market'
1525
- request[marketIdField] = market['id']
1526
- periodField = 'period' if swap else 'type'
1527
- request[periodField] = timeframeValue
1528
- price = self.safe_string(params, 'price')
1529
- params = self.omit(params, 'price')
1530
- method = self.get_supported_mapping(market['type'], {
1531
- 'spot': 'spotV1PublicGetKline',
1532
- 'swap': 'contractV1PublicGetKline',
1533
- })
1534
- if swap:
1535
- if price == 'mark':
1536
- method = 'contractV1PublicGetMarkKline'
1537
- elif price == 'index':
1538
- method = 'contractV1PublicGetIndexKline'
1539
- elif spot:
1540
- if since is not None:
1541
- request['since'] = since
1542
- response = await getattr(self, method)(self.extend(request, params))
1543
- #
1544
- # Spot
1545
- #
1546
- # {
1547
- # "symbol": "BTC",
1548
- # "data": [
1549
- # [1645091400000,43183.24,43187.49,43145.92,43182.28,0.9110],
1550
- # [1645091460000,43182.18,43183.15,43182.06,43183.15,1.4393],
1551
- # [1645091520000,43182.11,43240.1,43182.11,43240.1,0.3802]
1552
- # ],
1553
- # "moneyType": "USDT"
1554
- # }
1555
- #
1556
- # Swap
1557
- #
1558
- # {
1559
- # "code": 10000,
1560
- # "desc": "操作成功",
1561
- # "data": [
1562
- # [41433.44,41433.44,41405.88,41408.75,21.368,1646366460],
1563
- # [41409.25,41423.74,41408.8,41423.42,9.828,1646366520],
1564
- # [41423.96,41429.39,41369.98,41370.31,123.104,1646366580]
1565
- # ]
1566
- # }
1567
- #
1568
- # Mark
1569
- #
1570
- # {
1571
- # "code": 10000,
1572
- # "desc": "操作成功",
1573
- # "data": [
1574
- # [41603.39,41603.39,41591.59,41600.81,1646381760],
1575
- # [41600.36,41605.75,41587.69,41601.97,1646381820],
1576
- # [41601.97,41601.97,41562.62,41593.96,1646381880]
1577
- # ]
1578
- # }
1579
- #
1580
- # Index
1581
- #
1582
- # {
1583
- # "code": 10000,
1584
- # "desc": "操作成功",
1585
- # "data": [
1586
- # [41697.53,41722.29,41689.16,41689.16,1646381640],
1587
- # [41690.1,41691.73,41611.61,41611.61,1646381700],
1588
- # [41611.61,41619.49,41594.87,41594.87,1646381760]
1589
- # ]
1590
- # }
1591
- #
1592
- data = self.safe_value(response, 'data', [])
1593
- return self.parse_ohlcvs(data, market, timeframe, since, limit)
1594
-
1595
- def parse_trade(self, trade, market=None):
1596
- #
1597
- # Spot
1598
- #
1599
- # {
1600
- # "date":1624537391,
1601
- # "amount":"0.0142",
1602
- # "price":"33936.42",
1603
- # "trade_type":"ask",
1604
- # "type":"sell",
1605
- # "tid":1718869018
1606
- # }
1607
- #
1608
- # Swap
1609
- #
1610
- # {
1611
- # "amount": "0.002",
1612
- # "createTime": "1645787446034",
1613
- # "feeAmount": "-0.05762699",
1614
- # "feeCurrency": "USDT",
1615
- # "id": "6902932868050395136",
1616
- # "maker": False,
1617
- # "orderId": "6902932868042006528",
1618
- # "price": "38417.99",
1619
- # "relizedPnl": "0.30402",
1620
- # "side": 4,
1621
- # "userId": "6896693805014120448"
1622
- # },
1623
- #
1624
- sideField = 'side' if market['swap'] else 'trade_type'
1625
- side = self.safe_string(trade, sideField)
1626
- takerOrMaker = None
1627
- maker = self.safe_value(trade, 'maker')
1628
- if maker is not None:
1629
- takerOrMaker = 'maker' if maker else 'taker'
1630
- if market['spot']:
1631
- side = 'buy' if (side == 'bid') else 'sell'
1632
- else:
1633
- if side == '3':
1634
- side = 'sell' # close long
1635
- elif side == '4':
1636
- side = 'buy' # close short
1637
- elif side == '1':
1638
- side = 'buy' # open long
1639
- elif side == '2':
1640
- side = 'sell' # open short
1641
- timestamp = None
1642
- if market['swap']:
1643
- timestamp = self.safe_integer(trade, 'createTime')
1644
- else:
1645
- timestamp = self.safe_timestamp(trade, 'date')
1646
- price = self.safe_string(trade, 'price')
1647
- amount = self.safe_string(trade, 'amount')
1648
- fee = None
1649
- feeCostString = self.safe_string(trade, 'feeAmount')
1650
- if feeCostString is not None:
1651
- feeCurrencyId = self.safe_string(trade, 'feeCurrency')
1652
- fee = {
1653
- 'cost': feeCostString,
1654
- 'currency': self.safe_currency_code(feeCurrencyId),
1655
- }
1656
- market = self.safe_market(None, market)
1657
- return self.safe_trade({
1658
- 'info': trade,
1659
- 'id': self.safe_string(trade, 'tid'),
1660
- 'timestamp': timestamp,
1661
- 'datetime': self.iso8601(timestamp),
1662
- 'symbol': market['symbol'],
1663
- 'type': None,
1664
- 'side': side,
1665
- 'order': self.safe_string(trade, 'orderId'),
1666
- 'takerOrMaker': takerOrMaker,
1667
- 'price': price,
1668
- 'amount': amount,
1669
- 'cost': None,
1670
- 'fee': fee,
1671
- }, market)
1672
-
1673
- async def fetch_trades(self, symbol: str, since: Optional[int] = None, limit: Optional[int] = None, params={}):
1674
- """
1675
- get the list of most recent trades for a particular symbol
1676
- :param str symbol: unified symbol of the market to fetch trades for
1677
- :param int|None since: timestamp in ms of the earliest trade to fetch
1678
- :param int|None limit: the maximum amount of trades to fetch
1679
- :param dict params: extra parameters specific to the zb api endpoint
1680
- :returns [dict]: a list of `trade structures <https://docs.ccxt.com/en/latest/manual.html?#public-trades>`
1681
- """
1682
- if symbol is None:
1683
- raise ArgumentsRequired(self.id + ' fetchTrades() requires a symbol argument')
1684
- await self.load_markets()
1685
- market = self.market(symbol)
1686
- swap = market['swap']
1687
- request = {
1688
- # 'market': market['id'], # SPOT
1689
- # 'symbol': market['id'], # SWAP
1690
- # 'side': 1, # SWAP
1691
- # 'dateRange': 0, # SWAP
1692
- # 'startTime': since, # SWAP
1693
- # 'endtime': self.milliseconds(), # SWAP
1694
- # 'pageNum': 1, # SWAP
1695
- # 'pageSize': limit, # SWAP default is 10
1696
- }
1697
- if limit is not None:
1698
- request['pageSize'] = limit
1699
- if since is not None:
1700
- request['startTime'] = since
1701
- marketIdField = 'symbol' if swap else 'market'
1702
- request[marketIdField] = market['id']
1703
- if swap and params['pageNum'] is None:
1704
- request['pageNum'] = 1
1705
- method = self.get_supported_mapping(market['type'], {
1706
- 'spot': 'spotV1PublicGetTrades',
1707
- 'swap': 'contractV2PrivateGetTradeTradeHistory',
1708
- })
1709
- response = await getattr(self, method)(self.extend(request, params))
1710
- #
1711
- # Spot
1712
- #
1713
- # [
1714
- # {"date":1624537391,"amount":"0.0142","price":"33936.42","trade_type":"ask","type":"sell","tid":1718869018},
1715
- # {"date":1624537391,"amount":"0.0010","price":"33936.42","trade_type":"ask","type":"sell","tid":1718869020},
1716
- # {"date":1624537391,"amount":"0.0133","price":"33936.42","trade_type":"ask","type":"sell","tid":1718869021},
1717
- # ]
1718
- #
1719
- # Swap
1720
- #
1721
- # {
1722
- # "code": 10000,
1723
- # "data": {
1724
- # "list": [
1725
- # {
1726
- # "amount": "0.002",
1727
- # "createTime": "1645787446034",
1728
- # "feeAmount": "-0.05762699",
1729
- # "feeCurrency": "USDT",
1730
- # "id": "6902932868050395136",
1731
- # "maker": False,
1732
- # "orderId": "6902932868042006528",
1733
- # "price": "38417.99",
1734
- # "relizedPnl": "0.30402",
1735
- # "side": 4,
1736
- # "userId": "6896693805014120448"
1737
- # },
1738
- # ],
1739
- # "pageNum": 1,
1740
- # "pageSize": 10
1741
- # },
1742
- # "desc": "操作成功"
1743
- # }
1744
- #
1745
- if swap:
1746
- data = self.safe_value(response, 'data')
1747
- response = self.safe_value(data, 'list')
1748
- return self.parse_trades(response, market, since, limit)
1749
-
1750
- async def create_order(self, symbol: str, type, side: OrderSide, amount, price=None, params={}):
1751
- """
1752
- create a trade order
1753
- :param str symbol: unified symbol of the market to create an order in
1754
- :param str type: must be 'limit'
1755
- :param str side: 'buy' or 'sell'
1756
- :param float amount: how much of currency you want to trade in units of base currency
1757
- :param float|None price: the price at which the order is to be fullfilled, in units of the quote currency, ignored in market orders
1758
- :param dict params: extra parameters specific to the zb api endpoint
1759
- :param str params['marginMode']: 'cross' or 'isolated'
1760
- :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1761
- """
1762
- await self.load_markets()
1763
- market = self.market(symbol)
1764
- marginMode, query = self.handle_margin_mode_and_params('createOrder', params)
1765
- swap = market['swap']
1766
- spot = market['spot']
1767
- timeInForce = self.safe_string(params, 'timeInForce')
1768
- reduceOnly = self.safe_value(params, 'reduceOnly')
1769
- triggerPrice = self.safe_value_2(params, 'triggerPrice', 'stopPrice')
1770
- stopLossPrice = self.safe_value(params, 'stopLossPrice')
1771
- takeProfitPrice = self.safe_value(params, 'takeProfitPrice')
1772
- isStopLoss = stopLossPrice is not None
1773
- isTakeProfit = takeProfitPrice is not None
1774
- isTriggerOrder = triggerPrice is not None
1775
- if self.sum(isStopLoss, isTakeProfit, isTriggerOrder):
1776
- raise ExchangeError(self.id + ' createOrder() stopLossPrice and takeProfitPrice cannot both be defined')
1777
- isStopOrder = isStopLoss or isTakeProfit or isTriggerOrder
1778
- if isStopOrder and spot:
1779
- raise ExchangeError(self.id + ' createOrder() it is not possible to make a stop order on spot markets')
1780
- if type == 'market':
1781
- raise InvalidOrder(self.id + ' createOrder() on ' + market['type'] + ' markets does not allow market orders')
1782
- method = self.get_supported_mapping(market['type'], {
1783
- 'spot': 'spotV1PrivateGetOrder',
1784
- 'margin': 'spotV1PrivateGetOrder',
1785
- 'swap': 'contractV2PrivatePostTradeOrder',
1786
- })
1787
- request = {
1788
- 'amount': self.amount_to_precision(symbol, amount),
1789
- # 'symbol': market['id'],
1790
- # 'acctType': 0, # Spot, Margin 0/1/2 [Spot/Isolated/Cross] Optional, Default to: 0 Spot
1791
- # 'customerOrderId': '1f2g', # Spot, Margin
1792
- # 'orderType': 1, # Spot, Margin order type 1/2 [PostOnly/IOC] Optional
1793
- # 'triggerPrice': 30000.0, # Stop trigger price
1794
- # 'algoPrice': 29000.0, # Stop order price
1795
- # 'priceType': 1, # Stop Loss Take Profit, 1: Mark price, 2: Last price
1796
- # 'bizType': 1, # Stop Loss Take Profit, 1: TP, 2: SL
1797
- }
1798
- if spot:
1799
- exchangeSpecificParam = self.safe_integer(params, 'orderType', type) == 1
1800
- postOnly = self.is_post_only(False, exchangeSpecificParam, params)
1801
- request['tradeType'] = 1 if (side == 'buy') else 0
1802
- request['currency'] = market['id']
1803
- if postOnly:
1804
- request['orderType'] = 1
1805
- elif timeInForce == 'IOC':
1806
- request['orderType'] = 2
1807
- if price is not None:
1808
- request['price'] = self.price_to_precision(symbol, price)
1809
- if marginMode is not None:
1810
- if marginMode == 'isolated':
1811
- request['acctType'] = 1
1812
- elif marginMode == 'cross':
1813
- request['acctType'] = 2
1814
- elif swap:
1815
- exchangeSpecificParam = self.safe_integer(params, 'action', type) == 4
1816
- postOnly = self.is_post_only(False, exchangeSpecificParam, params)
1817
- # the default mode on zb is one way mode
1818
- # currently ccxt does not support hedge mode natively
1819
- if isStopLoss or isTakeProfit:
1820
- reduceOnly = True
1821
- if reduceOnly:
1822
- request['side'] = 0
1823
- else:
1824
- request['side'] = 5 if (side == 'buy') else 6
1825
- if isStopOrder:
1826
- method = 'contractV2PrivatePostTradeOrderAlgo'
1827
- if isStopLoss:
1828
- request['orderType'] = 2
1829
- request['bizType'] = 2
1830
- request['triggerPrice'] = self.price_to_precision(symbol, stopLossPrice)
1831
- elif isTakeProfit:
1832
- request['orderType'] = 2
1833
- request['bizType'] = 1
1834
- request['triggerPrice'] = self.price_to_precision(symbol, takeProfitPrice)
1835
- elif isTriggerOrder:
1836
- request['orderType'] = 1
1837
- request['triggerPrice'] = self.price_to_precision(symbol, triggerPrice)
1838
- request['algoPrice'] = self.price_to_precision(symbol, price)
1839
- request['pricetype'] = 2
1840
- else:
1841
- if timeInForce == 'IOC':
1842
- request['action'] = 3
1843
- elif postOnly:
1844
- request['action'] = 4
1845
- elif timeInForce == 'FOK':
1846
- request['action'] = 5
1847
- elif type == 'limit':
1848
- request['action'] = 1
1849
- else:
1850
- request['action'] = type
1851
- if price is not None:
1852
- request['price'] = self.price_to_precision(symbol, price)
1853
- request['symbol'] = market['id']
1854
- clientOrderId = self.safe_string(params, 'clientOrderId') # OPTIONAL '^[a-zA-Z0-9-_]{1,36}$', # The user-defined order number
1855
- if clientOrderId is not None:
1856
- request['clientOrderId'] = clientOrderId
1857
- # using self.extend name causes issues in python
1858
- extendOrderAlgos = self.safe_value(params, 'extend', None) # OPTIONAL {"orderAlgos":[{"bizType":1,"priceType":1,"triggerPrice":"70000"},{"bizType":2,"priceType":1,"triggerPrice":"40000"}]}
1859
- if extendOrderAlgos is not None:
1860
- request['extend'] = extendOrderAlgos
1861
- params = self.omit(query, ['takeProfitPrice', 'stopLossPrice', 'stopPrice', 'reduceOnly', 'orderType', 'triggerPrice', 'priceType', 'clientOrderId', 'extend'])
1862
- response = await getattr(self, method)(self.extend(request, params))
1863
- #
1864
- # Spot and Margin
1865
- #
1866
- # {
1867
- # "code": 1000,
1868
- # "message": "操作成功",
1869
- # "id": "202202224851151555"
1870
- # }
1871
- #
1872
- # Swap
1873
- #
1874
- # {
1875
- # "code": 10000,
1876
- # "desc": "操作成功",
1877
- # "data": {
1878
- # "orderId": "6901786759944937472",
1879
- # "orderCode": null
1880
- # }
1881
- # }
1882
- #
1883
- # Algo order
1884
- #
1885
- # {
1886
- # "code": 10000,
1887
- # "data": "6919884551305242624",
1888
- # "desc": "操作成功"
1889
- # }
1890
- #
1891
- result = response
1892
- if swap and not isStopOrder:
1893
- result = self.safe_value(response, 'data')
1894
- return self.parse_order(result, market)
1895
-
1896
- async def cancel_order(self, id: str, symbol: Optional[str] = None, params={}):
1897
- """
1898
- cancels an open order
1899
- :param str id: order id
1900
- :param str symbol: unified symbol of the market the order was made in
1901
- :param dict params: extra parameters specific to the zb api endpoint
1902
- :returns dict: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1903
- """
1904
- if symbol is None:
1905
- raise ArgumentsRequired(self.id + ' cancelOrder() requires a symbol argument')
1906
- await self.load_markets()
1907
- market = self.market(symbol)
1908
- swap = market['swap']
1909
- request = {
1910
- # 'currency': self.market_id(symbol), # only applicable to SPOT
1911
- # 'id': str(id), # only applicable to SPOT
1912
- # 'symbol': self.market_id(symbol), # only applicable to SWAP
1913
- # 'orderId': str(id), # only applicable to SWAP
1914
- # 'clientOrderId': params['clientOrderId'], # only applicable to SWAP
1915
- }
1916
- marketIdField = 'symbol' if swap else 'currency'
1917
- request[marketIdField] = self.market_id(symbol)
1918
- orderIdField = 'orderId' if swap else 'id'
1919
- request[orderIdField] = str(id)
1920
- method = self.get_supported_mapping(market['type'], {
1921
- 'spot': 'spotV1PrivateGetCancelOrder',
1922
- 'swap': 'contractV2PrivatePostTradeCancelOrder',
1923
- })
1924
- response = await getattr(self, method)(self.extend(request, params))
1925
- #
1926
- # Spot
1927
- #
1928
- # {
1929
- # "code": 1000,
1930
- # "message": "Success。"
1931
- # }
1932
- #
1933
- # Swap
1934
- #
1935
- # {
1936
- # "code": 10007,
1937
- # "desc": "orderId与clientOrderId选填1个"
1938
- # }
1939
- #
1940
- return self.parse_order(response, market)
1941
-
1942
- async def cancel_all_orders(self, symbol: Optional[str] = None, params={}):
1943
- """
1944
- cancel all open orders in a market
1945
- :param str symbol: unified market symbol of the market to cancel orders in
1946
- :param dict params: extra parameters specific to the zb api endpoint
1947
- :returns [dict]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
1948
- """
1949
- if symbol is None:
1950
- raise ArgumentsRequired(self.id + ' cancelAllOrders() requires a symbol argument')
1951
- await self.load_markets()
1952
- market = self.market(symbol)
1953
- stop = self.safe_value(params, 'stop')
1954
- if market['spot']:
1955
- raise NotSupported(self.id + ' cancelAllOrders() is not supported on ' + market['type'] + ' markets')
1956
- request = {
1957
- 'symbol': market['id'],
1958
- # 'ids': [6904603200733782016, 6819506476072247297], # STOP
1959
- # 'side': params['side'], # STOP, for stop orders: 1 Open long(buy), 2 Open short(sell), 3 Close long(sell), 4 Close Short(Buy). One-Way Positions: 5 Buy, 6 Sell, 0 Close Only
1960
- }
1961
- method = 'contractV2PrivatePostTradeCancelAllOrders'
1962
- if stop:
1963
- method = 'contractV2PrivatePostTradeCancelAlgos'
1964
- query = self.omit(params, 'stop')
1965
- return await getattr(self, method)(self.extend(request, query))
1966
-
1967
- async def fetch_order(self, id: str, symbol: Optional[str] = None, params={}):
1968
- """
1969
- fetches information on an order made by the user
1970
- :param str symbol: unified symbol of the market the order was made in
1971
- :param dict params: extra parameters specific to the zb api endpoint
1972
- :returns dict: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1973
- """
1974
- if symbol is None:
1975
- raise ArgumentsRequired(self.id + ' fetchOrder() requires a symbol argument')
1976
- await self.load_markets()
1977
- market = self.market(symbol)
1978
- orderType = self.safe_integer(params, 'orderType')
1979
- if orderType is not None:
1980
- raise ExchangeError(self.id + ' fetchOrder() it is not possible to fetch a single conditional order, use fetchOrders() instead')
1981
- swap = market['swap']
1982
- request = {
1983
- # 'currency': self.market_id(symbol), # only applicable to SPOT
1984
- # 'id': str(id), # only applicable to SPOT
1985
- # 'orderId': str(id), # only applicable to SWAP
1986
- # 'clientOrderId': params['clientOrderId'], # only applicable to SWAP
1987
- # 'symbol': market['id'], # STOP and SWAP
1988
- # 'side': params['side'], # STOP and SWAP, for stop orders: 1 Open long(buy), 2 Open short(sell), 3 Close long(sell), 4 Close Short(Buy). One-Way Positions: 5 Buy, 6 Sell, 0 Close Only
1989
- # 'orderType': 1, # STOP, 1: Plan order, 2: SP/SL
1990
- # 'bizType': 1, # Plan order, 1: TP, 2: SL
1991
- # 'status': 1, # STOP, 1: untriggered, 2: cancelled, 3:triggered, 4:failed, 5:completed
1992
- # 'startTime': since, # STOP and SWAP
1993
- # 'endTime': params['endTime'], # STOP and SWAP
1994
- # 'pageNum': 1, # STOP and SWAP, default 1
1995
- # 'pageSize': limit, # STOP, default 10
1996
- }
1997
- marketIdField = 'symbol' if swap else 'currency'
1998
- request[marketIdField] = self.market_id(symbol)
1999
- orderIdField = 'orderId' if swap else 'id'
2000
- request[orderIdField] = str(id)
2001
- method = self.get_supported_mapping(market['type'], {
2002
- 'spot': 'spotV1PrivateGetGetOrder',
2003
- 'swap': 'contractV2PrivateGetTradeGetOrder',
2004
- })
2005
- response = await getattr(self, method)(self.extend(request, params))
2006
- #
2007
- # Spot
2008
- #
2009
- # {
2010
- # 'total_amount': 0.01,
2011
- # 'id': '20180910244276459',
2012
- # 'price': 180.0,
2013
- # 'trade_date': 1536576744960,
2014
- # 'status': 2,
2015
- # 'trade_money': '1.96742',
2016
- # 'trade_amount': 0.01,
2017
- # 'type': 0,
2018
- # 'currency': 'eth_usdt'
2019
- # }
2020
- #
2021
- # Swap
2022
- #
2023
- # {
2024
- # "code": 10000,
2025
- # "data": {
2026
- # "action": 1,
2027
- # "amount": "0.002",
2028
- # "availableAmount": "0.002",
2029
- # "availableValue": "60",
2030
- # "avgPrice": "0",
2031
- # "canCancel": True,
2032
- # "cancelStatus": 20,
2033
- # "createTime": "1646185684379",
2034
- # "entrustType": 1,
2035
- # "id": "6904603200733782016",
2036
- # "leverage": 2,
2037
- # "margin": "30",
2038
- # "marketId": "100",
2039
- # "modifyTime": "1646185684416",
2040
- # "price": "30000",
2041
- # "priority": 0,
2042
- # "showStatus": 1,
2043
- # "side": 1,
2044
- # "sourceType": 4,
2045
- # "status": 12,
2046
- # "tradeAmount": "0",
2047
- # "tradeValue": "0",
2048
- # "type": 1,
2049
- # "userId": "6896693805014120448",
2050
- # "value": "60"
2051
- # },
2052
- # "desc":"操作成功"
2053
- # }
2054
- #
2055
- # Algo order
2056
- #
2057
- # {
2058
- # "code": 10000,
2059
- # "data": {
2060
- # "list": [
2061
- # {
2062
- # "action": 1,
2063
- # "algoPrice": "30000",
2064
- # "amount": "0.003",
2065
- # "bizType": 0,
2066
- # "canCancel": True,
2067
- # "createTime": "1649913941109",
2068
- # "errorCode": 0,
2069
- # "id": "6920240642849449984",
2070
- # "isLong": False,
2071
- # "leverage": 10,
2072
- # "marketId": "100",
2073
- # "modifyTime": "1649913941109",
2074
- # "orderType": 1,
2075
- # "priceType": 2,
2076
- # "side": 5,
2077
- # "sourceType": 4,
2078
- # "status": 1,
2079
- # "submitPrice": "41270.53",
2080
- # "symbol": "BTC_USDT",
2081
- # "tradedAmount": "0",
2082
- # "triggerCondition": "<=",
2083
- # "triggerPrice": "31000",
2084
- # "triggerTime": "0",
2085
- # "userId": "6896693805014120448"
2086
- # },
2087
- # ],
2088
- # "pageNum": 1,
2089
- # "pageSize": 10
2090
- # },
2091
- # "desc": "操作成功"
2092
- # }
2093
- #
2094
- result = response
2095
- if swap:
2096
- result = self.safe_value(response, 'data')
2097
- return self.parse_order(result, market)
2098
-
2099
- async def fetch_orders(self, symbol: Optional[str] = None, since: Optional[int] = None, limit: Optional[int] = None, params={}):
2100
- """
2101
- fetches information on multiple orders made by the user
2102
- :param str symbol: unified market symbol of the market orders were made in
2103
- :param int|None since: the earliest time in ms to fetch orders for
2104
- :param int|None limit: the maximum number of orde structures to retrieve
2105
- :param dict params: extra parameters specific to the zb api endpoint
2106
- :returns [dict]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
2107
- """
2108
- if symbol is None:
2109
- raise ArgumentsRequired(self.id + ' fetchOrders() requires a symbol argument')
2110
- await self.load_markets()
2111
- market = self.market(symbol)
2112
- orderType = self.safe_integer(params, 'orderType')
2113
- swap = market['swap']
2114
- request = {
2115
- 'pageSize': limit, # default pageSize is 50 for spot, 30 for swap
2116
- # 'currency': market['id'], # only applicable to SPOT
2117
- # 'pageIndex': 1, # only applicable to SPOT
2118
- # 'type': params['type'], # only applicable to SWAP
2119
- # 'dateRange': params['dateRange'], # only applicable to SWAP
2120
- # 'action': params['action'], # only applicable to SWAP
2121
- # 'symbol': market['id'], # STOP and SWAP
2122
- # 'side': params['side'], # STOP and SWAP, for stop orders: 1 Open long(buy), 2 Open short(sell), 3 Close long(sell), 4 Close Short(Buy). One-Way Positions: 5 Buy, 6 Sell, 0 Close Only
2123
- # 'orderType': 1, # STOP, 1: Plan order, 2: SP/SL
2124
- # 'bizType': 1, # Plan order, 1: TP, 2: SL
2125
- # 'status': 1, # STOP, 1: untriggered, 2: cancelled, 3:triggered, 4:failed, 5:completed
2126
- # 'startTime': since, # STOP and SWAP
2127
- # 'endTime': params['endTime'], # STOP and SWAP
2128
- # 'pageNum': 1, # STOP and SWAP, default 1
2129
- # 'pageSize': limit, # STOP, default 10
2130
- }
2131
- marketIdField = 'symbol' if market['swap'] else 'currency'
2132
- request[marketIdField] = market['id']
2133
- pageNumField = 'pageNum' if market['swap'] else 'pageIndex'
2134
- request[pageNumField] = 1
2135
- if swap:
2136
- request['startTime'] = since
2137
- method = self.get_supported_mapping(market['type'], {
2138
- 'spot': 'spotV1PrivateGetGetOrdersIgnoreTradeType',
2139
- 'swap': 'contractV2PrivateGetTradeGetAllOrders',
2140
- })
2141
- # tradeType 交易类型1/0[buy/sell]
2142
- if 'tradeType' in params:
2143
- method = 'spotV1PrivateGetGetOrdersNew'
2144
- if orderType is not None:
2145
- method = 'contractV2PrivateGetTradeGetOrderAlgos'
2146
- response = await getattr(self, method)(self.extend(request, params))
2147
- # Spot
2148
- #
2149
- # [
2150
- # {
2151
- # "acctType": 0,
2152
- # "currency": "btc_usdt",
2153
- # "fees": 0,
2154
- # "id": "202202234857482656",
2155
- # "price": 30000.0,
2156
- # "status": 3,
2157
- # "total_amount": 0.0006,
2158
- # "trade_amount": 0.0000,
2159
- # "trade_date": 1645610254524,
2160
- # "trade_money": 0.000000,
2161
- # "type": 1,
2162
- # "useZbFee": False,
2163
- # "webId": 0
2164
- # }
2165
- # ]
2166
- #
2167
- # Swap
2168
- #
2169
- # {
2170
- # "code": 10000,
2171
- # "data": {
2172
- # "list": [
2173
- # {
2174
- # "action": 1,
2175
- # "amount": "0.004",
2176
- # "availableAmount": "0.004",
2177
- # "availableValue": "120",
2178
- # "avgPrice": "0",
2179
- # "canCancel": True,
2180
- # "cancelStatus": 20,
2181
- # "createTime": "1645609643885",
2182
- # "entrustType": 1,
2183
- # "id": "6902187111785635850",
2184
- # "leverage": 5,
2185
- # "margin": "24",
2186
- # "marketId": "100",
2187
- # "marketName": "BTC_USDT",
2188
- # "modifyTime": "1645609643889",
2189
- # "price": "30000",
2190
- # "showStatus": 1,
2191
- # "side": 1,
2192
- # "sourceType": 1,
2193
- # "status": 12,
2194
- # "tradeAmount": "0",
2195
- # "tradeValue": "0",
2196
- # "type": 1,
2197
- # "userId": "6896693805014120448",
2198
- # "value": "120"
2199
- # },
2200
- # ],
2201
- # "pageNum": 1,
2202
- # "pageSize": 10
2203
- # },
2204
- # "desc": "操作成功"
2205
- # }
2206
- #
2207
- # Algo order
2208
- #
2209
- # {
2210
- # "code": 10000,
2211
- # "data": {
2212
- # "list": [
2213
- # {
2214
- # "action": 1,
2215
- # "algoPrice": "30000",
2216
- # "amount": "0.003",
2217
- # "bizType": 0,
2218
- # "canCancel": True,
2219
- # "createTime": "1649913941109",
2220
- # "errorCode": 0,
2221
- # "id": "6920240642849449984",
2222
- # "isLong": False,
2223
- # "leverage": 10,
2224
- # "marketId": "100",
2225
- # "modifyTime": "1649913941109",
2226
- # "orderType": 1,
2227
- # "priceType": 2,
2228
- # "side": 5,
2229
- # "sourceType": 4,
2230
- # "status": 1,
2231
- # "submitPrice": "41270.53",
2232
- # "symbol": "BTC_USDT",
2233
- # "tradedAmount": "0",
2234
- # "triggerCondition": "<=",
2235
- # "triggerPrice": "31000",
2236
- # "triggerTime": "0",
2237
- # "userId": "6896693805014120448"
2238
- # },
2239
- # ],
2240
- # "pageNum": 1,
2241
- # "pageSize": 10
2242
- # },
2243
- # "desc": "操作成功"
2244
- # }
2245
- #
2246
- result = response
2247
- if swap:
2248
- data = self.safe_value(response, 'data', {})
2249
- result = self.safe_value(data, 'list', [])
2250
- return self.parse_orders(result, market, since, limit)
2251
-
2252
- async def fetch_canceled_orders(self, symbol: Optional[str] = None, since: Optional[int] = None, limit=10, params={}):
2253
- """
2254
- fetches information on multiple canceled orders made by the user
2255
- :param str symbol: unified market symbol of the market orders were made in
2256
- :param int|None since: timestamp in ms of the earliest order, default is None
2257
- :param int|None limit: max number of orders to return, default is None
2258
- :param dict params: extra parameters specific to the zb api endpoint
2259
- :returns dict: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
2260
- """
2261
- if symbol is None:
2262
- raise ArgumentsRequired(self.id + ' fetchCanceledOrders() requires a symbol argument')
2263
- await self.load_markets()
2264
- market = self.market(symbol)
2265
- reduceOnly = self.safe_value(params, 'reduceOnly')
2266
- stop = self.safe_value(params, 'stop')
2267
- request = {
2268
- 'pageSize': limit, # SPOT and STOP, default pageSize is 10, doesn't work with other values now
2269
- # 'currency': market['id'], # SPOT
2270
- # 'pageIndex': 1, # SPOT, default pageIndex is 1
2271
- # 'symbol': market['id'], # STOP
2272
- # 'side': params['side'], # STOP, for stop orders: 1 Open long(buy), 2 Open short(sell), 3 Close long(sell), 4 Close Short(Buy). One-Way Positions: 5 Buy, 6 Sell, 0 Close Only
2273
- # 'orderType': 1, # STOP, 1: Plan order, 2: SP/SL
2274
- # 'bizType': 1, # Plan order, 1: TP, 2: SL
2275
- # 'status': 1, # STOP, 1: untriggered, 2: cancelled, 3:triggered, 4:failed, 5:completed
2276
- # 'startTime': since, # STOP
2277
- # 'endTime': params['endTime'], # STOP
2278
- # 'pageNum': 1, # STOP, default 1
2279
- }
2280
- marketIdField = 'currency' if market['spot'] else 'symbol'
2281
- request[marketIdField] = market['id']
2282
- pageNumField = 'pageIndex' if market['spot'] else 'pageNum'
2283
- request[pageNumField] = 1
2284
- method = 'spotV1PrivateGetGetOrdersIgnoreTradeType'
2285
- if stop:
2286
- method = 'contractV2PrivateGetTradeGetOrderAlgos'
2287
- orderType = self.safe_integer(params, 'orderType')
2288
- if orderType is None:
2289
- raise ArgumentsRequired(self.id + ' fetchCanceledOrders() requires an orderType parameter for stop orders')
2290
- side = self.safe_value(params, 'side')
2291
- bizType = self.safe_integer(params, 'bizType')
2292
- if side == 'sell' and reduceOnly:
2293
- request['side'] = 3 # close long
2294
- elif side == 'buy' and reduceOnly:
2295
- request['side'] = 4 # close short
2296
- elif side == 'buy':
2297
- request['side'] = 1 # open long
2298
- elif side == 'sell':
2299
- request['side'] = 2 # open short
2300
- elif side == 5:
2301
- request['side'] = 5 # one way position buy
2302
- elif side == 6:
2303
- request['side'] = 6 # one way position sell
2304
- elif side == 0:
2305
- request['side'] = 0 # one way position close only
2306
- if orderType == 1:
2307
- request['orderType'] = 1
2308
- elif orderType == 2 or bizType:
2309
- request['orderType'] = 2
2310
- request['bizType'] = bizType
2311
- request['status'] = 2
2312
- # tradeType 交易类型1/0[buy/sell]
2313
- if 'tradeType' in params:
2314
- method = 'spotV1PrivateGetGetOrdersNew'
2315
- response = None
2316
- try:
2317
- response = await getattr(self, method)(self.extend(request, params))
2318
- except Exception as e:
2319
- if isinstance(e, OrderNotFound):
2320
- return []
2321
- raise e
2322
- query = self.omit(params, ['reduceOnly', 'stop', 'side', 'orderType', 'bizType'])
2323
- response = await getattr(self, method)(self.extend(request, query))
2324
- #
2325
- # Spot
2326
- #
2327
- # [
2328
- # {
2329
- # "acctType": 0,
2330
- # "currency": "btc_usdt",
2331
- # "fees": 0,
2332
- # "id": "202202234857482656",
2333
- # "price": 30000.0,
2334
- # "status": 1,
2335
- # "total_amount": 0.0006,
2336
- # "trade_amount": 0.0000,
2337
- # "trade_date": 1645610254524,
2338
- # "trade_money": 0.000000,
2339
- # "type": 1,
2340
- # "useZbFee": False,
2341
- # "webId": 0
2342
- # }
2343
- # ]
2344
- #
2345
- # Algo order
2346
- #
2347
- # {
2348
- # "code": 10000,
2349
- # "data": {
2350
- # "list": [
2351
- # {
2352
- # "action": 1,
2353
- # "algoPrice": "30000",
2354
- # "amount": "0.003",
2355
- # "bizType": 0,
2356
- # "canCancel": True,
2357
- # "createTime": "1649913941109",
2358
- # "errorCode": 0,
2359
- # "id": "6920240642849449984",
2360
- # "isLong": False,
2361
- # "leverage": 10,
2362
- # "marketId": "100",
2363
- # "modifyTime": "1649913941109",
2364
- # "orderType": 1,
2365
- # "priceType": 2,
2366
- # "side": 5,
2367
- # "sourceType": 4,
2368
- # "status": 2,
2369
- # "submitPrice": "41270.53",
2370
- # "symbol": "BTC_USDT",
2371
- # "tradedAmount": "0",
2372
- # "triggerCondition": "<=",
2373
- # "triggerPrice": "31000",
2374
- # "triggerTime": "0",
2375
- # "userId": "6896693805014120448"
2376
- # },
2377
- # ],
2378
- # "pageNum": 1,
2379
- # "pageSize": 10
2380
- # },
2381
- # "desc": "操作成功"
2382
- # }
2383
- #
2384
- if stop:
2385
- data = self.safe_value(response, 'data', {})
2386
- response = self.safe_value(data, 'list', [])
2387
- result = []
2388
- if market['type'] == 'spot':
2389
- for i in range(0, len(response)):
2390
- entry = response[i]
2391
- status = self.safe_string(entry, 'status')
2392
- if status == '1':
2393
- result.append(entry)
2394
- response = result
2395
- return self.parse_orders(response, market, since, limit)
2396
-
2397
- async def fetch_closed_orders(self, symbol: Optional[str] = None, since: Optional[int] = None, limit=10, params={}):
2398
- """
2399
- fetches information on multiple closed orders made by the user
2400
- :param str symbol: unified market symbol of the market orders were made in
2401
- :param int|None since: the earliest time in ms to fetch orders for
2402
- :param int|None limit: the maximum number of orde structures to retrieve
2403
- :param dict params: extra parameters specific to the zb api endpoint
2404
- :returns [dict]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
2405
- """
2406
- if symbol is None:
2407
- raise ArgumentsRequired(self.id + ' fetchClosedOrders() requires a symbol argument')
2408
- await self.load_markets()
2409
- market = self.market(symbol)
2410
- swap = market['swap']
2411
- orderType = self.safe_integer(params, 'orderType')
2412
- request = {
2413
- 'pageSize': limit, # SPOT and STOP, default pageSize is 10, doesn't work with other values now
2414
- # 'currency': market['id'], # SPOT
2415
- # 'pageIndex': 1, # SPOT, default pageIndex is 1
2416
- # 'symbol': market['id'], # STOP
2417
- # 'side': params['side'], # STOP, for stop orders: 1 Open long(buy), 2 Open short(sell), 3 Close long(sell), 4 Close Short(Buy). One-Way Positions: 5 Buy, 6 Sell, 0 Close Only
2418
- # 'orderType': 1, # STOP, 1: Plan order, 2: SP/SL
2419
- # 'bizType': 1, # Plan order, 1: TP, 2: SL
2420
- # 'status': 1, # STOP, 1: untriggered, 2: cancelled, 3:triggered, 4:failed, 5:completed
2421
- # 'startTime': since, # STOP
2422
- # 'endTime': params['endTime'], # STOP
2423
- # 'pageNum': 1, # STOP, default 1
2424
- }
2425
- marketIdField = 'currency' if market['spot'] else 'symbol'
2426
- request[marketIdField] = market['id']
2427
- pageNumField = 'pageIndex' if market['spot'] else 'pageNum'
2428
- request[pageNumField] = 1
2429
- if swap and (since is not None):
2430
- request['startTime'] = since
2431
- method = self.get_supported_mapping(market['type'], {
2432
- 'spot': 'spotV1PrivateGetGetFinishedAndPartialOrders',
2433
- 'swap': 'contractV2PrivateGetTradeGetOrderAlgos',
2434
- })
2435
- if swap and (orderType is None):
2436
- raise ExchangeError(self.id + ' fetchClosedOrders() can not fetch swap orders, use fetchOrders instead')
2437
- if swap:
2438
- # a status of 2 would mean canceled and could also be valid
2439
- request['status'] = 5 # complete
2440
- response = await getattr(self, method)(self.extend(request, params))
2441
- #
2442
- # Spot
2443
- #
2444
- # [
2445
- # {
2446
- # "acctType": 0,
2447
- # "currency": "btc_usdt",
2448
- # "fees": 0.00823354,
2449
- # "id": "202204145086706337",
2450
- # "price": 41167.7,
2451
- # "status": 2,
2452
- # "total_amount": 0.0001,
2453
- # "trade_amount": 0.0001,
2454
- # "trade_date": 1649917867370,
2455
- # "trade_money": 4.116770,
2456
- # "type": 0,
2457
- # "useZbFee": False,
2458
- # "webId": 0
2459
- # },
2460
- # ]
2461
- #
2462
- # Algo order
2463
- #
2464
- # {
2465
- # "code": 10000,
2466
- # "data": {
2467
- # "list": [
2468
- # {
2469
- # "action": 1,
2470
- # "algoPrice": "30000",
2471
- # "amount": "0.003",
2472
- # "bizType": 0,
2473
- # "canCancel": True,
2474
- # "createTime": "1649913941109",
2475
- # "errorCode": 0,
2476
- # "id": "6920240642849449984",
2477
- # "isLong": False,
2478
- # "leverage": 10,
2479
- # "marketId": "100",
2480
- # "modifyTime": "1649913941109",
2481
- # "orderType": 1,
2482
- # "priceType": 2,
2483
- # "side": 5,
2484
- # "sourceType": 4,
2485
- # "status": 1,
2486
- # "submitPrice": "41270.53",
2487
- # "symbol": "BTC_USDT",
2488
- # "tradedAmount": "0",
2489
- # "triggerCondition": "<=",
2490
- # "triggerPrice": "31000",
2491
- # "triggerTime": "0",
2492
- # "userId": "6896693805014120448"
2493
- # },
2494
- # ],
2495
- # "pageNum": 1,
2496
- # "pageSize": 10
2497
- # },
2498
- # "desc": "操作成功"
2499
- # }
2500
- #
2501
- result = response
2502
- if swap:
2503
- data = self.safe_value(response, 'data', {})
2504
- result = self.safe_value(data, 'list', [])
2505
- return self.parse_orders(result, market, since, limit)
2506
-
2507
- async def fetch_open_orders(self, symbol: Optional[str] = None, since: Optional[int] = None, limit: Optional[int] = None, params={}):
2508
- """
2509
- fetch all unfilled currently open orders
2510
- :param str symbol: unified market symbol
2511
- :param int|None since: the earliest time in ms to fetch open orders for
2512
- :param int|None limit: the maximum number of open orders structures to retrieve
2513
- :param dict params: extra parameters specific to the zb api endpoint
2514
- :returns [dict]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
2515
- """
2516
- if symbol is None:
2517
- raise ArgumentsRequired(self.id + ' fetchOpenOrders() requires a symbol argument')
2518
- await self.load_markets()
2519
- market = self.market(symbol)
2520
- orderType = self.safe_integer(params, 'orderType')
2521
- swap = market['swap']
2522
- request = {
2523
- # 'pageSize': limit, # default pageSize is 10 for spot, 30 for swap
2524
- # 'currency': market['id'], # SPOT
2525
- # 'pageIndex': 1, # SPOT
2526
- # 'symbol': market['id'], # SWAP and STOP
2527
- # 'pageNum': 1, # SWAP and STOP, default 1
2528
- # 'type': params['type'], # swap only
2529
- # 'side': params['side'], # SWAP and STOP, for stop orders: 1 Open long(buy), 2 Open short(sell), 3 Close long(sell), 4 Close Short(Buy). One-Way Positions: 5 Buy, 6 Sell, 0 Close Only
2530
- # 'action': params['action'], # SWAP
2531
- # 'orderType': 1, # STOP, 1: Plan order, 2: SP/SL
2532
- # 'bizType': 1, # Plan order, 1: TP, 2: SL
2533
- # 'status': 1, # STOP, 1: untriggered, 2: cancelled, 3:triggered, 4:failed, 5:completed
2534
- # 'startTime': since, # SWAP and STOP
2535
- # 'endTime': params['endTime'], # STOP
2536
- }
2537
- if limit is not None:
2538
- request['pageSize'] = limit # default pageSize is 10 for spot, 30 for swap
2539
- marketIdField = 'symbol' if market['swap'] else 'currency'
2540
- request[marketIdField] = market['id']
2541
- pageNumField = 'pageNum' if market['swap'] else 'pageIndex'
2542
- request[pageNumField] = 1
2543
- if swap and (since is not None):
2544
- request['startTime'] = since
2545
- method = self.get_supported_mapping(market['type'], {
2546
- 'spot': 'spotV1PrivateGetGetUnfinishedOrdersIgnoreTradeType',
2547
- 'swap': 'contractV2PrivateGetTradeGetUndoneOrders',
2548
- })
2549
- if orderType is not None:
2550
- method = 'contractV2PrivateGetTradeGetOrderAlgos'
2551
- # value 3 would mean triggered but still open orders
2552
- request['status'] = 1 # untriggered
2553
- # tradeType 交易类型1/0[buy/sell]
2554
- if 'tradeType' in params:
2555
- method = 'spotV1PrivateGetGetOrdersNew'
2556
- response = await getattr(self, method)(self.extend(request, params))
2557
- #
2558
- # Spot
2559
- #
2560
- # [
2561
- # {
2562
- # "currency": "btc_usdt",
2563
- # "id": "20150928158614292",
2564
- # "price": 1560,
2565
- # "status": 3,
2566
- # "total_amount": 0.1,
2567
- # "trade_amount": 0,
2568
- # "trade_date": 1443410396717,
2569
- # "trade_money": 0,
2570
- # "type": 0,
2571
- # "fees": "0.03",
2572
- # "useZbFee": True
2573
- # },
2574
- # ]
2575
- #
2576
- # Swap
2577
- #
2578
- # {
2579
- # "code": 10000,
2580
- # "data": {
2581
- # "list": [
2582
- # {
2583
- # "action": 1,
2584
- # "amount": "0.003",
2585
- # "availableAmount": "0.003",
2586
- # "availableValue": "90",
2587
- # "avgPrice": "0",
2588
- # "canCancel": True,
2589
- # "cancelStatus": 20,
2590
- # "createTime": "1645694610880",
2591
- # "entrustType": 1,
2592
- # "id": "6902543489192632320",
2593
- # "leverage": 5,
2594
- # "margin": "18",
2595
- # "marketId": "100",
2596
- # "modifyTime": "1645694610883",
2597
- # "price": "30000",
2598
- # "priority": 0,
2599
- # "showStatus": 1,
2600
- # "side": 1,
2601
- # "sourceType": 1,
2602
- # "status": 12,
2603
- # "tradeAmount": "0",
2604
- # "tradeValue": "0",
2605
- # "type": 1,
2606
- # "userId": "6896693805014120448",
2607
- # "value": "90"
2608
- # }
2609
- # ],
2610
- # "pageNum": 1,
2611
- # "pageSize": 30
2612
- # },
2613
- # "desc": "操作成功"
2614
- # }
2615
- #
2616
- # Algo order
2617
- #
2618
- # {
2619
- # "code": 10000,
2620
- # "data": {
2621
- # "list": [
2622
- # {
2623
- # "action": 1,
2624
- # "algoPrice": "30000",
2625
- # "amount": "0.003",
2626
- # "bizType": 0,
2627
- # "canCancel": True,
2628
- # "createTime": "1649913941109",
2629
- # "errorCode": 0,
2630
- # "id": "6920240642849449984",
2631
- # "isLong": False,
2632
- # "leverage": 10,
2633
- # "marketId": "100",
2634
- # "modifyTime": "1649913941109",
2635
- # "orderType": 1,
2636
- # "priceType": 2,
2637
- # "side": 5,
2638
- # "sourceType": 4,
2639
- # "status": 1,
2640
- # "submitPrice": "41270.53",
2641
- # "symbol": "BTC_USDT",
2642
- # "tradedAmount": "0",
2643
- # "triggerCondition": "<=",
2644
- # "triggerPrice": "31000",
2645
- # "triggerTime": "0",
2646
- # "userId": "6896693805014120448"
2647
- # },
2648
- # ],
2649
- # "pageNum": 1,
2650
- # "pageSize": 10
2651
- # },
2652
- # "desc": "操作成功"
2653
- # }
2654
- #
2655
- result = response
2656
- if swap:
2657
- data = self.safe_value(response, 'data', {})
2658
- result = self.safe_value(data, 'list', [])
2659
- return self.parse_orders(result, market, since, limit)
2660
-
2661
- def parse_order(self, order, market=None):
2662
- #
2663
- # Spot fetchOrder, fetchClosedOrders
2664
- #
2665
- # {
2666
- # acctType: 0,
2667
- # currency: 'btc_usdt',
2668
- # fees: 3.6e-7,
2669
- # id: '202102282829772463',
2670
- # price: 45177.5,
2671
- # status: 2,
2672
- # total_amount: 0.0002,
2673
- # trade_amount: 0.0002,
2674
- # trade_date: 1614515104998,
2675
- # trade_money: 8.983712,
2676
- # type: 1,
2677
- # useZbFee: False
2678
- # },
2679
- #
2680
- # Swap fetchOrder
2681
- #
2682
- # {
2683
- # "action": 1,
2684
- # "amount": "0.002",
2685
- # "availableAmount": "0.002",
2686
- # "availableValue": "60",
2687
- # "avgPrice": "0",
2688
- # "canCancel": True,
2689
- # "cancelStatus": 20,
2690
- # "createTime": "1646185684379",
2691
- # "entrustType": 1,
2692
- # "id": "6904603200733782016",
2693
- # "leverage": 2,
2694
- # "margin": "30",
2695
- # "marketId": "100",
2696
- # "modifyTime": "1646185684416",
2697
- # "price": "30000",
2698
- # "priority": 0,
2699
- # "showStatus": 1,
2700
- # "side": 1,
2701
- # "sourceType": 4,
2702
- # "status": 12,
2703
- # "tradeAmount": "0",
2704
- # "tradeValue": "0",
2705
- # "type": 1,
2706
- # "userId": "6896693805014120448",
2707
- # "value": "60"
2708
- # },
2709
- #
2710
- # Algo fetchOrder, fetchOrders, fetchOpenOrders, fetchClosedOrders
2711
- #
2712
- # {
2713
- # "action": 1,
2714
- # "algoPrice": "30000",
2715
- # "amount": "0.003",
2716
- # "bizType": 0,
2717
- # "canCancel": True,
2718
- # "createTime": "1649913941109",
2719
- # "errorCode": 0,
2720
- # "id": "6920240642849449984",
2721
- # "isLong": False,
2722
- # "leverage": 10,
2723
- # "marketId": "100",
2724
- # "modifyTime": "1649913941109",
2725
- # "orderType": 1,
2726
- # "priceType": 2,
2727
- # "side": 5,
2728
- # "sourceType": 4,
2729
- # "status": 1,
2730
- # "submitPrice": "41270.53",
2731
- # "symbol": "BTC_USDT",
2732
- # "tradedAmount": "0",
2733
- # "triggerCondition": "<=",
2734
- # "triggerPrice": "31000",
2735
- # "triggerTime": "0",
2736
- # "userId": "6896693805014120448"
2737
- # },
2738
- #
2739
- # Spot createOrder
2740
- #
2741
- # {
2742
- # code: '1000',
2743
- # message: '操作成功',
2744
- # id: '202202224851151555',
2745
- # type: '1',
2746
- # total_amount: 0.0002,
2747
- # price: 30000
2748
- # }
2749
- #
2750
- # Swap createOrder
2751
- #
2752
- # {
2753
- # orderId: '6901786759944937472',
2754
- # orderCode: null,
2755
- # timeInForce: 'IOC',
2756
- # total_amount: 0.0002,
2757
- # price: 30000
2758
- # }
2759
- #
2760
- # Algo createOrder
2761
- #
2762
- # {
2763
- # "code": 10000,
2764
- # "data": "6919884551305242624",
2765
- # "desc": "操作成功"
2766
- # }
2767
- #
2768
- orderId = self.safe_string_2(order, 'orderId', 'data') if market['swap'] else self.safe_string(order, 'id')
2769
- if orderId is None:
2770
- orderId = self.safe_value(order, 'id')
2771
- rawSide = self.safe_integer_2(order, 'type', 'side')
2772
- side = None
2773
- if rawSide is not None:
2774
- if market['spot']:
2775
- side = 'buy' if (rawSide == 1) else 'sell'
2776
- elif market['swap']:
2777
- if rawSide == 0:
2778
- side = None
2779
- elif (rawSide == 1) or (rawSide == 4) or (rawSide == 5):
2780
- side = 'buy'
2781
- elif (rawSide == 2) or (rawSide == 3) or (rawSide == 6):
2782
- side = 'sell'
2783
- timestamp = self.safe_integer(order, 'trade_date')
2784
- if timestamp is None:
2785
- timestamp = self.safe_integer(order, 'createTime')
2786
- marketId = self.safe_string(order, 'currency')
2787
- market = self.safe_market(marketId, market, '_')
2788
- price = self.safe_string_2(order, 'price', 'algoPrice')
2789
- filled = self.safe_string(order, 'tradeAmount') if market['swap'] else self.safe_string(order, 'trade_amount')
2790
- amount = self.safe_string(order, 'total_amount')
2791
- if amount is None:
2792
- amount = self.safe_string(order, 'amount')
2793
- cost = self.safe_string(order, 'trade_money')
2794
- status = self.parse_order_status(self.safe_string(order, 'status'), market)
2795
- timeInForce = self.safe_string(order, 'timeInForce')
2796
- postOnly = (timeInForce == 'PO')
2797
- feeCost = self.safe_number(order, 'fees')
2798
- fee = None
2799
- if feeCost is not None:
2800
- feeCurrency = None
2801
- zbFees = self.safe_value(order, 'useZbFee')
2802
- if zbFees is True:
2803
- feeCurrency = 'ZB'
2804
- else:
2805
- feeCurrency = market['quote'] if (side == 'sell') else market['base']
2806
- fee = {
2807
- 'cost': feeCost,
2808
- 'currency': feeCurrency,
2809
- }
2810
- return self.safe_order({
2811
- 'info': order,
2812
- 'id': orderId,
2813
- 'clientOrderId': self.safe_string(order, 'userId'),
2814
- 'timestamp': timestamp,
2815
- 'datetime': self.iso8601(timestamp),
2816
- 'lastTradeTimestamp': None,
2817
- 'symbol': market['symbol'],
2818
- 'type': 'limit', # market order is not available on ZB
2819
- 'timeInForce': timeInForce,
2820
- 'postOnly': postOnly,
2821
- 'side': side,
2822
- 'price': price,
2823
- 'stopPrice': self.safe_number(order, 'triggerPrice'),
2824
- 'triggerPrice': self.safe_number(order, 'triggerPrice'),
2825
- 'average': self.safe_string(order, 'avgPrice'),
2826
- 'cost': cost,
2827
- 'amount': amount,
2828
- 'filled': filled,
2829
- 'remaining': None,
2830
- 'status': status,
2831
- 'fee': fee,
2832
- 'trades': None,
2833
- }, market)
2834
-
2835
- def parse_order_status(self, status, market=None):
2836
- statuses = {}
2837
- if market['type'] == 'spot':
2838
- statuses = {
2839
- '0': 'open',
2840
- '1': 'canceled',
2841
- '2': 'closed',
2842
- '3': 'open', # partial
2843
- }
2844
- else:
2845
- statuses = {
2846
- '1': 'open',
2847
- '2': 'canceled',
2848
- '3': 'open', # stop order triggered
2849
- '4': 'rejected',
2850
- '5': 'closed',
2851
- }
2852
- return self.safe_string(statuses, status, status)
2853
-
2854
- def parse_transaction_status(self, status):
2855
- statuses = {
2856
- '0': 'pending', # submitted, pending confirmation
2857
- '1': 'failed',
2858
- '2': 'ok',
2859
- '3': 'canceled',
2860
- '5': 'ok', # confirmed
2861
- }
2862
- return self.safe_string(statuses, status, status)
2863
-
2864
- def parse_transaction(self, transaction, currency=None):
2865
- #
2866
- # withdraw
2867
- #
2868
- # {
2869
- # "code": 1000,
2870
- # "message": "success",
2871
- # "id": "withdrawalId"
2872
- # }
2873
- #
2874
- # fetchWithdrawals
2875
- #
2876
- # {
2877
- # "amount": 0.01,
2878
- # "fees": 0.001,
2879
- # "id": 2016042556231,
2880
- # "manageTime": 1461579340000,
2881
- # "status": 3,
2882
- # "submitTime": 1461579288000,
2883
- # "toAddress": "14fxEPirL9fyfw1i9EF439Pq6gQ5xijUmp",
2884
- # }
2885
- #
2886
- # fetchDeposits
2887
- #
2888
- # {
2889
- # "address": "1FKN1DZqCm8HaTujDioRL2Aezdh7Qj7xxx",
2890
- # "amount": "1.00000000",
2891
- # "confirmTimes": 1,
2892
- # "currency": "BTC",
2893
- # "description": "Successfully Confirm",
2894
- # "hash": "7ce842de187c379abafadd64a5fe66c5c61c8a21fb04edff9532234a1dae6xxx",
2895
- # "id": 558,
2896
- # "itransfer": 1,
2897
- # "status": 2,
2898
- # "submit_time": "2016-12-07 18:51:57",
2899
- # }
2900
- #
2901
- id = self.safe_string(transaction, 'id')
2902
- txid = self.safe_string(transaction, 'hash')
2903
- amount = self.safe_number(transaction, 'amount')
2904
- timestamp = self.parse8601(self.safe_string(transaction, 'submit_time'))
2905
- timestamp = self.safe_integer(transaction, 'submitTime', timestamp)
2906
- address = self.safe_string_2(transaction, 'toAddress', 'address')
2907
- tag = None
2908
- if address is not None:
2909
- parts = address.split('_')
2910
- address = self.safe_string(parts, 0)
2911
- tag = self.safe_string(parts, 1)
2912
- confirmTimes = self.safe_integer(transaction, 'confirmTimes')
2913
- updated = self.safe_integer(transaction, 'manageTime')
2914
- type = None
2915
- currencyId = self.safe_string(transaction, 'currency')
2916
- code = self.safe_currency_code(currencyId, currency)
2917
- if address is not None:
2918
- type = 'withdrawal' if (confirmTimes is None) else 'deposit'
2919
- status = self.parse_transaction_status(self.safe_string(transaction, 'status'))
2920
- fee = None
2921
- feeCost = self.safe_number(transaction, 'fees')
2922
- if feeCost is not None:
2923
- fee = {
2924
- 'cost': feeCost,
2925
- 'currency': code,
2926
- }
2927
- return {
2928
- 'info': transaction,
2929
- 'id': id,
2930
- 'txid': txid,
2931
- 'timestamp': timestamp,
2932
- 'datetime': self.iso8601(timestamp),
2933
- 'network': None,
2934
- 'addressFrom': None,
2935
- 'address': address,
2936
- 'addressTo': address,
2937
- 'tagFrom': None,
2938
- 'tag': tag,
2939
- 'tagTo': tag,
2940
- 'type': type,
2941
- 'amount': amount,
2942
- 'currency': code,
2943
- 'status': status,
2944
- 'updated': updated,
2945
- 'fee': fee,
2946
- }
2947
-
2948
- async def set_leverage(self, leverage, symbol: Optional[str] = None, params={}):
2949
- """
2950
- set the level of leverage for a market
2951
- :param float leverage: the rate of leverage
2952
- :param str symbol: unified market symbol
2953
- :param dict params: extra parameters specific to the zb api endpoint
2954
- :returns dict: response from the exchange
2955
- """
2956
- await self.load_markets()
2957
- if symbol is None:
2958
- raise ArgumentsRequired(self.id + ' setLeverage() requires a symbol argument')
2959
- if (leverage < 1) or (leverage > 125):
2960
- raise BadRequest(self.id + ' setLeverage() leverage should be between 1 and 125')
2961
- market = self.market(symbol)
2962
- accountType = None
2963
- if not market['swap']:
2964
- raise BadSymbol(self.id + ' setLeverage() supports swap contracts only')
2965
- else:
2966
- accountType = 1
2967
- request = {
2968
- 'symbol': market['id'],
2969
- 'leverage': leverage,
2970
- 'futuresAccountType': accountType, # 1: USDT perpetual swaps
2971
- }
2972
- return await self.contractV2PrivatePostSettingSetLeverage(self.extend(request, params))
2973
-
2974
- async def fetch_funding_rate_history(self, symbol: Optional[str] = None, since: Optional[int] = None, limit: Optional[int] = None, params={}):
2975
- """
2976
- fetches historical funding rate prices
2977
- :param str|None symbol: unified symbol of the market to fetch the funding rate history for
2978
- :param int|None since: timestamp in ms of the earliest funding rate to fetch
2979
- :param int|None limit: the maximum amount of `funding rate structures <https://docs.ccxt.com/en/latest/manual.html?#funding-rate-history-structure>` to fetch
2980
- :param dict params: extra parameters specific to the zb api endpoint
2981
- :param int|None params['until']: timestamp in ms of the latest funding rate to fetch
2982
- :returns [dict]: a list of `funding rate structures <https://docs.ccxt.com/en/latest/manual.html?#funding-rate-history-structure>`
2983
- """
2984
- await self.load_markets()
2985
- request = {
2986
- # 'symbol': market['id'],
2987
- # 'startTime': since,
2988
- # 'endTime': endTime, # current time by default
2989
- # 'limit': limit, # default 100, max 1000
2990
- }
2991
- if symbol is not None:
2992
- market = self.market(symbol)
2993
- symbol = market['symbol']
2994
- request['symbol'] = market['id']
2995
- if since is not None:
2996
- request['startTime'] = since
2997
- until = self.safe_integer_2(params, 'until', 'till')
2998
- params = self.omit(params, ['endTime', 'till', 'until'])
2999
- if until is not None:
3000
- request['endTime'] = until
3001
- if limit is not None:
3002
- request['limit'] = limit
3003
- response = await self.contractV2PublicGetFundingRate(self.extend(request, params))
3004
- #
3005
- # {
3006
- # "code": 10000,
3007
- # "data": [
3008
- # {
3009
- # "symbol": "BTC_USDT",
3010
- # "fundingRate": "0.0001",
3011
- # "fundingTime": "1645171200000"
3012
- # },
3013
- # ],
3014
- # "desc": "操作成功"
3015
- # }
3016
- #
3017
- data = self.safe_value(response, 'data', [])
3018
- rates = []
3019
- for i in range(0, len(data)):
3020
- entry = data[i]
3021
- marketId = self.safe_string(entry, 'symbol')
3022
- symbolInner = self.safe_symbol(marketId)
3023
- timestamp = self.safe_integer(entry, 'fundingTime')
3024
- rates.append({
3025
- 'info': entry,
3026
- 'symbol': symbolInner,
3027
- 'fundingRate': self.safe_number(entry, 'fundingRate'),
3028
- 'timestamp': timestamp,
3029
- 'datetime': self.iso8601(timestamp),
3030
- })
3031
- sorted = self.sort_by(rates, 'timestamp')
3032
- return self.filter_by_symbol_since_limit(sorted, symbol, since, limit)
3033
-
3034
- async def fetch_funding_rate(self, symbol: str, params={}):
3035
- """
3036
- fetch the current funding rate
3037
- :param str symbol: unified market symbol
3038
- :param dict params: extra parameters specific to the zb api endpoint
3039
- :returns dict: a `funding rate structure <https://docs.ccxt.com/#/?id=funding-rate-structure>`
3040
- """
3041
- await self.load_markets()
3042
- market = self.market(symbol)
3043
- if not market['swap']:
3044
- raise BadSymbol(self.id + ' fetchFundingRate() does not supports contracts only')
3045
- request = {
3046
- 'symbol': market['id'],
3047
- }
3048
- response = await self.contractV1PublicGetFundingRate(self.extend(request, params))
3049
- #
3050
- # {
3051
- # "code": 10000,
3052
- # "desc": "操作成功",
3053
- # "data": {
3054
- # "fundingRate": "0.0001",
3055
- # "nextCalculateTime": "2022-02-19 00:00:00"
3056
- # }
3057
- # }
3058
- #
3059
- data = self.safe_value(response, 'data')
3060
- return self.parse_funding_rate(data, market)
3061
-
3062
- def parse_funding_rate(self, contract, market=None):
3063
- #
3064
- # fetchFundingRate
3065
- #
3066
- # {
3067
- # "fundingRate": "0.0001",
3068
- # "nextCalculateTime": "2022-02-19 00:00:00"
3069
- # }
3070
- #
3071
- # fetchFundingRates
3072
- #
3073
- # {
3074
- # "symbol": "BTC_USDT",
3075
- # "markPrice": "43254.42",
3076
- # "indexPrice": "43278.61",
3077
- # "lastFundingRate": "0.0001",
3078
- # "nextFundingTime": "1646121600000"
3079
- # }
3080
- #
3081
- marketId = self.safe_string(contract, 'symbol')
3082
- symbol = self.safe_symbol(marketId, market)
3083
- fundingRate = self.safe_number_2(contract, 'fundingRate', 'lastFundingRate')
3084
- nextFundingTimestamp = self.parse8601(self.safe_string(contract, 'nextCalculateTime'))
3085
- fundingTimestamp = self.safe_integer(contract, 'nextFundingTime')
3086
- return {
3087
- 'info': contract,
3088
- 'symbol': symbol,
3089
- 'markPrice': self.safe_string(contract, 'markPrice'),
3090
- 'indexPrice': self.safe_string(contract, 'indexPrice'),
3091
- 'interestRate': None,
3092
- 'estimatedSettlePrice': None,
3093
- 'timestamp': None,
3094
- 'datetime': None,
3095
- 'fundingRate': fundingRate,
3096
- 'fundingTimestamp': fundingTimestamp,
3097
- 'fundingDatetime': self.iso8601(fundingTimestamp),
3098
- 'nextFundingRate': None,
3099
- 'nextFundingTimestamp': nextFundingTimestamp,
3100
- 'nextFundingDatetime': self.iso8601(nextFundingTimestamp),
3101
- 'previousFundingRate': None,
3102
- 'previousFundingTimestamp': None,
3103
- 'previousFundingDatetime': None,
3104
- }
3105
-
3106
- async def fetch_funding_rates(self, symbols: Optional[List[str]] = None, params={}):
3107
- """
3108
- fetch the funding rate for multiple markets
3109
- :param [str]|None symbols: list of unified market symbols
3110
- :param dict params: extra parameters specific to the zb api endpoint
3111
- :returns dict: a dictionary of `funding rates structures <https://docs.ccxt.com/#/?id=funding-rates-structure>`, indexe by market symbols
3112
- """
3113
- await self.load_markets()
3114
- symbols = self.market_symbols(symbols)
3115
- response = await self.contractV2PublicGetPremiumIndex(params)
3116
- #
3117
- # {
3118
- # "code": 10000,
3119
- # "data": [
3120
- # {
3121
- # "symbol": "BTC_USDT",
3122
- # "markPrice": "43254.42",
3123
- # "indexPrice": "43278.61",
3124
- # "lastFundingRate": "0.0001",
3125
- # "nextFundingTime": "1646121600000"
3126
- # },
3127
- # ],
3128
- # "desc":"操作成功"
3129
- # }
3130
- #
3131
- data = self.safe_value(response, 'data', [])
3132
- result = self.parse_funding_rates(data)
3133
- return self.filter_by_array(result, 'symbol', symbols)
3134
-
3135
- async def withdraw(self, code: str, amount, address, tag=None, params={}):
3136
- """
3137
- make a withdrawal
3138
- :param str code: unified currency code
3139
- :param float amount: the amount to withdraw
3140
- :param str address: the address to withdraw to
3141
- :param str|None tag:
3142
- :param dict params: extra parameters specific to the zb api endpoint
3143
- :returns dict: a `transaction structure <https://docs.ccxt.com/#/?id=transaction-structure>`
3144
- """
3145
- tag, params = self.handle_withdraw_tag_and_params(tag, params)
3146
- password = self.safe_string(params, 'safePwd', self.password)
3147
- if password is None:
3148
- raise ArgumentsRequired(self.id + ' withdraw() requires exchange.password or a safePwd parameter')
3149
- fees = self.safe_number(params, 'fees')
3150
- if fees is None:
3151
- raise ArgumentsRequired(self.id + ' withdraw() requires a fees parameter')
3152
- self.check_address(address)
3153
- await self.load_markets()
3154
- currency = self.currency(code)
3155
- if tag is not None:
3156
- address += '_' + tag
3157
- request = {
3158
- 'amount': self.currency_to_precision(code, amount),
3159
- 'currency': currency['id'],
3160
- 'fees': self.currency_to_precision(code, fees),
3161
- # 'itransfer': 0, # agree for an internal transfer, 0 disagree, 1 agree, the default is to disagree
3162
- 'method': 'withdraw',
3163
- 'receiveAddr': address,
3164
- 'safePwd': password,
3165
- }
3166
- response = await self.spotV1PrivateGetWithdraw(self.extend(request, params))
3167
- #
3168
- # {
3169
- # "code": 1000,
3170
- # "message": "success",
3171
- # "id": "withdrawalId"
3172
- # }
3173
- #
3174
- transaction = self.parse_transaction(response, currency)
3175
- return self.extend(transaction, {
3176
- 'type': 'withdrawal',
3177
- 'address': address,
3178
- 'addressTo': address,
3179
- 'amount': amount,
3180
- })
3181
-
3182
- async def fetch_withdrawals(self, code: Optional[str] = None, since: Optional[int] = None, limit: Optional[int] = None, params={}):
3183
- """
3184
- fetch all withdrawals made from an account
3185
- :param str|None code: unified currency code
3186
- :param int|None since: the earliest time in ms to fetch withdrawals for
3187
- :param int|None limit: the maximum number of withdrawals structures to retrieve
3188
- :param dict params: extra parameters specific to the zb api endpoint
3189
- :returns [dict]: a list of `transaction structures <https://docs.ccxt.com/#/?id=transaction-structure>`
3190
- """
3191
- await self.load_markets()
3192
- request = {
3193
- # 'currency': currency['id'],
3194
- # 'pageIndex': 1,
3195
- # 'pageSize': limit,
3196
- }
3197
- currency = None
3198
- if code is not None:
3199
- currency = self.currency(code)
3200
- request['currency'] = currency['id']
3201
- if limit is not None:
3202
- request['pageSize'] = limit
3203
- response = await self.spotV1PrivateGetGetWithdrawRecord(self.extend(request, params))
3204
- #
3205
- # {
3206
- # "code": 1000,
3207
- # "message": {
3208
- # "des": "success",
3209
- # "isSuc": True,
3210
- # "datas": {
3211
- # "list": [
3212
- # {
3213
- # "amount": 0.01,
3214
- # "fees": 0.001,
3215
- # "id": 2016042556231,
3216
- # "manageTime": 1461579340000,
3217
- # "status": 3,
3218
- # "submitTime": 1461579288000,
3219
- # "toAddress": "14fxEPirL9fyfw1i9EF439Pq6gQ5xijUmp",
3220
- # },
3221
- # ],
3222
- # "pageIndex": 1,
3223
- # "pageSize": 10,
3224
- # "totalCount": 4,
3225
- # "totalPage": 1
3226
- # }
3227
- # }
3228
- # }
3229
- #
3230
- message = self.safe_value(response, 'message', {})
3231
- datas = self.safe_value(message, 'datas', {})
3232
- withdrawals = self.safe_value(datas, 'list', [])
3233
- return self.parse_transactions(withdrawals, currency, since, limit)
3234
-
3235
- async def fetch_deposits(self, code: Optional[str] = None, since: Optional[int] = None, limit: Optional[int] = None, params={}):
3236
- """
3237
- fetch all deposits made to an account
3238
- :param str|None code: unified currency code
3239
- :param int|None since: the earliest time in ms to fetch deposits for
3240
- :param int|None limit: the maximum number of deposits structures to retrieve
3241
- :param dict params: extra parameters specific to the zb api endpoint
3242
- :returns [dict]: a list of `transaction structures <https://docs.ccxt.com/#/?id=transaction-structure>`
3243
- """
3244
- await self.load_markets()
3245
- request = {
3246
- # 'currency': currency['id'],
3247
- # 'pageIndex': 1,
3248
- # 'pageSize': limit,
3249
- }
3250
- currency = None
3251
- if code is not None:
3252
- currency = self.currency(code)
3253
- request['currency'] = currency['id']
3254
- if limit is not None:
3255
- request['pageSize'] = limit
3256
- response = await self.spotV1PrivateGetGetChargeRecord(self.extend(request, params))
3257
- #
3258
- # {
3259
- # "code": 1000,
3260
- # "message": {
3261
- # "des": "success",
3262
- # "isSuc": True,
3263
- # "datas": {
3264
- # "list": [
3265
- # {
3266
- # "address": "1FKN1DZqCm8HaTujDioRL2Aezdh7Qj7xxx",
3267
- # "amount": "1.00000000",
3268
- # "confirmTimes": 1,
3269
- # "currency": "BTC",
3270
- # "description": "Successfully Confirm",
3271
- # "hash": "7ce842de187c379abafadd64a5fe66c5c61c8a21fb04edff9532234a1dae6xxx",
3272
- # "id": 558,
3273
- # "itransfer": 1,
3274
- # "status": 2,
3275
- # "submit_time": "2016-12-07 18:51:57",
3276
- # },
3277
- # ],
3278
- # "pageIndex": 1,
3279
- # "pageSize": 10,
3280
- # "total": 8
3281
- # }
3282
- # }
3283
- # }
3284
- #
3285
- message = self.safe_value(response, 'message', {})
3286
- datas = self.safe_value(message, 'datas', {})
3287
- deposits = self.safe_value(datas, 'list', [])
3288
- return self.parse_transactions(deposits, currency, since, limit)
3289
-
3290
- async def fetch_position(self, symbol: str, params={}):
3291
- """
3292
- fetch data on a single open contract trade position
3293
- :param str symbol: unified market symbol of the market the position is held in, default is None
3294
- :param dict params: extra parameters specific to the zb api endpoint
3295
- :returns dict: a `position structure <https://docs.ccxt.com/#/?id=position-structure>`
3296
- """
3297
- await self.load_markets()
3298
- market = None
3299
- if symbol is not None:
3300
- market = self.market(symbol)
3301
- request = {
3302
- 'futuresAccountType': 1, # 1: USDT-M Perpetual Futures
3303
- # 'symbol': market['id'],
3304
- # 'marketId': market['id'],
3305
- # 'side': params['side'],
3306
- }
3307
- response = await self.contractV2PrivateGetPositionsGetPositions(self.extend(request, params))
3308
- #
3309
- # {
3310
- # "code": 10000,
3311
- # "data": [
3312
- # {
3313
- # "amount": "0.002",
3314
- # "appendAmount": "0",
3315
- # "autoLightenRatio": "0",
3316
- # "avgPrice": "38570",
3317
- # "bankruptcyPrice": "46288.41",
3318
- # "contractType": 1,
3319
- # "createTime": "1645784751867",
3320
- # "freezeAmount": "0",
3321
- # "freezeList": [
3322
- # {
3323
- # "amount": "15.436832",
3324
- # "currencyId": "6",
3325
- # "currencyName": "usdt",
3326
- # "modifyTime": "1645784751867"
3327
- # }
3328
- # ],
3329
- # "id": "6902921567894972486",
3330
- # "lastAppendAmount": "0",
3331
- # "leverage": 5,
3332
- # "liquidateLevel": 1,
3333
- # "liquidatePrice": "46104",
3334
- # "maintainMargin": "0.30912384",
3335
- # "margin": "15.436832",
3336
- # "marginAppendCount": 0,
3337
- # "marginBalance": "15.295872",
3338
- # "marginMode": 1,
3339
- # "marginRate": "0.020209",
3340
- # "marketId": "100",
3341
- # "marketName": "BTC_USDT",
3342
- # "modifyTime": "1645784751867",
3343
- # "nominalValue": "77.14736",
3344
- # "originAppendAmount": "0",
3345
- # "originId": "6902921567894972591",
3346
- # "refreshType": "Timer",
3347
- # "returnRate": "-0.0091",
3348
- # "side": 0,
3349
- # "status": 1,
3350
- # "unrealizedPnl": "-0.14096",
3351
- # "userId": "6896693805014120448"
3352
- # }
3353
- # ],
3354
- # "desc": "操作成功"
3355
- # }
3356
- #
3357
- data = self.safe_value(response, 'data', [])
3358
- firstPosition = self.safe_value(data, 0)
3359
- return self.parse_position(firstPosition, market)
3360
-
3361
- async def fetch_positions(self, symbols: Optional[List[str]] = None, params={}):
3362
- """
3363
- fetch all open positions
3364
- :param [str]|None symbols: list of unified market symbols
3365
- :param dict params: extra parameters specific to the zb api endpoint
3366
- :returns [dict]: a list of `position structure <https://docs.ccxt.com/#/?id=position-structure>`
3367
- """
3368
- await self.load_markets()
3369
- request = {
3370
- 'futuresAccountType': 1, # 1: USDT-M Perpetual Futures
3371
- # 'symbol': market['id'],
3372
- # 'marketId': market['id'],
3373
- # 'side': params['side'],
3374
- }
3375
- response = await self.contractV2PrivateGetPositionsGetPositions(self.extend(request, params))
3376
- #
3377
- # {
3378
- # "code": 10000,
3379
- # "data": [
3380
- # {
3381
- # "amount": "0.002",
3382
- # "appendAmount": "0",
3383
- # "autoLightenRatio": "0",
3384
- # "avgPrice": "38570",
3385
- # "bankruptcyPrice": "46288.41",
3386
- # "contractType": 1,
3387
- # "createTime": "1645784751867",
3388
- # "freezeAmount": "0",
3389
- # "freezeList": [
3390
- # {
3391
- # "amount": "15.436832",
3392
- # "currencyId": "6",
3393
- # "currencyName": "usdt",
3394
- # "modifyTime": "1645784751867"
3395
- # }
3396
- # ],
3397
- # "id": "6902921567894972486",
3398
- # "lastAppendAmount": "0",
3399
- # "leverage": 5,
3400
- # "liquidateLevel": 1,
3401
- # "liquidatePrice": "46104",
3402
- # "maintainMargin": "0.30912384",
3403
- # "margin": "15.436832",
3404
- # "marginAppendCount": 0,
3405
- # "marginBalance": "15.295872",
3406
- # "marginMode": 1,
3407
- # "marginRate": "0.020209",
3408
- # "marketId": "100",
3409
- # "marketName": "BTC_USDT",
3410
- # "modifyTime": "1645784751867",
3411
- # "nominalValue": "77.14736",
3412
- # "originAppendAmount": "0",
3413
- # "originId": "6902921567894972591",
3414
- # "refreshType": "Timer",
3415
- # "returnRate": "-0.0091",
3416
- # "side": 0,
3417
- # "status": 1,
3418
- # "unrealizedPnl": "-0.14096",
3419
- # "userId": "6896693805014120448"
3420
- # },
3421
- # ],
3422
- # "desc": "操作成功"
3423
- # }
3424
- #
3425
- data = self.safe_value(response, 'data', [])
3426
- return self.parse_positions(data, symbols)
3427
-
3428
- def parse_position(self, position, market=None):
3429
- #
3430
- # {
3431
- # "amount": "0.002",
3432
- # "appendAmount": "0",
3433
- # "autoLightenRatio": "0",
3434
- # "avgPrice": "38570",
3435
- # "bankruptcyPrice": "46288.41",
3436
- # "contractType": 1,
3437
- # "createTime": "1645784751867",
3438
- # "freezeAmount": "0",
3439
- # "freezeList": [
3440
- # {
3441
- # "amount": "15.436832",
3442
- # "currencyId": "6",
3443
- # "currencyName": "usdt",
3444
- # "modifyTime": "1645784751867"
3445
- # }
3446
- # ],
3447
- # "id": "6902921567894972486",
3448
- # "lastAppendAmount": "0",
3449
- # "leverage": 5,
3450
- # "liquidateLevel": 1,
3451
- # "liquidatePrice": "46104",
3452
- # "maintainMargin": "0.30912384",
3453
- # "margin": "15.436832",
3454
- # "marginAppendCount": 0,
3455
- # "marginBalance": "15.295872",
3456
- # "marginMode": 1,
3457
- # "marginRate": "0.020209",
3458
- # "marketId": "100",
3459
- # "marketName": "BTC_USDT",
3460
- # "modifyTime": "1645784751867",
3461
- # "nominalValue": "77.14736",
3462
- # "originAppendAmount": "0",
3463
- # "originId": "6902921567894972591",
3464
- # "refreshType": "Timer",
3465
- # "returnRate": "-0.0091",
3466
- # "side": 0,
3467
- # "status": 1,
3468
- # "unrealizedPnl": "-0.14096",
3469
- # "userId": "6896693805014120448"
3470
- # }
3471
- #
3472
- marketId = self.safe_string(position, 'marketName')
3473
- market = self.safe_market(marketId, market)
3474
- symbol = market['symbol']
3475
- contracts = self.safe_string(position, 'amount')
3476
- entryPrice = self.safe_number(position, 'avgPrice')
3477
- initialMargin = self.safe_string(position, 'margin')
3478
- rawSide = self.safe_string(position, 'side')
3479
- side = 'long' if (rawSide == '1') else 'short'
3480
- openType = self.safe_string(position, 'marginMode')
3481
- marginMode = 'isolated' if (openType == '1') else 'cross'
3482
- leverage = self.safe_string(position, 'leverage')
3483
- liquidationPrice = self.safe_number(position, 'liquidatePrice')
3484
- unrealizedProfit = self.safe_number(position, 'unrealizedPnl')
3485
- maintenanceMargin = self.safe_number(position, 'maintainMargin')
3486
- marginRatio = self.safe_number(position, 'marginRate')
3487
- notional = self.safe_number(position, 'nominalValue')
3488
- percentage = Precise.string_mul(self.safe_string(position, 'returnRate'), '100')
3489
- timestamp = self.safe_number(position, 'createTime')
3490
- return self.safe_position({
3491
- 'info': position,
3492
- 'id': None,
3493
- 'symbol': symbol,
3494
- 'contracts': self.parse_number(contracts),
3495
- 'contractSize': None,
3496
- 'entryPrice': entryPrice,
3497
- 'collateral': None,
3498
- 'side': side,
3499
- 'unrealizedProfit': unrealizedProfit,
3500
- 'leverage': self.parse_number(leverage),
3501
- 'percentage': percentage,
3502
- 'marginMode': marginMode,
3503
- 'notional': notional,
3504
- 'markPrice': None,
3505
- 'lastPrice': None,
3506
- 'liquidationPrice': liquidationPrice,
3507
- 'initialMargin': self.parse_number(initialMargin),
3508
- 'initialMarginPercentage': None,
3509
- 'maintenanceMargin': maintenanceMargin,
3510
- 'maintenanceMarginPercentage': None,
3511
- 'marginRatio': marginRatio,
3512
- 'timestamp': timestamp,
3513
- 'datetime': self.iso8601(timestamp),
3514
- 'lastUpdateTimestamp': None,
3515
- })
3516
-
3517
- def parse_ledger_entry_type(self, type):
3518
- types = {
3519
- '1': 'realized pnl',
3520
- '2': 'commission',
3521
- '3': 'funding fee subtract',
3522
- '4': 'funding fee addition',
3523
- '5': 'insurance clear',
3524
- '6': 'transfer in',
3525
- '7': 'transfer out',
3526
- '8': 'margin addition',
3527
- '9': 'margin subtraction',
3528
- '10': 'commission addition',
3529
- '11': 'bill type freeze',
3530
- '12': 'bill type unfreeze',
3531
- '13': 'system take over margin',
3532
- '14': 'transfer',
3533
- '15': 'realized pnl collection',
3534
- '16': 'funding fee collection',
3535
- '17': 'recommender return commission',
3536
- '18': 'by level subtract positions',
3537
- '19': 'system add',
3538
- '20': 'system subtract',
3539
- '23': 'trading competition take over fund',
3540
- '24': 'trading contest tickets',
3541
- '25': 'return of trading contest tickets',
3542
- '26': 'experience expired recall',
3543
- '50': 'test register gift',
3544
- '51': 'register gift',
3545
- '52': 'deposit gift',
3546
- '53': 'trading volume gift',
3547
- '54': 'awards gift',
3548
- '55': 'trading volume gift',
3549
- '56': 'awards gift expire',
3550
- '201': 'open positions',
3551
- '202': 'close positions',
3552
- '203': 'take over positions',
3553
- '204': 'trading competition take over positions',
3554
- '205': 'one way open long',
3555
- '206': 'one way open short',
3556
- '207': 'one way close long',
3557
- '208': 'one way close short',
3558
- '301': 'coupon deduction service charge',
3559
- '302': 'experience deduction',
3560
- '303': 'experience expired',
3561
- }
3562
- return self.safe_string(types, type, type)
3563
-
3564
- def parse_ledger_entry(self, item, currency=None):
3565
- #
3566
- # [
3567
- # {
3568
- # "type": 3,
3569
- # "changeAmount": "0.00434664",
3570
- # "isIn": 0,
3571
- # "beforeAmount": "30.53353135",
3572
- # "beforeFreezeAmount": "21.547",
3573
- # "createTime": "1646121604997",
3574
- # "available": "30.52918471",
3575
- # "unit": "usdt",
3576
- # "symbol": "BTC_USDT"
3577
- # },
3578
- # ],
3579
- #
3580
- timestamp = self.safe_integer(item, 'createTime')
3581
- direction = None
3582
- changeDirection = self.safe_number(item, 'isIn')
3583
- if changeDirection == 1:
3584
- direction = 'increase'
3585
- else:
3586
- direction = 'reduce'
3587
- fee = None
3588
- feeCost = self.safe_number(item, 'fee')
3589
- if feeCost is not None:
3590
- fee = {
3591
- 'cost': feeCost,
3592
- 'currency': self.safe_currency_code(self.safe_string(item, 'unit')),
3593
- }
3594
- return {
3595
- 'id': self.safe_string(item, 'id'),
3596
- 'info': item,
3597
- 'timestamp': timestamp,
3598
- 'datetime': self.iso8601(timestamp),
3599
- 'direction': direction,
3600
- 'account': self.safe_string(item, 'userId'),
3601
- 'referenceId': None,
3602
- 'referenceAccount': None,
3603
- 'type': self.parse_ledger_entry_type(self.safe_integer(item, 'type')),
3604
- 'currency': self.safe_currency_code(self.safe_string(item, 'unit')),
3605
- 'amount': self.safe_number(item, 'changeAmount'),
3606
- 'before': self.safe_number(item, 'beforeAmount'),
3607
- 'after': self.safe_number(item, 'available'),
3608
- 'status': None,
3609
- 'fee': fee,
3610
- }
3611
-
3612
- async def fetch_ledger(self, code: Optional[str] = None, since: Optional[int] = None, limit: Optional[int] = None, params={}):
3613
- """
3614
- fetch the history of changes, actions done by the user or operations that altered balance of the user
3615
- :param str code: unified currency code, default is None
3616
- :param int|None since: timestamp in ms of the earliest ledger entry, default is None
3617
- :param int|None limit: max number of ledger entrys to return, default is None
3618
- :param dict params: extra parameters specific to the zb api endpoint
3619
- :returns dict: a `ledger structure <https://docs.ccxt.com/#/?id=ledger-structure>`
3620
- """
3621
- if code is None:
3622
- raise ArgumentsRequired(self.id + ' fetchLedger() requires a code argument')
3623
- await self.load_markets()
3624
- currency = self.currency(code)
3625
- request = {
3626
- 'futuresAccountType': 1,
3627
- # 'currencyId': '11',
3628
- # 'type': 1,
3629
- # 'endTime': self.milliseconds(),
3630
- # 'pageNum': 1,
3631
- }
3632
- if code is not None:
3633
- request['currencyName'] = currency['id']
3634
- if since is not None:
3635
- request['startTime'] = since
3636
- if limit is not None:
3637
- request['pageSize'] = limit
3638
- response = await self.contractV2PrivateGetFundGetBill(self.extend(request, params))
3639
- #
3640
- # {
3641
- # "code": 10000,
3642
- # "data": {
3643
- # "list": [
3644
- # {
3645
- # "type": 3,
3646
- # "changeAmount": "0.00434664",
3647
- # "isIn": 0,
3648
- # "beforeAmount": "30.53353135",
3649
- # "beforeFreezeAmount": "21.547",
3650
- # "createTime": "1646121604997",
3651
- # "available": "30.52918471",
3652
- # "unit": "usdt",
3653
- # "symbol": "BTC_USDT"
3654
- # },
3655
- # ],
3656
- # "pageNum": 1,
3657
- # "pageSize": 10
3658
- # },
3659
- # "desc": "操作成功"
3660
- # }
3661
- #
3662
- data = self.safe_value(response, 'data', {})
3663
- list = self.safe_value(data, 'list', [])
3664
- return self.parse_ledger(list, currency, since, limit)
3665
-
3666
- async def transfer(self, code: str, amount, fromAccount, toAccount, params={}):
3667
- """
3668
- transfer currency internally between wallets on the same account
3669
- :param str code: unified currency code
3670
- :param float amount: amount to transfer
3671
- :param str fromAccount: account to transfer from
3672
- :param str toAccount: account to transfer to
3673
- :param dict params: extra parameters specific to the zb api endpoint
3674
- :param str params['marginMode']: 'cross' or 'isolated'
3675
- :returns dict: a `transfer structure <https://docs.ccxt.com/#/?id=transfer-structure>`
3676
- """
3677
- await self.load_markets()
3678
- marketType, marketTypeQuery = self.handle_market_type_and_params('transfer', None, params)
3679
- marginMode, query = self.handle_margin_mode_and_params('transfer', marketTypeQuery)
3680
- currency = self.currency(code)
3681
- swap = (marketType == 'swap')
3682
- amountToPrecision = self.currency_to_precision(code, amount)
3683
- request = {
3684
- 'amount': amountToPrecision, # Swap, Cross Margin, Isolated Margin
3685
- # 'coin': currency['id'], # Margin
3686
- # 'currencyName': currency['id'], # Swap
3687
- # 'clientId': self.safe_string(params, 'clientId'), # Swap "2sdfsdfsdf232342"
3688
- # 'side': side, # Swap, 1:Deposit(zb account -> futures account),0:Withdrawal(futures account -> zb account)
3689
- # 'marketName': self.safe_string(params, 'marketName'), # Isolated Margin
3690
- }
3691
- method = None
3692
- side = None
3693
- if swap:
3694
- method = 'contractV2PrivatePostFundTransferFund'
3695
- if fromAccount == 'spot' or toAccount == 'future':
3696
- side = 1
3697
- else:
3698
- side = 0
3699
- request['currencyName'] = currency['id']
3700
- request['clientId'] = self.safe_string(params, 'clientId')
3701
- request['side'] = side
3702
- else:
3703
- if (marginMode == 'isolated') or (toAccount == 'isolated') or (fromAccount == 'isolated'):
3704
- if fromAccount == 'spot' or toAccount == 'isolated':
3705
- method = 'spotV1PrivateGetTransferInLever'
3706
- else:
3707
- method = 'spotV1PrivateGetTransferOutLever'
3708
- symbol = self.safe_string_2(params, 'marketName', 'symbol')
3709
- if symbol is None:
3710
- raise ArgumentsRequired(self.id + ' transfer() requires a symbol argument for isolated margin')
3711
- marketInner = self.market(symbol)
3712
- request['marketName'] = self.safe_symbol(marketInner['id'], marketInner, '_')
3713
- elif (marginMode == 'cross') or (toAccount == 'cross') or (fromAccount == 'cross'):
3714
- if fromAccount == 'spot' or toAccount == 'cross':
3715
- method = 'spotV1PrivateGetTransferInCross'
3716
- else:
3717
- method = 'spotV1PrivateGetTransferOutCross'
3718
- request['coin'] = currency['id']
3719
- response = await getattr(self, method)(self.extend(request, query))
3720
- #
3721
- # Swap
3722
- #
3723
- # {
3724
- # "code": 10000,
3725
- # "data": "2sdfsdfsdf232342",
3726
- # "desc": "Success"
3727
- # }
3728
- #
3729
- # Margin
3730
- #
3731
- # {
3732
- # "code": 1000,
3733
- # "message": "Success"
3734
- # }
3735
- #
3736
- return self.extend(self.parse_transfer(response, currency), {
3737
- 'amount': self.parse_number(amountToPrecision),
3738
- 'fromAccount': fromAccount,
3739
- 'toAccount': toAccount,
3740
- })
3741
-
3742
- def parse_transfer(self, transfer, currency=None):
3743
- # response samples in 'transfer'
3744
- timestamp = self.milliseconds()
3745
- return {
3746
- 'id': self.safe_string(transfer, 'data'),
3747
- 'timestamp': timestamp,
3748
- 'datetime': self.iso8601(timestamp),
3749
- 'currency': self.safe_currency_code(None, 'currency'),
3750
- 'amount': None,
3751
- 'fromAccount': None,
3752
- 'toAccount': None,
3753
- 'status': None,
3754
- }
3755
-
3756
- async def modify_margin_helper(self, symbol: str, amount, type, params={}):
3757
- if params['positionsId'] is None:
3758
- raise ArgumentsRequired(self.id + ' modifyMarginHelper() requires a positionsId argument in the params')
3759
- await self.load_markets()
3760
- market = self.market(symbol)
3761
- amount = self.amount_to_precision(symbol, amount)
3762
- position = self.safe_string(params, 'positionsId')
3763
- request = {
3764
- 'positionsId': position,
3765
- 'amount': amount,
3766
- 'type': type, # 1 increase, 0 reduce
3767
- 'futuresAccountType': 1, # 1: USDT Perpetual Futures
3768
- }
3769
- response = await self.contractV2PrivatePostPositionsUpdateMargin(self.extend(request, params))
3770
- #
3771
- # {
3772
- # "code": 10000,
3773
- # "data": {
3774
- # "amount": "0.002",
3775
- # "appendAmount": "0",
3776
- # "avgPrice": "43927.23",
3777
- # "bankruptcyPrice": "41730.86",
3778
- # "createTime": "1646208695609",
3779
- # "freezeAmount": "0",
3780
- # "id": "6900781818669377576",
3781
- # "keyMark": "6896693805014120448-100-1-",
3782
- # "lastAppendAmount": "0",
3783
- # "lastTime": "1646209235505",
3784
- # "leverage": 20,
3785
- # "liquidateLevel": 1,
3786
- # "liquidatePrice": "41898.46",
3787
- # "maintainMargin": "0",
3788
- # "margin": "4.392723",
3789
- # "marginAppendCount": 0,
3790
- # "marginBalance": "0",
3791
- # "marginMode": 1,
3792
- # "marginRate": "0",
3793
- # "marketId": "100",
3794
- # "marketName": "BTC_USDT",
3795
- # "modifyTime": "1646209235505",
3796
- # "nominalValue": "87.88828",
3797
- # "originAppendAmount": "0",
3798
- # "originId": "6904699716827818029",
3799
- # "positionsMode": 2,
3800
- # "sellerCurrencyId": "1",
3801
- # "side": 1,
3802
- # "status": 1,
3803
- # "unrealizedPnl": "0.03382",
3804
- # "usable": True,
3805
- # "userId": "6896693805014120448"
3806
- # },
3807
- # "desc":"操作成功"
3808
- # }
3809
- #
3810
- return self.extend(self.parse_margin_modification(response, market), {
3811
- 'amount': self.parse_number(amount),
3812
- })
3813
-
3814
- def parse_margin_modification(self, data, market=None):
3815
- innerData = self.safe_value(data, 'data', {})
3816
- sideRaw = self.safe_integer(innerData, 'side')
3817
- side = 'add' if (sideRaw == 1) else 'reduce'
3818
- statusCode = self.safe_integer(innerData, 'status')
3819
- status = 'ok' if (statusCode == 1) else 'failed'
3820
- return {
3821
- 'info': data,
3822
- 'type': side,
3823
- 'amount': None,
3824
- 'code': market['quote'],
3825
- 'symbol': market['symbol'],
3826
- 'status': status,
3827
- }
3828
-
3829
- async def add_margin(self, symbol: str, amount, params={}):
3830
- """
3831
- add margin
3832
- :param str symbol: unified market symbol
3833
- :param float amount: amount of margin to add
3834
- :param dict params: extra parameters specific to the zb api endpoint
3835
- :returns dict: a `margin structure <https://docs.ccxt.com/#/?id=add-margin-structure>`
3836
- """
3837
- if params['positionsId'] is None:
3838
- raise ArgumentsRequired(self.id + ' addMargin() requires a positionsId argument in the params')
3839
- return await self.modify_margin_helper(symbol, amount, 1, params)
3840
-
3841
- async def reduce_margin(self, symbol: str, amount, params={}):
3842
- """
3843
- remove margin from a position
3844
- :param str symbol: unified market symbol
3845
- :param float amount: the amount of margin to remove
3846
- :param dict params: extra parameters specific to the zb api endpoint
3847
- :returns dict: a `margin structure <https://docs.ccxt.com/#/?id=reduce-margin-structure>`
3848
- """
3849
- if params['positionsId'] is None:
3850
- raise ArgumentsRequired(self.id + ' reduceMargin() requires a positionsId argument in the params')
3851
- return await self.modify_margin_helper(symbol, amount, 0, params)
3852
-
3853
- async def fetch_borrow_rate(self, code: str, params={}):
3854
- """
3855
- fetch the rate of interest to borrow a currency for margin trading
3856
- :param str code: unified currency code
3857
- :param dict params: extra parameters specific to the zb api endpoint
3858
- :returns dict: a `borrow rate structure <https://docs.ccxt.com/#/?id=borrow-rate-structure>`
3859
- """
3860
- await self.load_markets()
3861
- currency = self.currency(code)
3862
- request = {
3863
- 'coin': currency['id'],
3864
- }
3865
- response = await self.spotV1PrivateGetGetLoans(self.extend(request, params))
3866
- #
3867
- # {
3868
- # code: '1000',
3869
- # message: '操作成功',
3870
- # result: [
3871
- # {
3872
- # interestRateOfDay: '0.0005',
3873
- # repaymentDay: '30',
3874
- # amount: '148804.4841',
3875
- # balance: '148804.4841',
3876
- # rateOfDayShow: '0.05 %',
3877
- # coinName: 'USDT',
3878
- # lowestAmount: '0.01'
3879
- # },
3880
- # ]
3881
- # }
3882
- #
3883
- timestamp = self.milliseconds()
3884
- data = self.safe_value(response, 'result', [])
3885
- rate = self.safe_value(data, 0, {})
3886
- return {
3887
- 'currency': self.safe_currency_code(self.safe_string(rate, 'coinName')),
3888
- 'rate': self.safe_number(rate, 'interestRateOfDay'),
3889
- 'period': self.safe_number(rate, 'repaymentDay'),
3890
- 'timestamp': timestamp,
3891
- 'datetime': self.iso8601(timestamp),
3892
- 'info': rate,
3893
- }
3894
-
3895
- async def fetch_borrow_rates(self, params={}):
3896
- """
3897
- fetch the borrow interest rates of all currencies
3898
- :param dict params: extra parameters specific to the zb api endpoint
3899
- :returns dict: a list of `borrow rate structures <https://docs.ccxt.com/#/?id=borrow-rate-structure>`
3900
- """
3901
- if params['coin'] is None:
3902
- raise ArgumentsRequired(self.id + ' fetchBorrowRates() requires a coin argument in the params')
3903
- await self.load_markets()
3904
- currency = self.currency(self.safe_string(params, 'coin'))
3905
- request = {
3906
- 'coin': currency['id'],
3907
- }
3908
- response = await self.spotV1PrivateGetGetLoans(self.extend(request, params))
3909
- #
3910
- # {
3911
- # code: '1000',
3912
- # message: '操作成功',
3913
- # result: [
3914
- # {
3915
- # interestRateOfDay: '0.0005',
3916
- # repaymentDay: '30',
3917
- # amount: '148804.4841',
3918
- # balance: '148804.4841',
3919
- # rateOfDayShow: '0.05 %',
3920
- # coinName: 'USDT',
3921
- # lowestAmount: '0.01'
3922
- # },
3923
- # ]
3924
- # }
3925
- #
3926
- timestamp = self.milliseconds()
3927
- data = self.safe_value(response, 'result', [])
3928
- rates = []
3929
- for i in range(0, len(data)):
3930
- entry = data[i]
3931
- rates.append({
3932
- 'currency': self.safe_currency_code(self.safe_string(entry, 'coinName')),
3933
- 'rate': self.safe_number(entry, 'interestRateOfDay'),
3934
- 'period': self.safe_number(entry, 'repaymentDay'),
3935
- 'timestamp': timestamp,
3936
- 'datetime': self.iso8601(timestamp),
3937
- 'info': entry,
3938
- })
3939
- return rates
3940
-
3941
- async def set_position_mode(self, hedged, symbol: Optional[str] = None, params={}):
3942
- """
3943
- set the level of leverage for a market
3944
- :param float leverage: the rate of leverage
3945
- :param str symbol: unified market symbol
3946
- :param dict params: extra parameters specific to the zb api endpoint
3947
- :returns dict: response from the exchange
3948
- """
3949
- await self.load_markets()
3950
- if symbol is None:
3951
- raise ArgumentsRequired(self.id + ' setPositionMode() requires a symbol argument')
3952
- market = self.market(symbol)
3953
- accountType = None
3954
- if not market['swap']:
3955
- raise BadSymbol(self.id + ' setPositionMode() supports swap contracts only')
3956
- else:
3957
- accountType = 1
3958
- request = {
3959
- 'marketId': market['id'],
3960
- 'positionMode': 2 if hedged else 1,
3961
- 'futuresAccountType': accountType, # 1: USDT perpetual swaps, 2: QC perpetual futures
3962
- }
3963
- response = await self.contractV2PrivatePostSettingSetPositionsMode(self.extend(request, params))
3964
- #
3965
- # {
3966
- # "code": 10000,
3967
- # "desc": "success",
3968
- # "data": {
3969
- # "userId": 111,
3970
- # "marketId": 100,
3971
- # "leverage": 20,
3972
- # "marginMode": 1,
3973
- # "positionsMode": 2,
3974
- # "enableAutoAppend": 1,
3975
- # "maxAppendAmount": "11212",
3976
- # "marginCoins": "qc,usdt,eth",
3977
- # "id": 6737268451833817088,
3978
- # "createTime": 1606289971312,
3979
- # "modifyTime": 0,
3980
- # "extend": null
3981
- # }
3982
- # }
3983
- #
3984
- return response
3985
-
3986
- async def borrow_margin(self, code: str, amount, symbol: Optional[str] = None, params={}):
3987
- """
3988
- create a loan to borrow margin
3989
- :param str code: unified currency code of the currency to borrow
3990
- :param float amount: the amount to borrow
3991
- :param str|None symbol: unified market symbol, required for isolated margin
3992
- :param dict params: extra parameters specific to the zb api endpoint
3993
- :param str params['safePwd']: transaction password, extra parameter required for cross margin
3994
- :param str params['marginMode']: 'cross' or 'isolated'
3995
- :returns dict: a `margin loan structure <https://docs.ccxt.com/#/?id=margin-loan-structure>`
3996
- """
3997
- await self.load_markets()
3998
- market = None
3999
- if symbol is not None:
4000
- market = self.market(symbol)
4001
- symbol = market['symbol']
4002
- marginMode = None
4003
- marginMode, params = self.handle_margin_mode_and_params('borrowMargin', params)
4004
- if marginMode is None:
4005
- if symbol is not None:
4006
- marginMode = 'isolated' # default to isolated if the symbol is defined
4007
- else:
4008
- marginMode = 'cross' # default to cross
4009
- password = self.safe_string(params, 'safePwd', self.password)
4010
- currency = self.currency(code)
4011
- request = {
4012
- 'coin': currency['id'],
4013
- 'amount': self.currency_to_precision(code, amount),
4014
- 'safePwd': password, # transaction password
4015
- }
4016
- method = None
4017
- if marginMode == 'isolated':
4018
- if symbol is None:
4019
- raise ArgumentsRequired(self.id + ' borrowMargin() requires a symbol argument for isolated margin')
4020
- marketInner = self.market(symbol)
4021
- request['marketName'] = self.safe_symbol(marketInner['id'], marketInner, '_')
4022
- method = 'spotV1PrivateGetBorrow'
4023
- elif marginMode == 'cross':
4024
- method = 'spotV1PrivateGetDoCrossLoan'
4025
- response = await getattr(self, method)(self.extend(request, params))
4026
- #
4027
- # {
4028
- # "code": 1000,
4029
- # "message": "操作成功"
4030
- # }
4031
- #
4032
- transaction = self.parse_margin_loan(response, currency)
4033
- return self.extend(transaction, {
4034
- 'amount': amount,
4035
- 'symbol': symbol,
4036
- })
4037
-
4038
- def parse_margin_loan(self, info, currency=None):
4039
- #
4040
- # {
4041
- # "code": 1000,
4042
- # "message": "操作成功"
4043
- # }
4044
- #
4045
- return {
4046
- 'id': None,
4047
- 'currency': self.safe_currency_code(None, currency),
4048
- 'amount': None,
4049
- 'symbol': None,
4050
- 'timestamp': None,
4051
- 'datetime': None,
4052
- 'info': info,
4053
- }
4054
-
4055
- def nonce(self):
4056
- return self.milliseconds()
4057
-
4058
- def sign(self, path, api='public', method='GET', params={}, headers=None, body=None):
4059
- section = self.safe_string(api, 0)
4060
- version = self.safe_string(api, 1)
4061
- access = self.safe_string(api, 2)
4062
- url = self.implode_hostname(self.urls['api'][section][version][access])
4063
- if access == 'public':
4064
- if path == 'getFeeInfo':
4065
- url = self.implode_hostname(self.urls['api'][section][version]['private']) + '/' + path
4066
- else:
4067
- url += '/' + version + '/' + path
4068
- if params:
4069
- url += '?' + self.urlencode(params)
4070
- elif section == 'contract':
4071
- timestamp = self.milliseconds()
4072
- iso8601 = self.iso8601(timestamp)
4073
- signedString = iso8601 + method + '/Server/api/' + version + '/' + path
4074
- params = self.keysort(params)
4075
- headers = {
4076
- 'ZB-APIKEY': self.apiKey,
4077
- 'ZB-TIMESTAMP': iso8601,
4078
- # 'ZB-LAN': 'cn', # cn, en, kr
4079
- }
4080
- url += '/' + version + '/' + path
4081
- if method == 'POST':
4082
- headers['Content-Type'] = 'application/json'
4083
- body = self.json(params)
4084
- signedString += self.urlencode(params)
4085
- else:
4086
- if params:
4087
- query = self.urlencode(params)
4088
- url += '?' + query
4089
- signedString += query
4090
- secret = self.hash(self.encode(self.secret), 'sha1')
4091
- signature = self.hmac(self.encode(signedString), self.encode(secret), hashlib.sha256, 'base64')
4092
- headers['ZB-SIGN'] = signature
4093
- else:
4094
- query = self.keysort(self.extend({
4095
- 'method': path,
4096
- 'accesskey': self.apiKey,
4097
- }, params))
4098
- nonce = self.nonce()
4099
- query = self.keysort(query)
4100
- auth = self.rawencode(query)
4101
- secret = self.hash(self.encode(self.secret), 'sha1')
4102
- signature = self.hmac(self.encode(auth), self.encode(secret), hashlib.md5)
4103
- suffix = 'sign=' + signature + '&reqTime=' + str(nonce)
4104
- url += '/' + path + '?' + auth + '&' + suffix
4105
- return {'url': url, 'method': method, 'body': body, 'headers': headers}
4106
-
4107
- def handle_errors(self, httpCode, reason, url, method, headers, body, response, requestHeaders, requestBody):
4108
- if response is None:
4109
- return None # fallback to default error handler
4110
- if body[0] == '{':
4111
- feedback = self.id + ' ' + body
4112
- self.throw_broadly_matched_exception(self.exceptions['broad'], body, feedback)
4113
- if 'code' in response:
4114
- code = self.safe_string(response, 'code')
4115
- self.throw_exactly_matched_exception(self.exceptions['exact'], code, feedback)
4116
- if (code != '1000') and (code != '10000'):
4117
- raise ExchangeError(feedback)
4118
- # special case for {"result":false,"message":"服务端忙碌"}(a "Busy Server" reply)
4119
- result = self.safe_value(response, 'result')
4120
- if result is not None:
4121
- if not result:
4122
- message = self.safe_string(response, 'message')
4123
- if message == u'服务端忙碌':
4124
- raise ExchangeNotAvailable(feedback)
4125
- else:
4126
- raise ExchangeError(feedback)
4127
- return None