ccxt 4.1.55__py2.py3-none-any.whl → 4.1.56__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.

Potentially problematic release.


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

@@ -1,2620 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
-
3
- # PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
4
- # https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
5
-
6
- from ccxt.async_support.base.exchange import Exchange
7
- from ccxt.abstract.lbank2 import ImplicitAPI
8
- import asyncio
9
- import hashlib
10
- from ccxt.base.types import Balances, Int, Order, OrderBook, OrderSide, OrderType, String, Ticker, Tickers, Trade, Transaction
11
- from typing import List
12
- from ccxt.base.errors import ExchangeError
13
- from ccxt.base.errors import PermissionDenied
14
- from ccxt.base.errors import BadRequest
15
- from ccxt.base.errors import BadSymbol
16
- from ccxt.base.errors import InsufficientFunds
17
- from ccxt.base.errors import InvalidAddress
18
- from ccxt.base.errors import InvalidOrder
19
- from ccxt.base.errors import DuplicateOrderId
20
- from ccxt.base.errors import RateLimitExceeded
21
- from ccxt.base.errors import InvalidNonce
22
- from ccxt.base.errors import AuthenticationError
23
- from ccxt.base.decimal_to_precision import TICK_SIZE
24
- from ccxt.base.precise import Precise
25
-
26
-
27
- class lbank2(Exchange, ImplicitAPI):
28
-
29
- def describe(self):
30
- return self.deep_extend(super(lbank2, self).describe(), {
31
- 'id': 'lbank2',
32
- 'name': 'LBank',
33
- 'countries': ['CN'],
34
- 'version': 'v2',
35
- # 50 per second for making and cancelling orders 1000ms / 50 = 20
36
- # 20 per second for all other requests, cost = 50 / 20 = 2.5
37
- 'rateLimit': 20,
38
- 'has': {
39
- 'CORS': False,
40
- 'spot': True,
41
- 'margin': False,
42
- 'swap': None,
43
- 'future': False,
44
- 'option': False,
45
- 'addMargin': False,
46
- 'cancelAllOrders': True,
47
- 'cancelOrder': True,
48
- 'createOrder': True,
49
- 'createReduceOnlyOrder': False,
50
- 'createStopLimitOrder': False,
51
- 'createStopMarketOrder': False,
52
- 'createStopOrder': False,
53
- 'fetchBalance': True,
54
- 'fetchBorrowRate': False,
55
- 'fetchBorrowRateHistories': False,
56
- 'fetchBorrowRateHistory': False,
57
- 'fetchBorrowRates': False,
58
- 'fetchBorrowRatesPerSymbol': False,
59
- 'fetchClosedOrders': False,
60
- 'fetchDepositWithdrawFee': 'emulated',
61
- 'fetchDepositWithdrawFees': True,
62
- 'fetchFundingHistory': False,
63
- 'fetchFundingRate': False,
64
- 'fetchFundingRateHistory': False,
65
- 'fetchFundingRates': False,
66
- 'fetchIndexOHLCV': False,
67
- 'fetchIsolatedPositions': False,
68
- 'fetchLeverage': False,
69
- 'fetchLeverageTiers': False,
70
- 'fetchMarginMode': False,
71
- 'fetchMarkets': True,
72
- 'fetchMarkOHLCV': False,
73
- 'fetchMyTrades': True,
74
- 'fetchOHLCV': True,
75
- 'fetchOpenOrders': True,
76
- 'fetchOrder': True,
77
- 'fetchOrderBook': True,
78
- 'fetchOrders': True,
79
- 'fetchPosition': False,
80
- 'fetchPositionMode': False,
81
- 'fetchPositions': False,
82
- 'fetchPositionsRisk': False,
83
- 'fetchPremiumIndexOHLCV': False,
84
- 'fetchTicker': True,
85
- 'fetchTickers': True,
86
- 'fetchTime': True,
87
- 'fetchTrades': True,
88
- 'fetchTradingFees': True,
89
- 'fetchTransactionFees': True,
90
- 'reduceMargin': False,
91
- 'setLeverage': False,
92
- 'setMarginMode': False,
93
- 'setPositionMode': False,
94
- 'withdraw': True,
95
- },
96
- 'timeframes': {
97
- '1m': 'minute1',
98
- '5m': 'minute5',
99
- '15m': 'minute15',
100
- '30m': 'minute30',
101
- '1h': 'hour1',
102
- '2h': 'hour2',
103
- '4h': 'hour4',
104
- '6h': 'hour6',
105
- '8h': 'hour8',
106
- '12h': 'hour12',
107
- '1d': 'day1',
108
- '1w': 'week1',
109
- },
110
- 'urls': {
111
- 'logo': 'https://user-images.githubusercontent.com/1294454/38063602-9605e28a-3302-11e8-81be-64b1e53c4cfb.jpg',
112
- 'api': {
113
- 'rest': 'https://api.lbank.info',
114
- 'contract': 'https://lbkperp.lbank.com',
115
- },
116
- 'api2': 'https://api.lbkex.com',
117
- 'www': 'https://www.lbank.info',
118
- 'doc': 'https://www.lbank.info/en-US/docs/index.html',
119
- 'fees': 'https://lbankinfo.zendesk.com/hc/en-gb/articles/360012072873-Trading-Fees',
120
- 'referral': 'https://www.lbank.info/invitevip?icode=7QCY',
121
- },
122
- 'api': {
123
- 'spot': {
124
- 'public': {
125
- 'get': {
126
- 'currencyPairs': 2.5,
127
- 'accuracy': 2.5,
128
- 'usdToCny': 2.5,
129
- 'withdrawConfigs': 2.5,
130
- 'timestamp': 2.5,
131
- 'ticker/24hr': 2.5,
132
- 'ticker': 2.5,
133
- 'depth': 2.5,
134
- 'incrDepth': 2.5,
135
- 'trades': 2.5,
136
- 'kline': 2.5,
137
- # new quote endpoints
138
- 'supplement/system_ping': 2.5,
139
- 'supplement/incrDepth': 2.5,
140
- 'supplement/trades': 2.5,
141
- 'supplement/ticker/price': 2.5,
142
- 'supplement/ticker/bookTicker': 2.5,
143
- },
144
- 'post': {
145
- 'supplement/system_status': 2.5,
146
- },
147
- },
148
- 'private': {
149
- 'post': {
150
- # account
151
- 'user_info': 2.5,
152
- 'subscribe/get_key': 2.5,
153
- 'subscribe/refresh_key': 2.5,
154
- 'subscribe/destroy_key': 2.5,
155
- 'get_deposit_address': 2.5,
156
- 'deposit_history': 2.5,
157
- # order
158
- 'create_order': 1,
159
- 'batch_create_order': 1,
160
- 'cancel_order': 1,
161
- 'cancel_clientOrders': 1,
162
- 'orders_info': 2.5,
163
- 'orders_info_history': 2.5,
164
- 'order_transaction_detail': 2.5,
165
- 'transaction_history': 2.5,
166
- 'orders_info_no_deal': 2.5,
167
- # withdraw
168
- 'withdraw': 2.5,
169
- 'withdrawCancel': 2.5,
170
- 'withdraws': 2.5,
171
- 'supplement/user_info': 2.5,
172
- 'supplement/withdraw': 2.5,
173
- 'supplement/deposit_history': 2.5,
174
- 'supplement/withdraws': 2.5,
175
- 'supplement/get_deposit_address': 2.5,
176
- 'supplement/asset_detail': 2.5,
177
- 'supplement/customer_trade_fee': 2.5,
178
- 'supplement/api_Restrictions': 2.5,
179
- # new quote endpoints
180
- 'supplement/system_ping': 2.5,
181
- # new order endpoints
182
- 'supplement/create_order_test': 1,
183
- 'supplement/create_order': 1,
184
- 'supplement/cancel_order': 1,
185
- 'supplement/cancel_order_by_symbol': 1,
186
- 'supplement/orders_info': 2.5,
187
- 'supplement/orders_info_no_deal': 2.5,
188
- 'supplement/orders_info_history': 2.5,
189
- 'supplement/user_info_account': 2.5,
190
- 'supplement/transaction_history': 2.5,
191
- },
192
- },
193
- },
194
- 'contract': {
195
- 'public': {
196
- 'get': {
197
- 'cfd/openApi/v1/pub/getTime': 2.5,
198
- 'cfd/openApi/v1/pub/instrument': 2.5,
199
- 'cfd/openApi/v1/pub/marketData': 2.5,
200
- 'cfd/openApi/v1/pub/marketOrder': 2.5,
201
- },
202
- },
203
- },
204
- },
205
- 'fees': {
206
- 'trading': {
207
- 'maker': self.parse_number('0.001'),
208
- 'taker': self.parse_number('0.001'),
209
- },
210
- 'funding': {
211
- 'withdraw': {},
212
- },
213
- },
214
- 'commonCurrencies': {
215
- 'VET_ERC20': 'VEN',
216
- 'PNT': 'Penta',
217
- },
218
- 'precisionMode': TICK_SIZE,
219
- 'options': {
220
- 'cacheSecretAsPem': True,
221
- 'createMarketBuyOrderRequiresPrice': True,
222
- 'fetchTrades': {
223
- 'method': 'spotPublicGetTrades', # or 'spotPublicGetTradesSupplement'
224
- },
225
- 'fetchTransactionFees': { # DEPRECATED, please use fetchDepositWithdrawFees
226
- 'method': 'fetchPrivateTransactionFees', # or 'fetchPublicTransactionFees'
227
- },
228
- 'fetchDepositWithdrawFees': {
229
- 'method': 'fetchPrivateDepositWithdrawFees', # or 'fetchPublicDepositWithdrawFees'
230
- },
231
- 'fetchDepositAddress': {
232
- 'method': 'fetchDepositAddressDefault', # or fetchDepositAddressSupplement
233
- },
234
- 'createOrder': {
235
- 'method': 'spotPrivatePostSupplementCreateOrder', # or spotPrivatePostCreateOrder
236
- },
237
- 'fetchOrder': {
238
- 'method': 'fetchOrderSupplement', # or fetchOrderDefault
239
- },
240
- 'fetchBalance': {
241
- 'method': 'spotPrivatePostSupplementUserInfo', # or spotPrivatePostSupplementUserInfoAccount or spotPrivatePostUserInfo
242
- },
243
- 'networks': {
244
- 'ERC20': 'erc20',
245
- 'ETH': 'erc20',
246
- 'TRC20': 'trc20',
247
- 'TRX': 'trc20',
248
- 'OMNI': 'omni',
249
- 'ASA': 'asa',
250
- 'BEP20': 'bep20(bsc)',
251
- 'BSC': 'bep20(bsc)',
252
- 'HT': 'heco',
253
- 'BNB': 'bep2',
254
- 'BTC': 'btc',
255
- 'DOGE': 'dogecoin',
256
- 'MATIC': 'matic',
257
- 'POLYGON': 'matic',
258
- 'OEC': 'oec',
259
- 'BTCTRON': 'btctron',
260
- 'XRP': 'xrp',
261
- # other unusual chains with number of listed currencies supported
262
- # 'avax c-chain': 1,
263
- # klay: 12,
264
- # bta: 1,
265
- # fantom: 1,
266
- # celo: 1,
267
- # sol: 2,
268
- # zenith: 1,
269
- # ftm: 5,
270
- # bep20: 1,(single token with mis-named chain) SSS
271
- # bitci: 1,
272
- # sgb: 1,
273
- # moonbeam: 1,
274
- # ekta: 1,
275
- # etl: 1,
276
- # arbitrum: 1,
277
- # tpc: 1,
278
- # ptx: 1
279
- # }
280
- },
281
- 'inverse-networks': {
282
- 'erc20': 'ERC20',
283
- 'trc20': 'TRC20',
284
- 'omni': 'OMNI',
285
- 'asa': 'ASA',
286
- 'bep20(bsc)': 'BSC',
287
- 'bep20': 'BSC',
288
- 'heco': 'HT',
289
- 'bep2': 'BNB',
290
- 'btc': 'BTC',
291
- 'dogecoin': 'DOGE',
292
- 'matic': 'MATIC',
293
- 'oec': 'OEC',
294
- 'btctron': 'BTCTRON',
295
- 'xrp': 'XRP',
296
- },
297
- 'defaultNetworks': {
298
- 'USDT': 'TRC20',
299
- },
300
- },
301
- })
302
-
303
- async def fetch_time(self, params={}):
304
- """
305
- fetches the current integer timestamp in milliseconds from the exchange server
306
- :see: https://www.lbank.info/en-US/docs/index.html#get-timestamp
307
- :see: https://www.lbank.com/en-US/docs/contract.html#get-the-current-time
308
- :param dict [params]: extra parameters specific to the lbank2 api endpoint
309
- :returns int: the current integer timestamp in milliseconds from the exchange server
310
- """
311
- type = None
312
- type, params = self.handle_market_type_and_params('fetchTime', None, params)
313
- response = None
314
- if type == 'swap':
315
- response = await self.contractPublicGetCfdOpenApiV1PubGetTime(params)
316
- else:
317
- response = await self.spotPublicGetTimestamp(params)
318
- #
319
- # spot
320
- #
321
- # {
322
- # "result": "true",
323
- # "data": 1691789627950,
324
- # "error_code": 0,
325
- # "ts": 1691789627950
326
- # }
327
- #
328
- # swap
329
- #
330
- # {
331
- # "data": 1691789627950,
332
- # "error_code": 0,
333
- # "msg": "Success",
334
- # "result": "true",
335
- # "success": True
336
- # }
337
- #
338
- return self.safe_integer(response, 'data')
339
-
340
- async def fetch_markets(self, params={}):
341
- """
342
- retrieves data on all markets for lbank2
343
- :see: https://www.lbank.com/en-US/docs/index.html#trading-pairs
344
- :see: https://www.lbank.com/en-US/docs/contract.html#query-contract-information-list
345
- :param dict [params]: extra parameters specific to the exchange api endpoint
346
- :returns dict[]: an array of objects representing market data
347
- """
348
- marketsPromises = [
349
- self.fetch_spot_markets(params),
350
- self.fetch_swap_markets(params),
351
- ]
352
- resolvedMarkets = await asyncio.gather(*marketsPromises)
353
- return self.array_concat(resolvedMarkets[0], resolvedMarkets[1])
354
-
355
- async def fetch_spot_markets(self, params={}):
356
- response = await self.spotPublicGetAccuracy(params)
357
- #
358
- # {
359
- # "result": "true",
360
- # "data": [
361
- # {
362
- # "symbol": "btc_usdt",
363
- # "quantityAccuracy": "4",
364
- # "minTranQua": "0.0001",
365
- # "priceAccuracy": "2"
366
- # },
367
- # ],
368
- # "error_code": 0,
369
- # "ts": 1691560288484
370
- # }
371
- #
372
- data = self.safe_value(response, 'data', [])
373
- result = []
374
- for i in range(0, len(data)):
375
- market = data[i]
376
- marketId = self.safe_string(market, 'symbol')
377
- parts = marketId.split('_')
378
- baseId = parts[0]
379
- quoteId = parts[1]
380
- base = self.safe_currency_code(baseId)
381
- quote = self.safe_currency_code(quoteId)
382
- symbol = base + '/' + quote
383
- result.append({
384
- 'id': marketId,
385
- 'symbol': symbol,
386
- 'base': base,
387
- 'quote': quote,
388
- 'settle': None,
389
- 'baseId': baseId,
390
- 'quoteId': quoteId,
391
- 'settleId': None,
392
- 'type': 'spot',
393
- 'spot': True,
394
- 'margin': False,
395
- 'swap': False,
396
- 'future': False,
397
- 'option': False,
398
- 'active': True,
399
- 'contract': None,
400
- 'linear': None,
401
- 'inverse': None,
402
- 'contractSize': None,
403
- 'expiry': None,
404
- 'expiryDatetime': None,
405
- 'strike': None,
406
- 'optionType': None,
407
- 'precision': {
408
- 'amount': self.parse_number(self.parse_precision(self.safe_string(market, 'quantityAccuracy'))),
409
- 'price': self.parse_number(self.parse_precision(self.safe_string(market, 'priceAccuracy'))),
410
- },
411
- 'limits': {
412
- 'leverage': {
413
- 'min': None,
414
- 'max': None,
415
- },
416
- 'amount': {
417
- 'min': self.safe_number(market, 'minTranQua'),
418
- 'max': None,
419
- },
420
- 'price': {
421
- 'min': None,
422
- 'max': None,
423
- },
424
- 'cost': {
425
- 'min': None,
426
- 'max': None,
427
- },
428
- },
429
- 'created': None,
430
- 'info': market,
431
- })
432
- return result
433
-
434
- async def fetch_swap_markets(self, params={}):
435
- request = {
436
- 'productGroup': 'SwapU',
437
- }
438
- response = await self.contractPublicGetCfdOpenApiV1PubInstrument(self.extend(request, params))
439
- #
440
- # {
441
- # "data": [
442
- # {
443
- # "priceLimitUpperValue": 0.2,
444
- # "symbol": "BTCUSDT",
445
- # "volumeTick": 0.0001,
446
- # "indexPrice": "29707.70200000",
447
- # "minOrderVolume": "0.0001",
448
- # "priceTick": 0.1,
449
- # "maxOrderVolume": "30.0",
450
- # "baseCurrency": "BTC",
451
- # "volumeMultiple": 1.0,
452
- # "exchangeID": "Exchange",
453
- # "priceCurrency": "USDT",
454
- # "priceLimitLowerValue": 0.2,
455
- # "clearCurrency": "USDT",
456
- # "symbolName": "BTCUSDT",
457
- # "defaultLeverage": 20.0,
458
- # "minOrderCost": "5.0"
459
- # },
460
- # ],
461
- # "error_code": 0,
462
- # "msg": "Success",
463
- # "result": "true",
464
- # "success": True
465
- # }
466
- #
467
- data = self.safe_value(response, 'data', [])
468
- result = []
469
- for i in range(0, len(data)):
470
- market = data[i]
471
- marketId = self.safe_string(market, 'symbol')
472
- baseId = self.safe_string(market, 'baseCurrency')
473
- settleId = self.safe_string(market, 'clearCurrency')
474
- quoteId = settleId
475
- base = self.safe_currency_code(baseId)
476
- quote = self.safe_currency_code(quoteId)
477
- settle = self.safe_currency_code(settleId)
478
- symbol = base + '/' + quote + ':' + settle
479
- result.append({
480
- 'id': marketId,
481
- 'symbol': symbol,
482
- 'base': base,
483
- 'quote': quote,
484
- 'settle': settle,
485
- 'baseId': baseId,
486
- 'quoteId': quoteId,
487
- 'settleId': settleId,
488
- 'type': 'swap',
489
- 'spot': False,
490
- 'margin': False,
491
- 'swap': True,
492
- 'future': False,
493
- 'option': False,
494
- 'active': True,
495
- 'contract': True,
496
- 'linear': True,
497
- 'inverse': None,
498
- 'contractSize': self.safe_number(market, 'volumeMultiple'),
499
- 'expiry': None,
500
- 'expiryDatetime': None,
501
- 'strike': None,
502
- 'optionType': None,
503
- 'precision': {
504
- 'amount': self.safe_number(market, 'volumeTick'),
505
- 'price': self.safe_number(market, 'priceTick'),
506
- },
507
- 'limits': {
508
- 'leverage': {
509
- 'min': None,
510
- 'max': None,
511
- },
512
- 'amount': {
513
- 'min': self.safe_number(market, 'minOrderVolume'),
514
- 'max': self.safe_number(market, 'maxOrderVolume'),
515
- },
516
- 'price': {
517
- 'min': self.safe_number(market, 'priceLimitLowerValue'),
518
- 'max': self.safe_number(market, 'priceLimitUpperValue'),
519
- },
520
- 'cost': {
521
- 'min': self.safe_number(market, 'minOrderCost'),
522
- 'max': None,
523
- },
524
- },
525
- 'created': None,
526
- 'info': market,
527
- })
528
- return result
529
-
530
- def parse_ticker(self, ticker, market=None) -> Ticker:
531
- #
532
- # spot: fetchTicker, fetchTickers
533
- #
534
- # {
535
- # "symbol": "btc_usdt",
536
- # "ticker": {
537
- # "high": "29695.57",
538
- # "vol": "6890.2789",
539
- # "low": "29110",
540
- # "change": "0.58",
541
- # "turnover": "202769821.06",
542
- # "latest": "29405.98"
543
- # },
544
- # "timestamp": :1692064274908
545
- # }
546
- #
547
- # swap: fetchTickers
548
- #
549
- # {
550
- # "prePositionFeeRate": "0.000053",
551
- # "volume": "2435.459",
552
- # "symbol": "BTCUSDT",
553
- # "highestPrice": "29446.5",
554
- # "lowestPrice": "29362.9",
555
- # "openPrice": "29419.5",
556
- # "markedPrice": "29385.1",
557
- # "turnover": "36345526.2438402",
558
- # "lastPrice": "29387.0"
559
- # }
560
- #
561
- timestamp = self.safe_integer(ticker, 'timestamp')
562
- marketId = self.safe_string(ticker, 'symbol')
563
- symbol = self.safe_symbol(marketId, market)
564
- tickerData = self.safe_value(ticker, 'ticker', {})
565
- market = self.safe_market(marketId, market)
566
- data = ticker if (market['contract']) else tickerData
567
- return self.safe_ticker({
568
- 'symbol': symbol,
569
- 'timestamp': timestamp,
570
- 'datetime': self.iso8601(timestamp),
571
- 'high': self.safe_string_2(data, 'high', 'highestPrice'),
572
- 'low': self.safe_string_2(data, 'low', 'lowestPrice'),
573
- 'bid': None,
574
- 'bidVolume': None,
575
- 'ask': None,
576
- 'askVolume': None,
577
- 'vwap': None,
578
- 'open': self.safe_string(data, 'openPrice'),
579
- 'close': None,
580
- 'last': self.safe_string_2(data, 'latest', 'lastPrice'),
581
- 'previousClose': None,
582
- 'change': None,
583
- 'percentage': self.safe_string(data, 'change'),
584
- 'average': None,
585
- 'baseVolume': self.safe_string_2(data, 'vol', 'volume'),
586
- 'quoteVolume': self.safe_string(data, 'turnover'),
587
- 'info': ticker,
588
- }, market)
589
-
590
- async def fetch_ticker(self, symbol: str, params={}) -> Ticker:
591
- """
592
- fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
593
- :see: https://www.lbank.info/en-US/docs/index.html#query-current-market-data-new
594
- :param str symbol: unified symbol of the market to fetch the ticker for
595
- :param dict [params]: extra parameters specific to the lbank2 api endpoint
596
- :returns dict: a `ticker structure <https://github.com/ccxt/ccxt/wiki/Manual#ticker-structure>`
597
- """
598
- await self.load_markets()
599
- market = self.market(symbol)
600
- if market['swap']:
601
- responseForSwap = await self.fetch_tickers([market['symbol']], params)
602
- return self.safe_value(responseForSwap, market['symbol'])
603
- request = {
604
- 'symbol': market['id'],
605
- }
606
- response = await self.spotPublicGetTicker24hr(self.extend(request, params))
607
- #
608
- # {
609
- # "result": "true",
610
- # "data": [
611
- # {
612
- # "symbol": "btc_usdt",
613
- # "ticker": {
614
- # "high": "29695.57",
615
- # "vol": "6890.2789",
616
- # "low": "29110",
617
- # "change": "0.58",
618
- # "turnover": "202769821.06",
619
- # "latest": "29405.98"
620
- # },
621
- # "timestamp": :1692064274908
622
- # }
623
- # ],
624
- # "error_code": 0,
625
- # "ts": :1692064276872
626
- # }
627
- #
628
- data = self.safe_value(response, 'data', [])
629
- first = self.safe_value(data, 0, {})
630
- return self.parse_ticker(first, market)
631
-
632
- async def fetch_tickers(self, symbols: List[str] = None, params={}) -> Tickers:
633
- """
634
- fetches price tickers for multiple markets, statistical calculations with the information calculated over the past 24 hours each market
635
- :see: https://www.lbank.info/en-US/docs/index.html#query-current-market-data-new
636
- :see: https://www.lbank.com/en-US/docs/contract.html#query-contract-market-list
637
- :param str[]|None symbols: unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
638
- :param dict [params]: extra parameters specific to the lbank api endpoint
639
- :returns dict: a dictionary of `ticker structures <https://github.com/ccxt/ccxt/wiki/Manual#ticker-structure>`
640
- """
641
- await self.load_markets()
642
- market = None
643
- if symbols is not None:
644
- symbols = self.market_symbols(symbols)
645
- symbolsLength = len(symbols)
646
- if symbolsLength > 0:
647
- market = self.market(symbols[0])
648
- request = {}
649
- type = None
650
- type, params = self.handle_market_type_and_params('fetchTickers', market, params)
651
- response = None
652
- if type == 'swap':
653
- request['productGroup'] = 'SwapU'
654
- response = await self.contractPublicGetCfdOpenApiV1PubMarketData(self.extend(request, params))
655
- else:
656
- request['symbol'] = 'all'
657
- response = await self.spotPublicGetTicker24hr(self.extend(request, params))
658
- #
659
- # spot
660
- #
661
- # {
662
- # "result": "true",
663
- # "data": [
664
- # {
665
- # "symbol": "btc_usdt",
666
- # "ticker": {
667
- # "high": "29695.57",
668
- # "vol": "6890.2789",
669
- # "low": "29110",
670
- # "change": "0.58",
671
- # "turnover": "202769821.06",
672
- # "latest": "29405.98"
673
- # },
674
- # "timestamp": :1692064274908
675
- # }
676
- # ],
677
- # "error_code": 0,
678
- # "ts": :1692064276872
679
- # }
680
- #
681
- # swap
682
- #
683
- # {
684
- # "data": [
685
- # {
686
- # "prePositionFeeRate": "0.000053",
687
- # "volume": "2435.459",
688
- # "symbol": "BTCUSDT",
689
- # "highestPrice": "29446.5",
690
- # "lowestPrice": "29362.9",
691
- # "openPrice": "29419.5",
692
- # "markedPrice": "29385.1",
693
- # "turnover": "36345526.2438402",
694
- # "lastPrice": "29387.0"
695
- # },
696
- # ],
697
- # "error_code": 0,
698
- # "msg": "Success",
699
- # "result": "true",
700
- # "success": True
701
- # }
702
- #
703
- data = self.safe_value(response, 'data', [])
704
- return self.parse_tickers(data, symbols)
705
-
706
- async def fetch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook:
707
- """
708
- fetches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
709
- :see: https://www.lbank.info/en-US/docs/index.html#query-market-depth
710
- :see: https://www.lbank.com/en-US/docs/contract.html#get-handicap
711
- :param str symbol: unified symbol of the market to fetch the order book for
712
- :param int [limit]: the maximum amount of order book entries to return
713
- :param dict [params]: extra parameters specific to the lbank2 api endpoint
714
- :returns dict: A dictionary of `order book structures <https://github.com/ccxt/ccxt/wiki/Manual#order-book-structure>` indexed by market symbols
715
- """
716
- await self.load_markets()
717
- market = self.market(symbol)
718
- if limit is None:
719
- limit = 60
720
- request = {
721
- 'symbol': market['id'],
722
- }
723
- type = None
724
- type, params = self.handle_market_type_and_params('fetchOrderBook', market, params)
725
- response = None
726
- if type == 'swap':
727
- request['depth'] = limit
728
- response = await self.contractPublicGetCfdOpenApiV1PubMarketOrder(self.extend(request, params))
729
- else:
730
- request['size'] = limit
731
- response = await self.spotPublicGetDepth(self.extend(request, params))
732
- #
733
- # spot
734
- #
735
- # {
736
- # "result": "true",
737
- # "data": {
738
- # "asks": [
739
- # ["29243.37", "2.8783"],
740
- # ["29243.39", "2.2842"],
741
- # ["29243.4", "0.0337"]
742
- # ],
743
- # "bids": [
744
- # ["29243.36", "1.5258"],
745
- # ["29243.34", "0.8218"],
746
- # ["29243.28", "1.285"]
747
- # ],
748
- # "timestamp": :1692157328820
749
- # },
750
- # "error_code": 0,
751
- # "ts": :1692157328820
752
- # }
753
- #
754
- # swap
755
- #
756
- # {
757
- # "data": {
758
- # "symbol": "BTCUSDT",
759
- # "asks": [
760
- # {
761
- # "volume": "14.6535",
762
- # "price": "29234.2",
763
- # "orders": "1"
764
- # },
765
- # ],
766
- # "bids": [
767
- # {
768
- # "volume": "13.4899",
769
- # "price": "29234.1",
770
- # "orders": "4"
771
- # },
772
- # ]
773
- # },
774
- # "error_code": 0,
775
- # "msg": "Success",
776
- # "result": "true",
777
- # "success": True
778
- # }
779
- #
780
- orderbook = self.safe_value(response, 'data', {})
781
- timestamp = self.milliseconds()
782
- if market['swap']:
783
- return self.parse_order_book(orderbook, market['symbol'], timestamp, 'bids', 'asks', 'price', 'volume')
784
- return self.parse_order_book(orderbook, market['symbol'], timestamp)
785
-
786
- def parse_trade(self, trade, market=None) -> Trade:
787
- #
788
- # fetchTrades(old) spotPublicGetTrades
789
- #
790
- # {
791
- # "date_ms":1647021989789,
792
- # "amount":0.0028,
793
- # "price":38804.2,
794
- # "type":"buy",
795
- # "tid":"52d5616ee35c43019edddebe59b3e094"
796
- # }
797
- #
798
- #
799
- # fetchTrades(new) spotPublicGetTradesSupplement
800
- #
801
- # {
802
- # "quoteQty":1675.048485,
803
- # "price":0.127545,
804
- # "qty":13133,
805
- # "id":"3589541dc22e4357b227283650f714e2",
806
- # "time":1648058297110,
807
- # "isBuyerMaker":false
808
- # }
809
- #
810
- # fetchMyTrades(private)
811
- #
812
- # {
813
- # "orderUuid":"38b4e7a4-14f6-45fd-aba1-1a37024124a0",
814
- # "tradeFeeRate":0.0010000000,
815
- # "dealTime":1648500944496,
816
- # "dealQuantity":30.00000000000000000000,
817
- # "tradeFee":0.00453300000000000000,
818
- # "txUuid":"11f3850cc6214ea3b495adad3a032794",
819
- # "dealPrice":0.15111300000000000000,
820
- # "dealVolumePrice":4.53339000000000000000,
821
- # "tradeType":"sell_market"
822
- # }
823
- #
824
- timestamp = self.safe_integer_2(trade, 'date_ms', 'time')
825
- if timestamp is None:
826
- timestamp = self.safe_integer(trade, 'dealTime')
827
- amountString = self.safe_string_2(trade, 'amount', 'qty')
828
- if amountString is None:
829
- amountString = self.safe_string(trade, 'dealQuantity')
830
- priceString = self.safe_string(trade, 'price')
831
- if priceString is None:
832
- priceString = self.safe_string(trade, 'dealPrice')
833
- costString = self.safe_string(trade, 'quoteQty')
834
- if costString is None:
835
- costString = self.safe_string(trade, 'dealVolumePrice')
836
- side = self.safe_string_2(trade, 'tradeType', 'type')
837
- type = None
838
- takerOrMaker = None
839
- if side is not None:
840
- parts = side.split('_')
841
- side = self.safe_string(parts, 0)
842
- typePart = self.safe_string(parts, 1)
843
- type = 'limit'
844
- takerOrMaker = 'taker'
845
- if typePart is not None:
846
- if typePart == 'market':
847
- type = 'market'
848
- elif typePart == 'maker':
849
- takerOrMaker = 'maker'
850
- id = self.safe_string_2(trade, 'tid', 'id')
851
- if id is None:
852
- id = self.safe_string(trade, 'txUuid')
853
- order = self.safe_string(trade, 'orderUuid')
854
- symbol = self.safe_symbol(None, market)
855
- fee = None
856
- feeCost = self.safe_string(trade, 'tradeFee')
857
- if feeCost is not None:
858
- fee = {
859
- 'cost': feeCost,
860
- 'currency': market['base'] if (side == 'buy') else market['quote'],
861
- 'rate': self.safe_string(trade, 'tradeFeeRate'),
862
- }
863
- return self.safe_trade({
864
- 'timestamp': timestamp,
865
- 'datetime': self.iso8601(timestamp),
866
- 'symbol': symbol,
867
- 'id': id,
868
- 'order': order,
869
- 'type': type,
870
- 'takerOrMaker': takerOrMaker,
871
- 'side': side,
872
- 'price': priceString,
873
- 'amount': amountString,
874
- 'cost': costString,
875
- 'fee': fee,
876
- 'info': trade,
877
- }, market)
878
-
879
- async def fetch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
880
- """
881
- get the list of most recent trades for a particular symbol
882
- :see: https://www.lbank.info/en-US/docs/index.html#query-historical-transactions
883
- :see: https://www.lbank.info/en-US/docs/index.html#recent-transactions-list
884
- :param str symbol: unified symbol of the market to fetch trades for
885
- :param int [since]: timestamp in ms of the earliest trade to fetch
886
- :param int [limit]: the maximum amount of trades to fetch
887
- :param dict [params]: extra parameters specific to the lbank2 api endpoint
888
- :returns Trade[]: a list of `trade structures <https://github.com/ccxt/ccxt/wiki/Manual#public-trades>`
889
- """
890
- await self.load_markets()
891
- market = self.market(symbol)
892
- request = {
893
- 'symbol': market['id'],
894
- }
895
- if since is not None:
896
- request['time'] = since
897
- if limit is not None:
898
- request['size'] = min(limit, 600)
899
- else:
900
- request['size'] = 600 # max
901
- method = self.safe_string(params, 'method')
902
- params = self.omit(params, 'method')
903
- if method is None:
904
- options = self.safe_value(self.options, 'fetchTrades', {})
905
- method = self.safe_string(options, 'method', 'spotPublicGetTrades')
906
- response = await getattr(self, method)(self.extend(request, params))
907
- #
908
- # {
909
- # "result":"true",
910
- # "data": [
911
- # {
912
- # "date_ms":1647021989789,
913
- # "amount":0.0028,
914
- # "price":38804.2,
915
- # "type":"buy",
916
- # "tid":"52d5616ee35c43019edddebe59b3e094"
917
- # }
918
- # ],
919
- # "error_code":0,
920
- # "ts":1647021999308
921
- # }
922
- #
923
- trades = self.safe_value(response, 'data', [])
924
- return self.parse_trades(trades, market, since, limit)
925
-
926
- def parse_ohlcv(self, ohlcv, market=None) -> list:
927
- #
928
- # [
929
- # 1482311500, # timestamp
930
- # 5423.23, # open
931
- # 5472.80, # high
932
- # 5516.09, # low
933
- # 5462, # close
934
- # 234.3250 # volume
935
- # ],
936
- #
937
- return [
938
- self.safe_timestamp(ohlcv, 0), # timestamp
939
- self.safe_number(ohlcv, 1), # open
940
- self.safe_number(ohlcv, 2), # high
941
- self.safe_number(ohlcv, 3), # low
942
- self.safe_number(ohlcv, 4), # close
943
- self.safe_number(ohlcv, 5), # volume
944
- ]
945
-
946
- async def fetch_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}) -> List[list]:
947
- """
948
- fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
949
- :see: https://www.lbank.info/en-US/docs/index.html#query-k-bar-data
950
- :param str symbol: unified symbol of the market to fetch OHLCV data for
951
- :param str timeframe: the length of time each candle represents
952
- :param int [since]: timestamp in ms of the earliest candle to fetch
953
- :param int [limit]: the maximum amount of candles to fetch
954
- :param dict [params]: extra parameters specific to the lbank2 api endpoint
955
- :returns int[][]: A list of candles ordered, open, high, low, close, volume
956
- """
957
- # endpoint doesnt work
958
- await self.load_markets()
959
- market = self.market(symbol)
960
- if limit is None:
961
- limit = 100
962
- if since is None:
963
- duration = self.parse_timeframe(timeframe)
964
- since = self.milliseconds() - duration * 1000 * limit
965
- request = {
966
- 'symbol': market['id'],
967
- 'type': self.safe_string(self.timeframes, timeframe, timeframe),
968
- 'time': self.parse_to_int(since / 1000),
969
- 'size': limit, # max 2000
970
- }
971
- response = await self.spotPublicGetKline(self.extend(request, params))
972
- ohlcvs = self.safe_value(response, 'data', [])
973
- #
974
- #
975
- # [
976
- # [
977
- # 1482311500,
978
- # 5423.23,
979
- # 5472.80,
980
- # 5516.09,
981
- # 5462,
982
- # 234.3250
983
- # ],
984
- # [
985
- # 1482311400,
986
- # 5432.52,
987
- # 5459.87,
988
- # 5414.30,
989
- # 5428.23,
990
- # 213.7329
991
- # ]
992
- # ]
993
- #
994
- return self.parse_ohlcvs(ohlcvs, market, timeframe, since, limit)
995
-
996
- def parse_balance(self, response) -> Balances:
997
- #
998
- # spotPrivatePostUserInfo
999
- #
1000
- # {
1001
- # "toBtc": {
1002
- # "egc:": "0",
1003
- # "iog": "0",
1004
- # "ksm": "0",
1005
- # },
1006
- # "freeze": {
1007
- # "egc": "0",
1008
- # "iog": "0",
1009
- # "ksm": "0" ,
1010
- # },
1011
- # "asset": {
1012
- # "egc": "0",
1013
- # "iog": "0",
1014
- # "ksm": "0",
1015
- # },
1016
- # "free": {
1017
- # "egc": "0",
1018
- # "iog": "0",
1019
- # "ksm": "0",
1020
- # }
1021
- # }
1022
- #
1023
- # spotPrivatePostSupplementUserInfoAccount
1024
- #
1025
- # {
1026
- # "balances":[
1027
- # {
1028
- # "asset":"lbk",
1029
- # "free":"0",
1030
- # "locked":"0"
1031
- # }, ...
1032
- # ]
1033
- # }
1034
- #
1035
- # spotPrivatePostSupplementUserInfo
1036
- #
1037
- # [
1038
- # {
1039
- # "usableAmt":"31.45130723",
1040
- # "assetAmt":"31.45130723",
1041
- # "networkList":[
1042
- # {
1043
- # "isDefault":true,
1044
- # "withdrawFeeRate":"",
1045
- # "name":"bep20(bsc)",
1046
- # "withdrawMin":30,
1047
- # "minLimit":0.0001,
1048
- # "minDeposit":0.0001,
1049
- # "feeAssetCode":"doge",
1050
- # "withdrawFee":"30",
1051
- # "type":1,
1052
- # "coin":"doge",
1053
- # "network":"bsc"
1054
- # },
1055
- # {
1056
- # "isDefault":false,
1057
- # "withdrawFeeRate":"",
1058
- # "name":"dogecoin",
1059
- # "withdrawMin":10,
1060
- # "minLimit":0.0001,
1061
- # "minDeposit":10,
1062
- # "feeAssetCode":"doge",
1063
- # "withdrawFee":"10",
1064
- # "type":1,
1065
- # "coin":"doge",
1066
- # "network":"dogecoin"
1067
- # }
1068
- # ],
1069
- # "freezeAmt":"0",
1070
- # "coin":"doge"
1071
- # }, ...
1072
- # ]
1073
- #
1074
- timestamp = self.safe_integer(response, 'ts')
1075
- result = {
1076
- 'info': response,
1077
- 'timestamp': timestamp,
1078
- 'datetime': self.iso8601(timestamp),
1079
- }
1080
- data = self.safe_value(response, 'data')
1081
- # from spotPrivatePostUserInfo
1082
- toBtc = self.safe_value(data, 'toBtc')
1083
- if toBtc is not None:
1084
- used = self.safe_value(data, 'freeze', {})
1085
- free = self.safe_value(data, 'free', {})
1086
- currencies = list(free.keys())
1087
- for i in range(0, len(currencies)):
1088
- currencyId = currencies[i]
1089
- code = self.safe_currency_code(currencyId)
1090
- account = self.account()
1091
- account['used'] = self.safe_string(used, currencyId)
1092
- account['free'] = self.safe_string(free, currencyId)
1093
- result[code] = account
1094
- return self.safe_balance(result)
1095
- # from spotPrivatePostSupplementUserInfoAccount
1096
- balances = self.safe_value(data, 'balances')
1097
- if balances is not None:
1098
- for i in range(0, len(balances)):
1099
- item = balances[i]
1100
- currencyId = self.safe_string(item, 'asset')
1101
- codeInner = self.safe_currency_code(currencyId)
1102
- account = self.account()
1103
- account['free'] = self.safe_string(item, 'free')
1104
- account['used'] = self.safe_string(item, 'locked')
1105
- result[codeInner] = account
1106
- return self.safe_balance(result)
1107
- # from spotPrivatePostSupplementUserInfo
1108
- isArray = isinstance(data, list)
1109
- if isArray is True:
1110
- for i in range(0, len(data)):
1111
- item = data[i]
1112
- currencyId = self.safe_string(item, 'coin')
1113
- codeInner = self.safe_currency_code(currencyId)
1114
- account = self.account()
1115
- account['free'] = self.safe_string(item, 'usableAmt')
1116
- account['used'] = self.safe_string(item, 'freezeAmt')
1117
- result[codeInner] = account
1118
- return self.safe_balance(result)
1119
- return None
1120
-
1121
- async def fetch_balance(self, params={}) -> Balances:
1122
- """
1123
- query for balance and get the amount of funds available for trading or funds locked in orders
1124
- :see: https://www.lbank.info/en-US/docs/index.html#asset-information
1125
- :see: https://www.lbank.info/en-US/docs/index.html#account-information
1126
- :see: https://www.lbank.info/en-US/docs/index.html#get-all-coins-information
1127
- :param dict [params]: extra parameters specific to the lbank2 api endpoint
1128
- :returns dict: a `balance structure <https://github.com/ccxt/ccxt/wiki/Manual#balance-structure>`
1129
- """
1130
- await self.load_markets()
1131
- method = self.safe_string(params, 'method')
1132
- if method is None:
1133
- options = self.safe_value(self.options, 'fetchBalance', {})
1134
- method = self.safe_string(options, 'method', 'spotPrivatePostSupplementUserInfo')
1135
- response = await getattr(self, method)()
1136
- #
1137
- # {
1138
- # "result": "true",
1139
- # "data": [
1140
- # {
1141
- # "usableAmt": "14.36",
1142
- # "assetAmt": "14.36",
1143
- # "networkList": [
1144
- # {
1145
- # "isDefault": False,
1146
- # "withdrawFeeRate": "",
1147
- # "name": "erc20",
1148
- # "withdrawMin": 30,
1149
- # "minLimit": 0.0001,
1150
- # "minDeposit": 20,
1151
- # "feeAssetCode": "usdt",
1152
- # "withdrawFee": "30",
1153
- # "type": 1,
1154
- # "coin": "usdt",
1155
- # "network": "eth"
1156
- # },
1157
- # ...
1158
- # ],
1159
- # "freezeAmt": "0",
1160
- # "coin": "ada"
1161
- # }
1162
- # ],
1163
- # "code": 0
1164
- # }
1165
- #
1166
- return self.parse_balance(response)
1167
-
1168
- def parse_trading_fee(self, fee, market=None):
1169
- #
1170
- # {
1171
- # "symbol":"skt_usdt",
1172
- # "makerCommission":"0.10",
1173
- # "takerCommission":"0.10"
1174
- # }
1175
- #
1176
- marketId = self.safe_string(fee, 'symbol')
1177
- symbol = self.safe_symbol(marketId)
1178
- return {
1179
- 'info': fee,
1180
- 'symbol': symbol,
1181
- 'maker': self.safe_number(fee, 'makerCommission'),
1182
- 'taker': self.safe_number(fee, 'takerCommission'),
1183
- }
1184
-
1185
- async def fetch_trading_fee(self, symbol: str, params={}):
1186
- """
1187
- fetch the trading fees for a market
1188
- :see: https://www.lbank.info/en-US/docs/index.html#transaction-fee-rate-query
1189
- :param str symbol: unified market symbol
1190
- :param dict [params]: extra parameters specific to the lbank2 api endpoint
1191
- :returns dict: a `fee structure <https://github.com/ccxt/ccxt/wiki/Manual#fee-structure>`
1192
- """
1193
- market = self.market(symbol)
1194
- result = await self.fetch_trading_fees(self.extend(params, {'category': market['id']}))
1195
- return result
1196
-
1197
- async def fetch_trading_fees(self, params={}):
1198
- """
1199
- fetch the trading fees for multiple markets
1200
- :see: https://www.lbank.info/en-US/docs/index.html#transaction-fee-rate-query
1201
- :param dict [params]: extra parameters specific to the lbank2 api endpoint
1202
- :returns dict: a dictionary of `fee structures <https://github.com/ccxt/ccxt/wiki/Manual#fee-structure>` indexed by market symbols
1203
- """
1204
- await self.load_markets()
1205
- request = {}
1206
- response = await self.spotPrivatePostSupplementCustomerTradeFee(self.extend(request, params))
1207
- fees = self.safe_value(response, 'data', [])
1208
- result = {}
1209
- for i in range(0, len(fees)):
1210
- fee = self.parse_trading_fee(fees[i])
1211
- symbol = fee['symbol']
1212
- result[symbol] = fee
1213
- return result
1214
-
1215
- async def create_order(self, symbol: str, type: OrderType, side: OrderSide, amount, price=None, params={}):
1216
- """
1217
- create a trade order
1218
- :see: https://www.lbank.info/en-US/docs/index.html#place-order
1219
- :see: https://www.lbank.info/en-US/docs/index.html#place-an-order
1220
- :param str symbol: unified symbol of the market to create an order in
1221
- :param str type: 'market' or 'limit'
1222
- :param str side: 'buy' or 'sell'
1223
- :param float amount: how much of currency you want to trade in units of base currency
1224
- :param float [price]: the price at which the order is to be fullfilled, in units of the quote currency, ignored in market orders
1225
- :param dict [params]: extra parameters specific to the lbank2 api endpoint
1226
- :returns dict: an `order structure <https://github.com/ccxt/ccxt/wiki/Manual#order-structure>`
1227
- """
1228
- await self.load_markets()
1229
- market = self.market(symbol)
1230
- clientOrderId = self.safe_string_2(params, 'custom_id', 'clientOrderId')
1231
- postOnly = self.safe_value(params, 'postOnly', False)
1232
- timeInForce = self.safe_string_upper(params, 'timeInForce')
1233
- params = self.omit(params, ['custom_id', 'clientOrderId', 'timeInForce', 'postOnly'])
1234
- request = {
1235
- 'symbol': market['id'],
1236
- }
1237
- ioc = (timeInForce == 'IOC')
1238
- fok = (timeInForce == 'FOK')
1239
- maker = (postOnly or (timeInForce == 'PO'))
1240
- if (type == 'market') and (ioc or fok or maker):
1241
- raise InvalidOrder(self.id + ' createOrder() does not allow market FOK, IOC, or postOnly orders. Only limit IOC, FOK, and postOnly orders are allowed')
1242
- if type == 'limit':
1243
- request['type'] = side
1244
- request['price'] = self.price_to_precision(symbol, price)
1245
- request['amount'] = self.amount_to_precision(symbol, amount)
1246
- if ioc:
1247
- request['type'] = side + '_' + 'ioc'
1248
- elif fok:
1249
- request['type'] = side + '_' + 'fok'
1250
- elif maker:
1251
- request['type'] = side + '_' + 'maker'
1252
- elif type == 'market':
1253
- if side == 'sell':
1254
- request['type'] = side + '_' + 'market'
1255
- request['amount'] = self.amount_to_precision(symbol, amount)
1256
- elif side == 'buy':
1257
- request['type'] = side + '_' + 'market'
1258
- if self.options['createMarketBuyOrderRequiresPrice']:
1259
- if price is None:
1260
- raise InvalidOrder(self.id + " createOrder() requires the price argument with market buy orders to calculate total order cost(amount to spend), where cost = amount * price. Supply the price argument to createOrder() call if you want the cost to be calculated for you from price and amount, or, alternatively, add .options['createMarketBuyOrderRequiresPrice'] = False to supply the cost in the amount argument(the exchange-specific behaviour)")
1261
- else:
1262
- amountString = self.number_to_string(amount)
1263
- priceString = self.number_to_string(price)
1264
- quoteAmount = Precise.string_mul(amountString, priceString)
1265
- cost = self.parse_number(quoteAmount)
1266
- request['price'] = self.price_to_precision(symbol, cost)
1267
- else:
1268
- request['price'] = amount
1269
- if clientOrderId is not None:
1270
- request['custom_id'] = clientOrderId
1271
- method = None
1272
- method = self.safe_string(params, 'method')
1273
- params = self.omit(params, 'method')
1274
- if method is None:
1275
- options = self.safe_value(self.options, 'createOrder', {})
1276
- method = self.safe_string(options, 'method', 'spotPrivatePostSupplementCreateOrder')
1277
- response = await getattr(self, method)(self.extend(request, params))
1278
- #
1279
- # {
1280
- # "result":true,
1281
- # "data":{
1282
- # "symbol":"doge_usdt",
1283
- # "order_id":"0cf8a3de-4597-4296-af45-be7abaa06b07"
1284
- # },
1285
- # "error_code":0,
1286
- # "ts":1648162321043
1287
- # }
1288
- #
1289
- result = self.safe_value(response, 'data', {})
1290
- return self.safe_order({
1291
- 'id': self.safe_string(result, 'order_id'),
1292
- 'info': result,
1293
- }, market)
1294
-
1295
- def parse_order_status(self, status):
1296
- statuses = {
1297
- '-1': 'canceled', # canceled
1298
- '0': 'open', # not traded
1299
- '1': 'open', # partial deal
1300
- '2': 'closed', # complete deal
1301
- '3': 'canceled', # filled partially and cancelled
1302
- '4': 'closed', # disposal processing
1303
- }
1304
- return self.safe_string(statuses, status, status)
1305
-
1306
- def parse_order(self, order, market=None) -> Order:
1307
- #
1308
- # fetchOrderSupplement(private)
1309
- #
1310
- # {
1311
- # "cummulativeQuoteQty":0,
1312
- # "symbol":"doge_usdt",
1313
- # "executedQty":0,
1314
- # "orderId":"53d2d53e-70fb-4398-b722-f48571a5f61e",
1315
- # "origQty":1E+2,
1316
- # "price":0.05,
1317
- # "clientOrderId":null,
1318
- # "origQuoteOrderQty":5,
1319
- # "updateTime":1648163406000,
1320
- # "time":1648163139387,
1321
- # "type":"buy_maker",
1322
- # "status":-1
1323
- # }
1324
- #
1325
- #
1326
- # fetchOrderDefault(private)
1327
- #
1328
- # {
1329
- # "symbol":"shib_usdt",
1330
- # "amount":1,
1331
- # "create_time":1649367863356,
1332
- # "price":0.0000246103,
1333
- # "avg_price":0.00002466180000000104,
1334
- # "type":"buy_market",
1335
- # "order_id":"abe8b92d-86d9-4d6d-b71e-d14f5fb53ddf",
1336
- # "custom_id": "007", # field only present if user creates it at order time
1337
- # "deal_amount":40548.54065802,
1338
- # "status":2
1339
- # }
1340
- #
1341
- # fetchOpenOrders(private)
1342
- #
1343
- # {
1344
- # "cummulativeQuoteQty":0,
1345
- # "symbol":"doge_usdt",
1346
- # "executedQty":0,
1347
- # "orderId":"73878edf-008d-4e4c-8041-df1f1b2cd8bb",
1348
- # "origQty":100,
1349
- # "price":0.05,
1350
- # "origQuoteOrderQty":5,
1351
- # "updateTime":1648501762000,
1352
- # "time":1648501762353,
1353
- # "type":"buy",
1354
- # "status":0
1355
- # }
1356
- #
1357
- # fetchOrders(private)
1358
- #
1359
- # {
1360
- # "cummulativeQuoteQty":0,
1361
- # "symbol":"doge_usdt",
1362
- # "executedQty":0,
1363
- # "orderId":"2cadc7cc-b5f6-486b-a5b4-d6ac49a9c186",
1364
- # "origQty":100,
1365
- # "price":0.05,
1366
- # "origQuoteOrderQty":5,
1367
- # "updateTime":1648501384000,
1368
- # "time":1648501363889,
1369
- # "type":"buy",
1370
- # "status":-1
1371
- # }
1372
- #
1373
- id = self.safe_string_2(order, 'orderId', 'order_id')
1374
- clientOrderId = self.safe_string_2(order, 'clientOrderId', 'custom_id')
1375
- timestamp = self.safe_integer_2(order, 'time', 'create_time')
1376
- rawStatus = self.safe_string(order, 'status')
1377
- marketId = self.safe_string(order, 'symbol')
1378
- market = self.safe_market(marketId, market)
1379
- timeInForce = None
1380
- postOnly = False
1381
- type = 'limit'
1382
- rawType = self.safe_string(order, 'type') # buy, sell, buy_market, sell_market, buy_maker,sell_maker,buy_ioc,sell_ioc, buy_fok, sell_fok
1383
- parts = rawType.split('_')
1384
- side = self.safe_string(parts, 0)
1385
- typePart = self.safe_string(parts, 1) # market, maker, ioc, fok or None(limit)
1386
- if typePart == 'market':
1387
- type = 'market'
1388
- if typePart == 'maker':
1389
- postOnly = True
1390
- timeInForce = 'PO'
1391
- if typePart == 'ioc':
1392
- timeInForce = 'IOC'
1393
- if typePart == 'fok':
1394
- timeInForce = 'FOK'
1395
- price = self.safe_string(order, 'price')
1396
- costString = self.safe_string(order, 'cummulativeQuoteQty')
1397
- amountString = None
1398
- if rawType != 'buy_market':
1399
- amountString = self.safe_string_2(order, 'origQty', 'amount')
1400
- filledString = self.safe_string_2(order, 'executedQty', 'deal_amount')
1401
- return self.safe_order({
1402
- 'id': id,
1403
- 'clientOrderId': clientOrderId,
1404
- 'datetime': self.iso8601(timestamp),
1405
- 'timestamp': timestamp,
1406
- 'lastTradeTimestamp': None,
1407
- 'status': self.parse_order_status(rawStatus),
1408
- 'symbol': market['symbol'],
1409
- 'type': type,
1410
- 'timeInForce': timeInForce,
1411
- 'postOnly': postOnly,
1412
- 'side': side,
1413
- 'price': price,
1414
- 'stopPrice': None,
1415
- 'triggerPrice': None,
1416
- 'cost': costString,
1417
- 'amount': amountString,
1418
- 'filled': filledString,
1419
- 'remaining': None,
1420
- 'trades': None,
1421
- 'fee': None,
1422
- 'info': order,
1423
- 'average': None,
1424
- }, market)
1425
-
1426
- async def fetch_order(self, id: str, symbol: String = None, params={}):
1427
- """
1428
- fetches information on an order made by the user
1429
- :see: https://www.lbank.info/en-US/docs/index.html#query-order
1430
- :see: https://www.lbank.info/en-US/docs/index.html#query-order-new
1431
- :param str symbol: unified symbol of the market the order was made in
1432
- :param dict [params]: extra parameters specific to the lbank2 api endpoint
1433
- :returns dict: An `order structure <https://github.com/ccxt/ccxt/wiki/Manual#order-structure>`
1434
- """
1435
- await self.load_markets()
1436
- method = self.safe_string(params, 'method')
1437
- if method is None:
1438
- options = self.safe_value(self.options, 'fetchOrder', {})
1439
- method = self.safe_string(options, 'method', 'fetchOrderSupplement')
1440
- if method == 'fetchOrderSupplement':
1441
- return await self.fetch_order_supplement(id, symbol, params)
1442
- return await self.fetch_order_default(id, symbol, params)
1443
-
1444
- async def fetch_order_supplement(self, id: str, symbol: String = None, params={}):
1445
- self.check_required_symbol('fetchOrder', symbol)
1446
- await self.load_markets()
1447
- market = self.market(symbol)
1448
- request = {
1449
- 'symbol': market['id'],
1450
- 'orderId': id,
1451
- }
1452
- response = await self.spotPrivatePostSupplementOrdersInfo(self.extend(request, params))
1453
- #
1454
- # {
1455
- # "result":true,
1456
- # "data":{
1457
- # "cummulativeQuoteQty":0,
1458
- # "symbol":"doge_usdt",
1459
- # "executedQty":0,
1460
- # "orderId":"53d2d53e-70fb-4398-b722-f48571a5f61e",
1461
- # "origQty":1E+2,
1462
- # "price":0.05,
1463
- # "clientOrderId":null,
1464
- # "origQuoteOrderQty":5,
1465
- # "updateTime":1648163406000,
1466
- # "time":1648163139387,
1467
- # "type":"buy_maker",
1468
- # "status":-1
1469
- # },
1470
- # "error_code":0,
1471
- # "ts":1648164471827
1472
- # }
1473
- #
1474
- result = self.safe_value(response, 'data', {})
1475
- return self.parse_order(result)
1476
-
1477
- async def fetch_order_default(self, id: str, symbol: String = None, params={}):
1478
- # Id can be a list of ids delimited by a comma
1479
- self.check_required_symbol('fetchOrder', symbol)
1480
- await self.load_markets()
1481
- market = self.market(symbol)
1482
- request = {
1483
- 'symbol': market['id'],
1484
- 'order_id': id,
1485
- }
1486
- response = await self.spotPrivatePostOrdersInfo(self.extend(request, params))
1487
- #
1488
- # {
1489
- # "result":true,
1490
- # "data":[
1491
- # {
1492
- # "symbol":"doge_usdt",
1493
- # "amount":18,
1494
- # "create_time":1647455223186,
1495
- # "price":0,
1496
- # "avg_price":0.113344,
1497
- # "type":"sell_market",
1498
- # "order_id":"d4ca1ddd-40d9-42c1-9717-5de435865bec",
1499
- # "deal_amount":18,
1500
- # "status":2
1501
- # }
1502
- # ],
1503
- # "error_code":0,
1504
- # "ts":1647455270776
1505
- # }
1506
- #
1507
- result = self.safe_value(response, 'data', [])
1508
- numOrders = len(result)
1509
- if numOrders == 1:
1510
- return self.parse_order(result[0])
1511
- else:
1512
- # parsedOrders = []
1513
- # for i in range(0, numOrders):
1514
- # parsedOrder = self.parse_order(result[i])
1515
- # parsedOrders.append(parsedOrder)
1516
- # }
1517
- # return parsedOrders
1518
- raise BadRequest(self.id + ' fetchOrder() can only fetch one order at a time')
1519
-
1520
- async def fetch_my_trades(self, symbol: String = None, since: Int = None, limit: Int = None, params={}):
1521
- """
1522
- fetch all trades made by the user
1523
- :see: https://www.lbank.info/en-US/docs/index.html#past-transaction-details
1524
- :param str symbol: unified market symbol
1525
- :param int [since]: the earliest time in ms to fetch trades for
1526
- :param int [limit]: the maximum number of trade structures to retrieve
1527
- :param dict [params]: extra parameters specific to the lbank2 api endpoint
1528
- :returns Trade[]: a list of `trade structures <https://github.com/ccxt/ccxt/wiki/Manual#trade-structure>`
1529
- """
1530
- self.check_required_symbol('fetchMyTrades', symbol)
1531
- await self.load_markets()
1532
- market = self.market(symbol)
1533
- since = self.safe_value(params, 'start_date', since)
1534
- params = self.omit(params, 'start_date')
1535
- request = {
1536
- 'symbol': market['id'],
1537
- # 'start_date' Start time yyyy-mm-dd, the maximum is today, the default is yesterday
1538
- # 'end_date' Finish time yyyy-mm-dd, the maximum is today, the default is today
1539
- # 'The start': and end date of the query window is up to 2 days
1540
- # 'from' Initial transaction number inquiring
1541
- # 'direct' inquire direction,The default is the 'next' which is the positive sequence of dealing time,the 'prev' is inverted order of dealing time
1542
- # 'size' Query the number of defaults to 100
1543
- }
1544
- if limit is not None:
1545
- request['size'] = limit
1546
- if since is not None:
1547
- request['start_date'] = self.ymd(since, '-') # max query 2 days ago
1548
- request['end_date'] = self.ymd(since + 86400000, '-') # will cover 2 days
1549
- response = await self.spotPrivatePostTransactionHistory(self.extend(request, params))
1550
- #
1551
- # {
1552
- # "result":true,
1553
- # "data":[
1554
- # {
1555
- # "orderUuid":"38b4e7a4-14f6-45fd-aba1-1a37024124a0",
1556
- # "tradeFeeRate":0.0010000000,
1557
- # "dealTime":1648500944496,
1558
- # "dealQuantity":30.00000000000000000000,
1559
- # "tradeFee":0.00453300000000000000,
1560
- # "txUuid":"11f3850cc6214ea3b495adad3a032794",
1561
- # "dealPrice":0.15111300000000000000,
1562
- # "dealVolumePrice":4.53339000000000000000,
1563
- # "tradeType":"sell_market"
1564
- # }
1565
- # ],
1566
- # "error_code":0,
1567
- # "ts":1648509742164
1568
- # }
1569
- #
1570
- trades = self.safe_value(response, 'data', [])
1571
- return self.parse_trades(trades, market, since, limit)
1572
-
1573
- async def fetch_orders(self, symbol: String = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
1574
- """
1575
- fetches information on multiple orders made by the user
1576
- :see: https://www.lbank.info/en-US/docs/index.html#query-all-orders
1577
- :param str symbol: unified market symbol of the market orders were made in
1578
- :param int [since]: the earliest time in ms to fetch orders for
1579
- :param int [limit]: the maximum number of order structures to retrieve
1580
- :param dict [params]: extra parameters specific to the lbank2 api endpoint
1581
- :returns Order[]: a list of `order structures <https://github.com/ccxt/ccxt/wiki/Manual#order-structure>`
1582
- """
1583
- # default query is for canceled and completely filled orders
1584
- # does not return open orders unless specified explicitly
1585
- self.check_required_symbol('fetchOrders', symbol)
1586
- await self.load_markets()
1587
- market = self.market(symbol)
1588
- if limit is None:
1589
- limit = 100
1590
- request = {
1591
- 'symbol': market['id'],
1592
- 'current_page': 1,
1593
- 'page_length': limit,
1594
- # 'status' -1: Cancelled, 0: Unfilled, 1: Partially filled, 2: Completely filled, 3: Partially filled and cancelled, 4: Cancellation is being processed
1595
- }
1596
- response = await self.spotPrivatePostSupplementOrdersInfoHistory(self.extend(request, params))
1597
- #
1598
- # {
1599
- # "result":true,
1600
- # "data":{
1601
- # "total":1,
1602
- # "page_length":100,
1603
- # "orders":[
1604
- # {
1605
- # "cummulativeQuoteQty":0,
1606
- # "symbol":"doge_usdt",
1607
- # "executedQty":0,
1608
- # "orderId":"2cadc7cc-b5f6-486b-a5b4-d6ac49a9c186",
1609
- # "origQty":100,
1610
- # "price":0.05,
1611
- # "origQuoteOrderQty":5,
1612
- # "updateTime":1648501384000,
1613
- # "time":1648501363889,
1614
- # "type":"buy",
1615
- # "status":-1
1616
- # }, ...
1617
- # ],
1618
- # "current_page":1
1619
- # },
1620
- # "error_code":0,
1621
- # "ts":1648505706348
1622
- # }
1623
- #
1624
- result = self.safe_value(response, 'data', {})
1625
- orders = self.safe_value(result, 'orders', [])
1626
- return self.parse_orders(orders, market, since, limit)
1627
-
1628
- async def fetch_open_orders(self, symbol: String = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
1629
- """
1630
- fetch all unfilled currently open orders
1631
- :see: https://www.lbank.info/en-US/docs/index.html#current-pending-order
1632
- :param str symbol: unified market symbol
1633
- :param int [since]: the earliest time in ms to fetch open orders for
1634
- :param int [limit]: the maximum number of open order structures to retrieve
1635
- :param dict [params]: extra parameters specific to the lbank2 api endpoint
1636
- :returns Order[]: a list of `order structures <https://github.com/ccxt/ccxt/wiki/Manual#order-structure>`
1637
- """
1638
- self.check_required_symbol('fetchOpenOrders', symbol)
1639
- await self.load_markets()
1640
- market = self.market(symbol)
1641
- if limit is None:
1642
- limit = 100
1643
- request = {
1644
- 'symbol': market['id'],
1645
- 'current_page': 1,
1646
- 'page_length': limit,
1647
- }
1648
- response = await self.spotPrivatePostSupplementOrdersInfoNoDeal(self.extend(request, params))
1649
- #
1650
- # {
1651
- # "result":true,
1652
- # "data":{
1653
- # "total":1,
1654
- # "page_length":100,
1655
- # "orders":[
1656
- # {
1657
- # "cummulativeQuoteQty":0,
1658
- # "symbol":"doge_usdt",
1659
- # "executedQty":0,
1660
- # "orderId":"73878edf-008d-4e4c-8041-df1f1b2cd8bb",
1661
- # "origQty":100,
1662
- # "price":0.05,
1663
- # "origQuoteOrderQty":5,
1664
- # "updateTime":1648501762000,
1665
- # "time":1648501762353,
1666
- # "type":"buy",
1667
- # "status":0
1668
- # }, ...
1669
- # ],
1670
- # "current_page":1
1671
- # },
1672
- # "error_code":0,
1673
- # "ts":1648506110196
1674
- # }
1675
- #
1676
- result = self.safe_value(response, 'data', {})
1677
- orders = self.safe_value(result, 'orders', [])
1678
- return self.parse_orders(orders, market, since, limit)
1679
-
1680
- async def cancel_order(self, id: str, symbol: String = None, params={}):
1681
- """
1682
- cancels an open order
1683
- :see: https://www.lbank.info/en-US/docs/index.html#cancel-order-new
1684
- :param str id: order id
1685
- :param str symbol: unified symbol of the market the order was made in
1686
- :param dict [params]: extra parameters specific to the lbank2 api endpoint
1687
- :returns dict: An `order structure <https://github.com/ccxt/ccxt/wiki/Manual#order-structure>`
1688
- """
1689
- self.check_required_symbol('cancelOrder', symbol)
1690
- await self.load_markets()
1691
- clientOrderId = self.safe_string_2(params, 'origClientOrderId', 'clientOrderId')
1692
- params = self.omit(params, ['origClientOrderId', 'clientOrderId'])
1693
- market = self.market(symbol)
1694
- request = {
1695
- 'symbol': market['id'],
1696
- 'orderId': id,
1697
- }
1698
- if clientOrderId is not None:
1699
- request['origClientOrderId'] = clientOrderId
1700
- response = await self.spotPrivatePostSupplementCancelOrder(self.extend(request, params))
1701
- #
1702
- # {
1703
- # "result":true,
1704
- # "data":{
1705
- # "executedQty":0.0,
1706
- # "price":0.05,
1707
- # "origQty":100.0,
1708
- # "tradeType":"buy",
1709
- # "status":0
1710
- # },
1711
- # "error_code":0,
1712
- # "ts":1648501286196
1713
- # }
1714
- result = self.safe_value(response, 'data', {})
1715
- return result
1716
-
1717
- async def cancel_all_orders(self, symbol: String = None, params={}):
1718
- """
1719
- cancel all open orders in a market
1720
- :see: https://www.lbank.info/en-US/docs/index.html#cancel-all-pending-orders-for-a-single-trading-pair
1721
- :param str symbol: unified market symbol of the market to cancel orders in
1722
- :param dict [params]: extra parameters specific to the lbank2 api endpoint
1723
- :returns dict[]: a list of `order structures <https://github.com/ccxt/ccxt/wiki/Manual#order-structure>`
1724
- """
1725
- self.check_required_symbol('cancelAllOrders', symbol)
1726
- await self.load_markets()
1727
- market = self.market(symbol)
1728
- request = {
1729
- 'symbol': market['id'],
1730
- }
1731
- response = await self.spotPrivatePostSupplementCancelOrderBySymbol(self.extend(request, params))
1732
- #
1733
- # {
1734
- # "result":"true",
1735
- # "data":[
1736
- # {
1737
- # "executedQty":0.00000000000000000000,
1738
- # "orderId":"293ef71b-3e67-4962-af93-aa06990a045f",
1739
- # "price":0.05000000000000000000,
1740
- # "origQty":100.00000000000000000000,
1741
- # "tradeType":"buy",
1742
- # "status":0
1743
- # },
1744
- # ],
1745
- # "error_code":0,
1746
- # "ts":1648506641469
1747
- # }
1748
- #
1749
- result = self.safe_value(response, 'data', [])
1750
- return result
1751
-
1752
- def get_network_code_for_currency(self, currencyCode, params):
1753
- defaultNetworks = self.safe_value(self.options, 'defaultNetworks')
1754
- defaultNetwork = self.safe_string_upper(defaultNetworks, currencyCode)
1755
- networks = self.safe_value(self.options, 'networks', {})
1756
- network = self.safe_string_upper(params, 'network', defaultNetwork) # self line allows the user to specify either ERC20 or ETH
1757
- network = self.safe_string(networks, network, network) # handle ERC20>ETH alias
1758
- return network
1759
-
1760
- async def fetch_deposit_address(self, code: str, params={}):
1761
- """
1762
- fetch the deposit address for a currency associated with self account
1763
- :see: https://www.lbank.info/en-US/docs/index.html#get-deposit-address
1764
- :see: https://www.lbank.info/en-US/docs/index.html#the-user-obtains-the-deposit-address
1765
- :param str code: unified currency code
1766
- :param dict [params]: extra parameters specific to the lbank2 api endpoint
1767
- :returns dict: an `address structure <https://github.com/ccxt/ccxt/wiki/Manual#address-structure>`
1768
- """
1769
- await self.load_markets()
1770
- method = self.safe_string(params, 'method')
1771
- params = self.omit(params, 'method')
1772
- if method is None:
1773
- options = self.safe_value(self.options, 'fetchDepositAddress', {})
1774
- method = self.safe_string(options, 'method', 'fetchDepositAddressDefault')
1775
- return await getattr(self, method)(code, params)
1776
-
1777
- async def fetch_deposit_address_default(self, code: str, params={}):
1778
- await self.load_markets()
1779
- currency = self.currency(code)
1780
- request = {
1781
- 'assetCode': currency['id'],
1782
- }
1783
- network = self.get_network_code_for_currency(code, params)
1784
- if network is not None:
1785
- request['netWork'] = network # ... yes, really lol
1786
- params = self.omit(params, 'network')
1787
- response = await self.spotPrivatePostGetDepositAddress(self.extend(request, params))
1788
- #
1789
- # {
1790
- # "result":true,
1791
- # "data":{
1792
- # "assetCode":"usdt",
1793
- # "address":"0xc85689d37ca650bf2f2161364cdedee21eb6ca53",
1794
- # "memo":null,
1795
- # "netWork":"bep20(bsc)"
1796
- # },
1797
- # "error_code":0,
1798
- # "ts":1648075865103
1799
- # }
1800
- #
1801
- result = self.safe_value(response, 'data')
1802
- address = self.safe_string(result, 'address')
1803
- tag = self.safe_string(result, 'memo')
1804
- networkId = self.safe_string(result, 'netWork')
1805
- inverseNetworks = self.safe_value(self.options, 'inverse-networks', {})
1806
- networkCode = self.safe_string_upper(inverseNetworks, networkId, networkId)
1807
- return {
1808
- 'currency': code,
1809
- 'address': address,
1810
- 'tag': tag,
1811
- 'network': networkCode,
1812
- 'info': response,
1813
- }
1814
-
1815
- async def fetch_deposit_address_supplement(self, code: str, params={}):
1816
- # returns the address for whatever the default network is...
1817
- await self.load_markets()
1818
- currency = self.currency(code)
1819
- request = {
1820
- 'coin': currency['id'],
1821
- }
1822
- networks = self.safe_value(self.options, 'networks')
1823
- network = self.safe_string_upper(params, 'network')
1824
- network = self.safe_string(networks, network, network)
1825
- if network is not None:
1826
- request['networkName'] = network
1827
- params = self.omit(params, 'network')
1828
- response = await self.spotPrivatePostSupplementGetDepositAddress(self.extend(request, params))
1829
- #
1830
- # {
1831
- # "result":true,
1832
- # "data":{
1833
- # "address":"TDxtabCC8iQwaxUUrPcE4WL2jArGAfvQ5A",
1834
- # "memo":null,
1835
- # "coin":"usdt"
1836
- # },
1837
- # "error_code":0,
1838
- # "ts":1648073818880
1839
- # }
1840
- #
1841
- result = self.safe_value(response, 'data')
1842
- address = self.safe_string(result, 'address')
1843
- tag = self.safe_string(result, 'memo')
1844
- inverseNetworks = self.safe_value(self.options, 'inverse-networks', {})
1845
- networkCode = self.safe_string_upper(inverseNetworks, network, network)
1846
- return {
1847
- 'currency': code,
1848
- 'address': address,
1849
- 'tag': tag,
1850
- 'network': networkCode, # will be None if not specified in request
1851
- 'info': response,
1852
- }
1853
-
1854
- async def withdraw(self, code: str, amount, address, tag=None, params={}):
1855
- """
1856
- make a withdrawal
1857
- :see: https://www.lbank.info/en-US/docs/index.html#withdrawal
1858
- :param str code: unified currency code
1859
- :param float amount: the amount to withdraw
1860
- :param str address: the address to withdraw to
1861
- :param str tag:
1862
- :param dict [params]: extra parameters specific to the lbank2 api endpoint
1863
- :returns dict: a `transaction structure <https://github.com/ccxt/ccxt/wiki/Manual#transaction-structure>`
1864
- """
1865
- tag, params = self.handle_withdraw_tag_and_params(tag, params)
1866
- self.check_address(address)
1867
- await self.load_markets()
1868
- fee = self.safe_string(params, 'fee')
1869
- params = self.omit(params, 'fee')
1870
- # The relevant coin network fee can be found by calling fetchDepositWithdrawFees(), note: if no network param is supplied then the default network will be used, self can also be found in fetchDepositWithdrawFees().
1871
- self.check_required_argument('withdraw', fee, 'fee')
1872
- currency = self.currency(code)
1873
- request = {
1874
- 'address': address,
1875
- 'coin': currency['id'],
1876
- 'amount': amount,
1877
- 'fee': fee, # the correct coin-network fee must be supplied, which can be found by calling fetchDepositWithdrawFees(private)
1878
- # 'networkName': defaults to the defaultNetwork of the coin which can be found in the /supplement/user_info endpoint
1879
- # 'memo': memo: memo word of bts and dct
1880
- # 'mark': Withdrawal Notes
1881
- # 'name': Remarks of the address. After hasattr(self, filling) parameter, it will be added to the withdrawal address book of the currency.
1882
- # 'withdrawOrderId': withdrawOrderId
1883
- # 'type': type=1 is for intra-site transfer
1884
- }
1885
- if tag is not None:
1886
- request['memo'] = tag
1887
- network = self.safe_string_upper_2(params, 'network', 'networkName')
1888
- params = self.omit(params, ['network', 'networkName'])
1889
- networks = self.safe_value(self.options, 'networks')
1890
- networkId = self.safe_string(networks, network, network)
1891
- if networkId is not None:
1892
- request['networkName'] = networkId
1893
- response = await self.spotPrivatePostSupplementWithdraw(self.extend(request, params))
1894
- #
1895
- # {
1896
- # "result":true,
1897
- # "data": {
1898
- # "fee":10.00000000000000000000,
1899
- # "withdrawId":1900376
1900
- # },
1901
- # "error_code":0,
1902
- # "ts":1648992501414
1903
- # }
1904
- #
1905
- result = self.safe_value(response, 'data', {})
1906
- return {
1907
- 'info': result,
1908
- 'id': self.safe_string(result, 'withdrawId'),
1909
- }
1910
-
1911
- def parse_transaction_status(self, status, type):
1912
- statuses = {
1913
- 'deposit': {
1914
- '1': 'pending',
1915
- '2': 'ok',
1916
- '3': 'failed',
1917
- '4': 'canceled',
1918
- '5': 'transfer',
1919
- },
1920
- 'withdrawal': {
1921
- '1': 'pending',
1922
- '2': 'canceled',
1923
- '3': 'failed',
1924
- '4': 'ok',
1925
- },
1926
- }
1927
- return self.safe_string(self.safe_value(statuses, type, {}), status, status)
1928
-
1929
- def parse_transaction(self, transaction, currency=None) -> Transaction:
1930
- #
1931
- # fetchDeposits(private)
1932
- #
1933
- # {
1934
- # "insertTime":1649012310000,
1935
- # "amount":9.00000000000000000000,
1936
- # "address":"TYASr5UV6HEcXatwdFQfmLVUqQQQMUxHLS",
1937
- # "networkName":"trc20",
1938
- # "txId":"081e4e9351dd0274922168da5f2d14ea6c495b1c3b440244f4a6dd9fe196bf2b",
1939
- # "coin":"usdt",
1940
- # "status":"2"
1941
- # }
1942
- #
1943
- #
1944
- # fetchWithdrawals(private)
1945
- #
1946
- # {
1947
- # "amount":2.00000000000000000000,
1948
- # "address":"TBjrW5JHDyPZjFc5nrRMhRWUDaJmhGhmD6",
1949
- # "fee":1.00000000000000000000,
1950
- # "networkName":"trc20",
1951
- # "coid":"usdt",
1952
- # "transferType":"数字资产提现",
1953
- # "txId":"47eeee2763ad49b8817524dacfa7d092fb58f8b0ab7e5d25473314df1a793c3d",
1954
- # "id":1902194,
1955
- # "applyTime":1649014002000,
1956
- # "status":"4"
1957
- # }
1958
- #
1959
- id = self.safe_string(transaction, 'id')
1960
- type = None
1961
- if id is None:
1962
- type = 'deposit'
1963
- else:
1964
- type = 'withdrawal'
1965
- txid = self.safe_string(transaction, 'txId')
1966
- timestamp = self.safe_integer_2(transaction, 'insertTime', 'applyTime')
1967
- networks = self.safe_value(self.options, 'inverse-networks', {})
1968
- networkId = self.safe_string(transaction, 'networkName')
1969
- network = self.safe_string(networks, networkId, networkId)
1970
- address = self.safe_string(transaction, 'address')
1971
- addressFrom = None
1972
- addressTo = None
1973
- if type == 'deposit':
1974
- addressFrom = address
1975
- else:
1976
- addressTo = address
1977
- amount = self.safe_number(transaction, 'amount')
1978
- currencyId = self.safe_string_2(transaction, 'coin', 'coid')
1979
- code = self.safe_currency_code(currencyId, currency)
1980
- status = self.parse_transaction_status(self.safe_string(transaction, 'status'), type)
1981
- fee = None
1982
- feeCost = self.safe_number(transaction, 'fee')
1983
- if feeCost is not None:
1984
- fee = {
1985
- 'cost': feeCost,
1986
- 'currency': code,
1987
- }
1988
- return {
1989
- 'info': transaction,
1990
- 'id': id,
1991
- 'txid': txid,
1992
- 'timestamp': timestamp,
1993
- 'datetime': self.iso8601(timestamp),
1994
- 'network': network,
1995
- 'address': address,
1996
- 'addressTo': addressTo,
1997
- 'addressFrom': addressFrom,
1998
- 'tag': None,
1999
- 'tagTo': None,
2000
- 'tagFrom': None,
2001
- 'type': type,
2002
- 'amount': amount,
2003
- 'currency': code,
2004
- 'status': status,
2005
- 'updated': None,
2006
- 'comment': None,
2007
- 'internal': (status == 'transfer'),
2008
- 'fee': fee,
2009
- }
2010
-
2011
- async def fetch_deposits(self, code: String = None, since: Int = None, limit: Int = None, params={}) -> List[Transaction]:
2012
- """
2013
- fetch all deposits made to an account
2014
- :see: https://www.lbank.info/en-US/docs/index.html#get-recharge-history
2015
- :param str code: unified currency code
2016
- :param int [since]: the earliest time in ms to fetch deposits for
2017
- :param int [limit]: the maximum number of deposits structures to retrieve
2018
- :param dict [params]: extra parameters specific to the lbank2 api endpoint
2019
- :returns dict[]: a list of `transaction structures <https://github.com/ccxt/ccxt/wiki/Manual#transaction-structure>`
2020
- """
2021
- await self.load_markets()
2022
- request = {
2023
- # 'status': Recharge status: ("1","Applying"),("2","Recharge successful"),("3","Recharge failed"),("4","Already Cancel"),("5", "Transfer")
2024
- # 'endTime': end time, timestamp in milliseconds, default now
2025
- }
2026
- currency = None
2027
- if code is not None:
2028
- currency = self.currency(code)
2029
- request['coin'] = currency['id']
2030
- if since is not None:
2031
- request['startTime'] = since
2032
- response = await self.spotPrivatePostSupplementDepositHistory(self.extend(request, params))
2033
- #
2034
- # {
2035
- # "result":true,
2036
- # "data": {
2037
- # "total":1,
2038
- # "depositOrders": [
2039
- # {
2040
- # "insertTime":1649012310000,
2041
- # "amount":9.00000000000000000000,
2042
- # "address":"TYASr5UV6HEcXatwdFQfmLVUqQQQMUxHLS",
2043
- # "networkName":"trc20",
2044
- # "txId":"081e4e9351dd0274922168da5f2d14ea6c495b1c3b440244f4a6dd9fe196bf2b",
2045
- # "coin":"usdt",
2046
- # "status":"2"
2047
- # },
2048
- # ],
2049
- # "page_length":20,
2050
- # "current_page":1
2051
- # },
2052
- # "error_code":0,
2053
- # "ts":1649719721758
2054
- # }
2055
- #
2056
- data = self.safe_value(response, 'data', {})
2057
- deposits = self.safe_value(data, 'depositOrders', [])
2058
- return self.parse_transactions(deposits, currency, since, limit)
2059
-
2060
- async def fetch_withdrawals(self, code: String = None, since: Int = None, limit: Int = None, params={}) -> List[Transaction]:
2061
- """
2062
- fetch all withdrawals made from an account
2063
- :see: https://www.lbank.info/en-US/docs/index.html#get-withdrawal-history
2064
- :param str code: unified currency code
2065
- :param int [since]: the earliest time in ms to fetch withdrawals for
2066
- :param int [limit]: the maximum number of withdrawals structures to retrieve
2067
- :param dict [params]: extra parameters specific to the lbank2 api endpoint
2068
- :returns dict[]: a list of `transaction structures <https://github.com/ccxt/ccxt/wiki/Manual#transaction-structure>`
2069
- """
2070
- await self.load_markets()
2071
- request = {
2072
- # 'status': Recharge status: ("1","Applying"),("2","Recharge successful"),("3","Recharge failed"),("4","Already Cancel"),("5", "Transfer")
2073
- # 'endTime': end time, timestamp in milliseconds, default now
2074
- # 'withdrawOrderId': Custom withdrawal id
2075
- }
2076
- currency = None
2077
- if code is not None:
2078
- currency = self.currency(code)
2079
- request['coin'] = currency['id']
2080
- if since is not None:
2081
- request['startTime'] = since
2082
- response = await self.spotPrivatePostSupplementWithdraws(self.extend(request, params))
2083
- #
2084
- # {
2085
- # "result":true,
2086
- # "data": {
2087
- # "total":1,
2088
- # "withdraws": [
2089
- # {
2090
- # "amount":2.00000000000000000000,
2091
- # "address":"TBjrW5JHDyPZjFc5nrRMhRWUDaJmhGhmD6",
2092
- # "fee":1.00000000000000000000,
2093
- # "networkName":"trc20",
2094
- # "coid":"usdt",
2095
- # "transferType":"数字资产提现",
2096
- # "txId":"47eeee2763ad49b8817524dacfa7d092fb58f8b0ab7e5d25473314df1a793c3d",
2097
- # "id":1902194,
2098
- # "applyTime":1649014002000,
2099
- # "status":"4"
2100
- # },
2101
- # ],
2102
- # "page_length":20,
2103
- # "current_page":1
2104
- # },
2105
- # "error_code":0,
2106
- # "ts":1649720362362
2107
- # }
2108
- #
2109
- data = self.safe_value(response, 'data', {})
2110
- withdraws = self.safe_value(data, 'withdraws', [])
2111
- return self.parse_transactions(withdraws, currency, since, limit)
2112
-
2113
- async def fetch_transaction_fees(self, codes=None, params={}):
2114
- """
2115
- * @deprecated
2116
- please use fetchDepositWithdrawFees instead
2117
- :param str[]|None codes: not used by lbank2 fetchTransactionFees()
2118
- :param dict [params]: extra parameters specific to the lbank2 api endpoint
2119
- :returns dict: a list of `fee structures <https://github.com/ccxt/ccxt/wiki/Manual#fee-structure>`
2120
- """
2121
- # private only returns information for currencies with non-zero balance
2122
- await self.load_markets()
2123
- isAuthorized = self.check_required_credentials(False)
2124
- result = None
2125
- if isAuthorized is True:
2126
- method = self.safe_string(params, 'method')
2127
- params = self.omit(params, 'method')
2128
- if method is None:
2129
- options = self.safe_value(self.options, 'fetchTransactionFees', {})
2130
- method = self.safe_string(options, 'method', 'fetchPrivateTransactionFees')
2131
- result = await getattr(self, method)(params)
2132
- else:
2133
- result = await self.fetch_public_transaction_fees(params)
2134
- return result
2135
-
2136
- async def fetch_private_transaction_fees(self, params={}):
2137
- # complete response
2138
- # incl. for coins which None in public method
2139
- await self.load_markets()
2140
- response = await self.spotPrivatePostSupplementUserInfo()
2141
- #
2142
- # {
2143
- # "result": "true",
2144
- # "data": [
2145
- # {
2146
- # "usableAmt": "14.36",
2147
- # "assetAmt": "14.36",
2148
- # "networkList": [
2149
- # {
2150
- # "isDefault": False,
2151
- # "withdrawFeeRate": "",
2152
- # "name": "erc20",
2153
- # "withdrawMin": 30,
2154
- # "minLimit": 0.0001,
2155
- # "minDeposit": 20,
2156
- # "feeAssetCode": "usdt",
2157
- # "withdrawFee": "30",
2158
- # "type": 1,
2159
- # "coin": "usdt",
2160
- # "network": "eth"
2161
- # },
2162
- # ...
2163
- # ],
2164
- # "freezeAmt": "0",
2165
- # "coin": "ada"
2166
- # }
2167
- # ],
2168
- # "code": 0
2169
- # }
2170
- #
2171
- result = self.safe_value(response, 'data', [])
2172
- withdrawFees = {}
2173
- for i in range(0, len(result)):
2174
- entry = result[i]
2175
- currencyId = self.safe_string(entry, 'coin')
2176
- code = self.safe_currency_code(currencyId)
2177
- networkList = self.safe_value(entry, 'networkList', [])
2178
- withdrawFees[code] = {}
2179
- for j in range(0, len(networkList)):
2180
- networkEntry = networkList[j]
2181
- networkId = self.safe_string(networkEntry, 'name')
2182
- networkCode = self.safe_string(self.options['inverse-networks'], networkId, networkId)
2183
- fee = self.safe_number(networkEntry, 'withdrawFee')
2184
- if fee is not None:
2185
- withdrawFees[code][networkCode] = fee
2186
- return {
2187
- 'withdraw': withdrawFees,
2188
- 'deposit': {},
2189
- 'info': response,
2190
- }
2191
-
2192
- async def fetch_public_transaction_fees(self, params={}):
2193
- # extremely incomplete response
2194
- # vast majority fees None
2195
- await self.load_markets()
2196
- code = self.safe_string_2(params, 'coin', 'assetCode')
2197
- params = self.omit(params, ['coin', 'assetCode'])
2198
- request = {}
2199
- if code is not None:
2200
- currency = self.currency(code)
2201
- request['assetCode'] = currency['id']
2202
- response = await self.spotPublicGetWithdrawConfigs(self.extend(request, params))
2203
- #
2204
- # {
2205
- # "result": "true",
2206
- # "data": [
2207
- # {
2208
- # "amountScale": "4",
2209
- # "chain": "heco",
2210
- # "assetCode": "lbk",
2211
- # "min": "200",
2212
- # "transferAmtScale": "4",
2213
- # "canWithDraw": True,
2214
- # "fee": "100",
2215
- # "minTransfer": "0.0001",
2216
- # "type": "1"
2217
- # },
2218
- # ...
2219
- # ],
2220
- # "error_code": "0",
2221
- # "ts": "1663364435973"
2222
- # }
2223
- #
2224
- result = self.safe_value(response, 'data', [])
2225
- withdrawFees = {}
2226
- for i in range(0, len(result)):
2227
- item = result[i]
2228
- canWithdraw = self.safe_value(item, 'canWithDraw')
2229
- if canWithdraw == 'true':
2230
- currencyId = self.safe_string(item, 'assetCode')
2231
- codeInner = self.safe_currency_code(currencyId)
2232
- chain = self.safe_string(item, 'chain')
2233
- network = self.safe_string(self.options['inverse-networks'], chain, chain)
2234
- if network is None:
2235
- network = codeInner
2236
- fee = self.safe_string(item, 'fee')
2237
- if withdrawFees[codeInner] is None:
2238
- withdrawFees[codeInner] = {}
2239
- withdrawFees[codeInner][network] = self.parse_number(fee)
2240
- return {
2241
- 'withdraw': withdrawFees,
2242
- 'deposit': {},
2243
- 'info': response,
2244
- }
2245
-
2246
- async def fetch_deposit_withdraw_fees(self, codes: List[str] = None, params={}):
2247
- """
2248
- when using private endpoint, only returns information for currencies with non-zero balance, use public method by specifying self.options['fetchDepositWithdrawFees']['method'] = 'fetchPublicDepositWithdrawFees'
2249
- :see: https://www.lbank.info/en-US/docs/index.html#get-all-coins-information
2250
- :see: https://www.lbank.info/en-US/docs/index.html#withdrawal-configurations
2251
- :param str[]|None codes: array of unified currency codes
2252
- :param dict [params]: extra parameters specific to the lbank2 api endpoint
2253
- :returns dict: a list of `fee structures <https://github.com/ccxt/ccxt/wiki/Manual#fee-structure>`
2254
- """
2255
- await self.load_markets()
2256
- isAuthorized = self.check_required_credentials(False)
2257
- method = None
2258
- if isAuthorized is True:
2259
- method = self.safe_string(params, 'method')
2260
- params = self.omit(params, 'method')
2261
- if method is None:
2262
- options = self.safe_value(self.options, 'fetchDepositWithdrawFees', {})
2263
- method = self.safe_string(options, 'method', 'fetchPrivateDepositWithdrawFees')
2264
- else:
2265
- method = 'fetchPublicDepositWithdrawFees'
2266
- return await getattr(self, method)(codes, params)
2267
-
2268
- async def fetch_private_deposit_withdraw_fees(self, codes=None, params={}):
2269
- # complete response
2270
- # incl. for coins which None in public method
2271
- await self.load_markets()
2272
- response = await self.spotPrivatePostSupplementUserInfo(params)
2273
- #
2274
- # {
2275
- # "result": "true",
2276
- # "data": [
2277
- # {
2278
- # "usableAmt": "14.36",
2279
- # "assetAmt": "14.36",
2280
- # "networkList": [
2281
- # {
2282
- # "isDefault": False,
2283
- # "withdrawFeeRate": "",
2284
- # "name": "erc20",
2285
- # "withdrawMin": 30,
2286
- # "minLimit": 0.0001,
2287
- # "minDeposit": 20,
2288
- # "feeAssetCode": "usdt",
2289
- # "withdrawFee": "30",
2290
- # "type": 1,
2291
- # "coin": "usdt",
2292
- # "network": "eth"
2293
- # },
2294
- # ...
2295
- # ],
2296
- # "freezeAmt": "0",
2297
- # "coin": "ada"
2298
- # }
2299
- # ],
2300
- # "code": 0
2301
- # }
2302
- #
2303
- data = self.safe_value(response, 'data', [])
2304
- return self.parse_deposit_withdraw_fees(data, codes, 'coin')
2305
-
2306
- async def fetch_public_deposit_withdraw_fees(self, codes=None, params={}):
2307
- # extremely incomplete response
2308
- # vast majority fees None
2309
- await self.load_markets()
2310
- request = {}
2311
- response = await self.spotPublicGetWithdrawConfigs(self.extend(request, params))
2312
- #
2313
- # {
2314
- # "result": "true",
2315
- # "data": [
2316
- # {
2317
- # "amountScale": "4",
2318
- # "chain": "heco",
2319
- # "assetCode": "lbk",
2320
- # "min": "200",
2321
- # "transferAmtScale": "4",
2322
- # "canWithDraw": True,
2323
- # "fee": "100",
2324
- # "minTransfer": "0.0001",
2325
- # "type": "1"
2326
- # },
2327
- # ...
2328
- # ],
2329
- # "error_code": "0",
2330
- # "ts": "1663364435973"
2331
- # }
2332
- #
2333
- data = self.safe_value(response, 'data', [])
2334
- return self.parse_public_deposit_withdraw_fees(data, codes)
2335
-
2336
- def parse_public_deposit_withdraw_fees(self, response, codes=None):
2337
- #
2338
- # [
2339
- # {
2340
- # "amountScale": "4",
2341
- # "chain": "heco",
2342
- # "assetCode": "lbk",
2343
- # "min": "200",
2344
- # "transferAmtScale": "4",
2345
- # "canWithDraw": True,
2346
- # "fee": "100",
2347
- # "minTransfer": "0.0001",
2348
- # "type": "1"
2349
- # },
2350
- # ...
2351
- # ]
2352
- #
2353
- result = {}
2354
- for i in range(0, len(response)):
2355
- fee = response[i]
2356
- canWithdraw = self.safe_value(fee, 'canWithDraw')
2357
- if canWithdraw is True:
2358
- currencyId = self.safe_string(fee, 'assetCode')
2359
- code = self.safe_currency_code(currencyId)
2360
- if codes is None or self.in_array(code, codes):
2361
- withdrawFee = self.safe_number(fee, 'fee')
2362
- if withdrawFee is not None:
2363
- resultValue = self.safe_value(result, code)
2364
- if resultValue is None:
2365
- result[code] = self.deposit_withdraw_fee([fee])
2366
- else:
2367
- result[code]['info'].append(fee)
2368
- chain = self.safe_string(fee, 'chain')
2369
- networkCode = self.safe_string(self.options['inverse-networks'], chain, chain)
2370
- if networkCode is not None:
2371
- result[code]['networks'][networkCode] = {
2372
- 'withdraw': {
2373
- 'fee': withdrawFee,
2374
- 'percentage': None,
2375
- },
2376
- 'deposit': {
2377
- 'fee': None,
2378
- 'percentage': None,
2379
- },
2380
- }
2381
- else:
2382
- result[code]['withdraw'] = {
2383
- 'fee': withdrawFee,
2384
- 'percentage': None,
2385
- }
2386
- return result
2387
-
2388
- def parse_deposit_withdraw_fee(self, fee, currency=None):
2389
- #
2390
- # * only used for fetchPrivateDepositWithdrawFees
2391
- #
2392
- # {
2393
- # "usableAmt": "14.36",
2394
- # "assetAmt": "14.36",
2395
- # "networkList": [
2396
- # {
2397
- # "isDefault": False,
2398
- # "withdrawFeeRate": "",
2399
- # "name": "erc20",
2400
- # "withdrawMin": 30,
2401
- # "minLimit": 0.0001,
2402
- # "minDeposit": 20,
2403
- # "feeAssetCode": "usdt",
2404
- # "withdrawFee": "30",
2405
- # "type": 1,
2406
- # "coin": "usdt",
2407
- # "network": "eth"
2408
- # },
2409
- # ...
2410
- # ],
2411
- # "freezeAmt": "0",
2412
- # "coin": "ada"
2413
- # }
2414
- #
2415
- result = self.deposit_withdraw_fee(fee)
2416
- networkList = self.safe_value(fee, 'networkList', [])
2417
- for j in range(0, len(networkList)):
2418
- networkEntry = networkList[j]
2419
- networkId = self.safe_string(networkEntry, 'name')
2420
- networkCode = self.safe_string_upper(self.options['inverse-networks'], networkId, networkId)
2421
- withdrawFee = self.safe_number(networkEntry, 'withdrawFee')
2422
- isDefault = self.safe_value(networkEntry, 'isDefault')
2423
- if withdrawFee is not None:
2424
- if isDefault:
2425
- result['withdraw'] = {
2426
- 'fee': withdrawFee,
2427
- 'percentage': None,
2428
- }
2429
- result['networks'][networkCode] = {
2430
- 'withdraw': {
2431
- 'fee': withdrawFee,
2432
- 'percentage': None,
2433
- },
2434
- 'deposit': {
2435
- 'fee': None,
2436
- 'percentage': None,
2437
- },
2438
- }
2439
- return result
2440
-
2441
- def sign(self, path, api='public', method='GET', params={}, headers=None, body=None):
2442
- query = self.omit(params, self.extract_params(path))
2443
- url = self.urls['api']['rest'] + '/' + self.version + '/' + self.implode_params(path, params)
2444
- # Every spot endpoint ends with ".do"
2445
- if api[0] == 'spot':
2446
- url += '.do'
2447
- else:
2448
- url = self.urls['api']['contract'] + '/' + self.implode_params(path, params)
2449
- if api[1] == 'public':
2450
- if query:
2451
- url += '?' + self.urlencode(self.keysort(query))
2452
- else:
2453
- self.check_required_credentials()
2454
- timestamp = str(self.milliseconds())
2455
- echostr = self.uuid22() + self.uuid16()
2456
- query = self.extend({
2457
- 'api_key': self.apiKey,
2458
- }, query)
2459
- signatureMethod = None
2460
- if len(self.secret) > 32:
2461
- signatureMethod = 'RSA'
2462
- else:
2463
- signatureMethod = 'HmacSHA256'
2464
- auth = self.rawencode(self.keysort(self.extend({
2465
- 'echostr': echostr,
2466
- 'signature_method': signatureMethod,
2467
- 'timestamp': timestamp,
2468
- }, query)))
2469
- encoded = self.encode(auth)
2470
- hash = self.hash(encoded, 'md5')
2471
- uppercaseHash = hash.upper()
2472
- sign = None
2473
- if signatureMethod == 'RSA':
2474
- cacheSecretAsPem = self.safe_value(self.options, 'cacheSecretAsPem', True)
2475
- pem = None
2476
- if cacheSecretAsPem:
2477
- pem = self.safe_value(self.options, 'pem')
2478
- if pem is None:
2479
- pem = self.convert_secret_to_pem(self.encode(self.secret))
2480
- self.options['pem'] = pem
2481
- else:
2482
- pem = self.convert_secret_to_pem(self.encode(self.secret))
2483
- sign = self.rsa(uppercaseHash, pem, 'sha256')
2484
- elif signatureMethod == 'HmacSHA256':
2485
- sign = self.hmac(self.encode(uppercaseHash), self.encode(self.secret), hashlib.sha256)
2486
- query['sign'] = sign
2487
- body = self.urlencode(self.keysort(query))
2488
- headers = {
2489
- 'Content-Type': 'application/x-www-form-urlencoded',
2490
- 'timestamp': timestamp,
2491
- 'signature_method': signatureMethod,
2492
- 'echostr': echostr,
2493
- }
2494
- return {'url': url, 'method': method, 'body': body, 'headers': headers}
2495
-
2496
- def convert_secret_to_pem(self, secret):
2497
- lineLength = 64
2498
- secretLength = len(secret) - 0
2499
- numLines = self.parse_to_int(secretLength / lineLength)
2500
- numLines = self.sum(numLines, 1)
2501
- pem = "-----BEGIN PRIVATE KEY-----\n" # eslint-disable-line
2502
- for i in range(0, numLines):
2503
- start = i * lineLength
2504
- end = self.sum(start, lineLength)
2505
- pem += self.secret[start:end] + "\n" # eslint-disable-line
2506
- return pem + '-----END PRIVATE KEY-----'
2507
-
2508
- def handle_errors(self, httpCode, reason, url, method, headers, body, response, requestHeaders, requestBody):
2509
- if response is None:
2510
- return None
2511
- success = self.safe_value(response, 'result')
2512
- if success == 'false' or not success:
2513
- errorCode = self.safe_string(response, 'error_code')
2514
- message = self.safe_string({
2515
- '10000': 'Internal error',
2516
- '10001': 'The required parameters can not be empty',
2517
- '10002': 'Validation failed',
2518
- '10003': 'Invalid parameter',
2519
- '10004': 'Request too frequent',
2520
- '10005': 'Secret key does not exist',
2521
- '10006': 'User does not exist',
2522
- '10007': 'Invalid signature',
2523
- '10008': 'Invalid Trading Pair',
2524
- '10009': 'Price and/or Amount are required for limit order',
2525
- '10010': 'Price and/or Amount must be less than minimum requirement',
2526
- # '10011': 'Market orders can not be missing the amount of the order',
2527
- # '10012': 'market sell orders can not be missing orders',
2528
- '10013': 'The amount is too small',
2529
- '10014': 'Insufficient amount of money in the account',
2530
- '10015': 'Invalid order type',
2531
- '10016': 'Insufficient account balance',
2532
- '10017': 'Server Error',
2533
- '10018': 'Page size should be between 1 and 50',
2534
- '10019': 'Cancel NO more than 3 orders in one request',
2535
- '10020': 'Volume < 0.001',
2536
- '10021': 'Price < 0.01',
2537
- '10022': 'Invalid authorization',
2538
- '10023': 'Market Order is not supported yet',
2539
- '10024': 'User cannot trade on self pair',
2540
- '10025': 'Order has been filled',
2541
- '10026': 'Order has been cancelld',
2542
- '10027': 'Order is cancelling',
2543
- '10028': 'Wrong query time',
2544
- '10029': 'from is not in the query time',
2545
- '10030': 'from do not match the transaction type of inqury',
2546
- '10031': 'echostr length must be valid and length must be from 30 to 40',
2547
- '10033': 'Failed to create order',
2548
- '10036': 'customID duplicated',
2549
- '10100': 'Has no privilege to withdraw',
2550
- '10101': 'Invalid fee rate to withdraw',
2551
- '10102': 'Too little to withdraw',
2552
- '10103': 'Exceed daily limitation of withdraw',
2553
- '10104': 'Cancel was rejected',
2554
- '10105': 'Request has been cancelled',
2555
- '10106': 'None trade time',
2556
- '10107': 'Start price exception',
2557
- '10108': 'can not create order',
2558
- '10109': 'wallet address is not mapping',
2559
- '10110': 'transfer fee is not mapping',
2560
- '10111': 'mount > 0',
2561
- '10112': 'fee is too lower',
2562
- '10113': 'transfer fee is 0',
2563
- '10600': 'intercepted by replay attacks filter, check timestamp',
2564
- '10601': 'Interface closed unavailable',
2565
- '10701': 'invalid asset code',
2566
- '10702': 'not allowed deposit',
2567
- }, errorCode, self.json(response))
2568
- ErrorClass = self.safe_value({
2569
- '10001': BadRequest,
2570
- '10002': AuthenticationError,
2571
- '10003': BadRequest,
2572
- '10004': RateLimitExceeded,
2573
- '10005': AuthenticationError,
2574
- '10006': AuthenticationError,
2575
- '10007': AuthenticationError,
2576
- '10008': BadSymbol,
2577
- '10009': InvalidOrder,
2578
- '10010': InvalidOrder,
2579
- '10013': InvalidOrder,
2580
- '10014': InsufficientFunds,
2581
- '10015': InvalidOrder,
2582
- '10016': InsufficientFunds,
2583
- '10017': ExchangeError,
2584
- '10018': BadRequest,
2585
- '10019': BadRequest,
2586
- '10020': BadRequest,
2587
- '10021': InvalidOrder,
2588
- '10022': PermissionDenied, # 'Invalid authorization',
2589
- '10023': InvalidOrder, # 'Market Order is not supported yet',
2590
- '10024': PermissionDenied, # 'User cannot trade on self pair',
2591
- '10025': InvalidOrder, # 'Order has been filled',
2592
- '10026': InvalidOrder, # 'Order has been cancelled',
2593
- '10027': InvalidOrder, # 'Order is cancelling',
2594
- '10028': BadRequest, # 'Wrong query time',
2595
- '10029': BadRequest, # 'from is not in the query time',
2596
- '10030': BadRequest, # 'from do not match the transaction type of inqury',
2597
- '10031': InvalidNonce, # 'echostr length must be valid and length must be from 30 to 40',
2598
- '10033': ExchangeError, # 'Failed to create order',
2599
- '10036': DuplicateOrderId, # 'customID duplicated',
2600
- '10100': PermissionDenied, # 'Has no privilege to withdraw',
2601
- '10101': BadRequest, # 'Invalid fee rate to withdraw',
2602
- '10102': InsufficientFunds, # 'Too little to withdraw',
2603
- '10103': ExchangeError, # 'Exceed daily limitation of withdraw',
2604
- '10104': ExchangeError, # 'Cancel was rejected',
2605
- '10105': ExchangeError, # 'Request has been cancelled',
2606
- '10106': BadRequest, # 'None trade time',
2607
- '10107': BadRequest, # 'Start price exception',
2608
- '10108': ExchangeError, # 'can not create order',
2609
- '10109': InvalidAddress, # 'wallet address is not mapping',
2610
- '10110': ExchangeError, # 'transfer fee is not mapping',
2611
- '10111': BadRequest, # 'mount > 0',
2612
- '10112': BadRequest, # 'fee is too lower',
2613
- '10113': BadRequest, # 'transfer fee is 0',
2614
- '10600': BadRequest, # 'intercepted by replay attacks filter, check timestamp',
2615
- '10601': ExchangeError, # 'Interface closed unavailable',
2616
- '10701': BadSymbol, # 'invalid asset code',
2617
- '10702': PermissionDenied, # 'not allowed deposit',
2618
- }, errorCode, ExchangeError)
2619
- raise ErrorClass(message)
2620
- return None