ccxt 3.1.53__py2.py3-none-any.whl → 3.1.54__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.
- ccxt/__init__.py +1 -1
- ccxt/abstract/bybit.py +1 -0
- ccxt/abstract/okex.py +1 -0
- ccxt/abstract/okex5.py +1 -0
- ccxt/abstract/okx.py +1 -0
- ccxt/async_support/__init__.py +1 -1
- ccxt/async_support/base/exchange.py +3 -3
- ccxt/async_support/bitmex.py +447 -399
- ccxt/async_support/bybit.py +1 -0
- ccxt/async_support/cryptocom.py +83 -0
- ccxt/async_support/luno.py +1 -1
- ccxt/async_support/okx.py +1 -0
- ccxt/base/exchange.py +3 -3
- ccxt/bitmex.py +447 -399
- ccxt/bybit.py +1 -0
- ccxt/cryptocom.py +83 -0
- ccxt/luno.py +1 -1
- ccxt/okx.py +1 -0
- ccxt/pro/__init__.py +1 -1
- {ccxt-3.1.53.dist-info → ccxt-3.1.54.dist-info}/METADATA +4 -4
- {ccxt-3.1.53.dist-info → ccxt-3.1.54.dist-info}/RECORD +23 -23
- {ccxt-3.1.53.dist-info → ccxt-3.1.54.dist-info}/WHEEL +0 -0
- {ccxt-3.1.53.dist-info → ccxt-3.1.54.dist-info}/top_level.txt +0 -0
ccxt/async_support/bitmex.py
CHANGED
@@ -57,10 +57,13 @@ class bitmex(Exchange, ImplicitAPI):
|
|
57
57
|
'editOrder': True,
|
58
58
|
'fetchBalance': True,
|
59
59
|
'fetchClosedOrders': True,
|
60
|
+
'fetchCurrencies': True,
|
60
61
|
'fetchDepositAddress': True,
|
61
62
|
'fetchDepositAddresses': False,
|
62
63
|
'fetchDepositAddressesByNetwork': False,
|
63
64
|
'fetchDepositsWithdrawals': 'emulated',
|
65
|
+
'fetchDepositWithdrawalFee': 'emulated',
|
66
|
+
'fetchDepositWithdrawalFees': True,
|
64
67
|
'fetchFundingHistory': False,
|
65
68
|
'fetchFundingRate': False,
|
66
69
|
'fetchFundingRateHistory': True,
|
@@ -235,32 +238,37 @@ class bitmex(Exchange, ImplicitAPI):
|
|
235
238
|
# https://github.com/ccxt/ccxt/issues/4789
|
236
239
|
'api-expires': 5, # in seconds
|
237
240
|
'fetchOHLCVOpenTimestamp': True,
|
241
|
+
'oldPrecision': False,
|
238
242
|
'networks': {
|
239
243
|
'BTC': 'btc',
|
240
244
|
'ETH': 'eth',
|
241
|
-
'BSC': 'bsc',
|
242
|
-
'BNB': 'bsc',
|
243
|
-
'TRON': 'tron',
|
244
245
|
'ERC20': 'eth',
|
245
246
|
'BEP20': 'bsc',
|
247
|
+
'BSC': 'bsc',
|
246
248
|
'TRC20': 'tron',
|
249
|
+
'TRON': 'tron',
|
247
250
|
'TRX': 'tron',
|
248
|
-
'
|
251
|
+
'AVALANCHEC': 'avax',
|
249
252
|
'NEAR': 'near',
|
253
|
+
'TEZOS': 'xtz',
|
250
254
|
'XTZ': 'xtz',
|
255
|
+
'POLKADOT': 'dot',
|
251
256
|
'DOT': 'dot',
|
257
|
+
'SOLANA': 'sol',
|
252
258
|
'SOL': 'sol',
|
259
|
+
'CARDANO': 'ada',
|
253
260
|
},
|
254
261
|
'networksById': {
|
255
262
|
'btc': 'BTC',
|
256
263
|
'eth': 'ERC20',
|
257
|
-
'bsc': '
|
258
|
-
'tron': '
|
259
|
-
'avax': '
|
264
|
+
'bsc': 'BEP20',
|
265
|
+
'tron': 'TRC20',
|
266
|
+
'avax': 'AVALANCHEC',
|
260
267
|
'near': 'NEAR',
|
261
|
-
'xtz': '
|
262
|
-
'dot': '
|
263
|
-
'sol': '
|
268
|
+
'xtz': 'TEZOS',
|
269
|
+
'dot': 'POLKADOT',
|
270
|
+
'sol': 'SOLANA',
|
271
|
+
'ada': 'CARDANO',
|
264
272
|
},
|
265
273
|
},
|
266
274
|
'commonCurrencies': {
|
@@ -274,6 +282,166 @@ class bitmex(Exchange, ImplicitAPI):
|
|
274
282
|
},
|
275
283
|
})
|
276
284
|
|
285
|
+
async def fetch_currencies(self, params={}):
|
286
|
+
"""
|
287
|
+
fetches all available currencies on an exchange
|
288
|
+
:param dict params: extra parameters specific to the mexc3 api endpoint
|
289
|
+
:returns dict: an associative dictionary of currencies
|
290
|
+
"""
|
291
|
+
response = await self.publicGetWalletAssets(params)
|
292
|
+
#
|
293
|
+
# {
|
294
|
+
# "XBt": {
|
295
|
+
# "asset": "XBT",
|
296
|
+
# "currency": "XBt",
|
297
|
+
# "majorCurrency": "XBT",
|
298
|
+
# "name": "Bitcoin",
|
299
|
+
# "currencyType": "Crypto",
|
300
|
+
# "scale": "8",
|
301
|
+
# # "mediumPrecision": "8",
|
302
|
+
# # "shorterPrecision": "4",
|
303
|
+
# # "symbol": "₿",
|
304
|
+
# # "weight": "1",
|
305
|
+
# # "tickLog": "0",
|
306
|
+
# "enabled": True,
|
307
|
+
# "isMarginCurrency": True,
|
308
|
+
# "minDepositAmount": "10000",
|
309
|
+
# "minWithdrawalAmount": "1000",
|
310
|
+
# "maxWithdrawalAmount": "100000000000000",
|
311
|
+
# "networks": [
|
312
|
+
# {
|
313
|
+
# "asset": "btc",
|
314
|
+
# "tokenAddress": "",
|
315
|
+
# "depositEnabled": True,
|
316
|
+
# "withdrawalEnabled": True,
|
317
|
+
# "withdrawalFee": "20000",
|
318
|
+
# "minFee": "20000",
|
319
|
+
# "maxFee": "10000000"
|
320
|
+
# }
|
321
|
+
# ]
|
322
|
+
# },
|
323
|
+
# }
|
324
|
+
#
|
325
|
+
result = {}
|
326
|
+
for i in range(0, len(response)):
|
327
|
+
currency = response[i]
|
328
|
+
asset = self.safe_string(currency, 'asset')
|
329
|
+
code = self.safe_currency_code(asset)
|
330
|
+
id = self.safe_string(currency, 'currency')
|
331
|
+
name = self.safe_string(currency, 'name')
|
332
|
+
chains = self.safe_value(currency, 'networks', [])
|
333
|
+
depositEnabled = False
|
334
|
+
withdrawEnabled = False
|
335
|
+
networks = {}
|
336
|
+
scale = self.safe_string(currency, 'scale')
|
337
|
+
precisionString = self.parse_precision(scale)
|
338
|
+
precision = self.parse_number(precisionString)
|
339
|
+
for j in range(0, len(chains)):
|
340
|
+
chain = chains[j]
|
341
|
+
networkId = self.safe_string(chain, 'asset')
|
342
|
+
network = self.network_id_to_code(networkId)
|
343
|
+
withdrawalFeeRaw = self.safe_string(chain, 'withdrawalFee')
|
344
|
+
withdrawalFee = self.parse_number(Precise.string_mul(withdrawalFeeRaw, precisionString))
|
345
|
+
isDepositEnabled = self.safe_value(chain, 'depositEnabled', False)
|
346
|
+
isWithdrawEnabled = self.safe_value(chain, 'withdrawalEnabled', False)
|
347
|
+
active = (isDepositEnabled and isWithdrawEnabled)
|
348
|
+
if isDepositEnabled:
|
349
|
+
depositEnabled = True
|
350
|
+
if isWithdrawEnabled:
|
351
|
+
withdrawEnabled = True
|
352
|
+
networks[network] = {
|
353
|
+
'info': chain,
|
354
|
+
'id': networkId,
|
355
|
+
'network': network,
|
356
|
+
'active': active,
|
357
|
+
'deposit': isDepositEnabled,
|
358
|
+
'withdraw': isWithdrawEnabled,
|
359
|
+
'fee': withdrawalFee,
|
360
|
+
'precision': None,
|
361
|
+
'limits': {
|
362
|
+
'withdraw': {
|
363
|
+
'min': None,
|
364
|
+
'max': None,
|
365
|
+
},
|
366
|
+
'deposit': {
|
367
|
+
'min': None,
|
368
|
+
'max': None,
|
369
|
+
},
|
370
|
+
},
|
371
|
+
}
|
372
|
+
currencyEnabled = self.safe_value(currency, 'enabled')
|
373
|
+
currencyActive = currencyEnabled or (depositEnabled or withdrawEnabled)
|
374
|
+
minWithdrawalString = self.safe_string(currency, 'minWithdrawalAmount')
|
375
|
+
minWithdrawal = self.parse_number(Precise.string_mul(minWithdrawalString, precisionString))
|
376
|
+
maxWithdrawalString = self.safe_string(currency, 'maxWithdrawalAmount')
|
377
|
+
maxWithdrawal = self.parse_number(Precise.string_mul(maxWithdrawalString, precisionString))
|
378
|
+
minDepositString = self.safe_string(currency, 'minDepositAmount')
|
379
|
+
minDeposit = self.parse_number(Precise.string_mul(minDepositString, precisionString))
|
380
|
+
result[code] = {
|
381
|
+
'id': id,
|
382
|
+
'code': code,
|
383
|
+
'info': currency,
|
384
|
+
'name': name,
|
385
|
+
'active': currencyActive,
|
386
|
+
'deposit': depositEnabled,
|
387
|
+
'withdraw': withdrawEnabled,
|
388
|
+
'fee': None,
|
389
|
+
'precision': precision,
|
390
|
+
'limits': {
|
391
|
+
'amount': {
|
392
|
+
'min': None,
|
393
|
+
'max': None,
|
394
|
+
},
|
395
|
+
'withdraw': {
|
396
|
+
'min': minWithdrawal,
|
397
|
+
'max': maxWithdrawal,
|
398
|
+
},
|
399
|
+
'deposit': {
|
400
|
+
'min': minDeposit,
|
401
|
+
'max': None,
|
402
|
+
},
|
403
|
+
},
|
404
|
+
'networks': networks,
|
405
|
+
}
|
406
|
+
return result
|
407
|
+
|
408
|
+
def convert_from_real_amount(self, code, amount):
|
409
|
+
currency = self.currency(code)
|
410
|
+
precision = self.safe_string(currency, 'precision')
|
411
|
+
amountString = self.number_to_string(amount)
|
412
|
+
finalAmount = Precise.string_div(amountString, precision)
|
413
|
+
return self.parse_number(finalAmount)
|
414
|
+
|
415
|
+
def convert_to_real_amount(self, code, amount):
|
416
|
+
currency = self.currency(code)
|
417
|
+
precision = self.safe_string(currency, 'precision')
|
418
|
+
amountString = self.number_to_string(amount)
|
419
|
+
finalAmount = Precise.string_mul(amountString, precision)
|
420
|
+
return self.parse_number(finalAmount)
|
421
|
+
|
422
|
+
def amount_to_precision(self, symbol, amount):
|
423
|
+
symbol = self.safe_symbol(symbol)
|
424
|
+
market = self.market(symbol)
|
425
|
+
oldPrecision = self.safe_value(self.options, 'oldPrecision')
|
426
|
+
if market['spot'] and not oldPrecision:
|
427
|
+
amount = self.convert_from_real_amount(market['base'], amount)
|
428
|
+
return super(bitmex, self).amount_to_precision(symbol, amount)
|
429
|
+
|
430
|
+
def convert_from_raw_quantity(self, symbol, rawQuantity, currencySide='base'):
|
431
|
+
if self.safe_value(self.options, 'oldPrecision'):
|
432
|
+
return self.parse_number(rawQuantity)
|
433
|
+
symbol = self.safe_symbol(symbol)
|
434
|
+
marketExists = self.in_array(symbol, self.symbols)
|
435
|
+
if not marketExists:
|
436
|
+
return self.parse_number(rawQuantity)
|
437
|
+
market = self.market(symbol)
|
438
|
+
if market['spot']:
|
439
|
+
return self.convert_to_real_amount(market[currencySide], rawQuantity)
|
440
|
+
return self.parse_number(rawQuantity)
|
441
|
+
|
442
|
+
def convert_from_raw_cost(self, symbol, rawQuantity):
|
443
|
+
return self.convert_from_raw_quantity(symbol, rawQuantity, 'quote')
|
444
|
+
|
277
445
|
async def fetch_markets(self, params={}):
|
278
446
|
"""
|
279
447
|
retrieves data on all markets for bitmex
|
@@ -404,102 +572,109 @@ class bitmex(Exchange, ImplicitAPI):
|
|
404
572
|
settle = self.safe_currency_code(settleId)
|
405
573
|
# 'positionCurrency' may be empty("", currently returns for ETHUSD)
|
406
574
|
# so let's take the settlCurrency first and then adjust if needed
|
407
|
-
typ = self.safe_string(market, 'typ')
|
408
|
-
# Perpetual Contracts - FFWCSX
|
409
|
-
# Perpetual Contracts(FX underliers) - FFWCSF
|
410
|
-
# Spot - IFXXXP
|
411
|
-
# Futures - FFCCSX
|
412
|
-
# BitMEX Basket Index - MRBXXX
|
413
|
-
# BitMEX Crypto Index - MRCXXX
|
414
|
-
# BitMEX FX Index - MRFXXX
|
415
|
-
# BitMEX Lending/Premium Index - MRRXXX
|
416
|
-
# BitMEX Volatility Index - MRIXXX
|
575
|
+
typ = self.safe_string(market, 'typ') # type definitions at: https://www.bitmex.com/api/explorer/#not /Instrument/Instrument_get
|
417
576
|
types = {
|
418
577
|
'FFWCSX': 'swap',
|
419
578
|
'FFWCSF': 'swap',
|
420
579
|
'IFXXXP': 'spot',
|
421
580
|
'FFCCSX': 'future',
|
581
|
+
'MRBXXX': 'index',
|
582
|
+
'MRCXXX': 'index',
|
583
|
+
'MRFXXX': 'index',
|
584
|
+
'MRRXXX': 'index',
|
585
|
+
'MRIXXX': 'index',
|
422
586
|
}
|
423
587
|
type = self.safe_string(types, typ, typ)
|
424
588
|
swap = type == 'swap'
|
425
589
|
future = type == 'future'
|
426
590
|
spot = type == 'spot'
|
427
591
|
contract = swap or future
|
428
|
-
symbol = base + '/' + quote
|
429
592
|
contractSize = None
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
inverse = self.safe_value(market, 'isInverse')
|
593
|
+
index = type == 'index'
|
594
|
+
isInverse = self.safe_value(market, 'isInverse') # self is True when BASE and SETTLE are same, i.e. BTC/XXX:BTC
|
595
|
+
isQuanto = self.safe_value(market, 'isQuanto') # self is True when BASE and SETTLE are different, i.e. AXS/XXX:BTC
|
596
|
+
linear = (not isInverse and not isQuanto) if contract else None
|
435
597
|
status = self.safe_string(market, 'state')
|
436
598
|
active = status != 'Unlisted'
|
437
599
|
expiry = None
|
438
600
|
expiryDatetime = None
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
601
|
+
symbol = None
|
602
|
+
if spot:
|
603
|
+
symbol = base + '/' + quote
|
604
|
+
elif contract:
|
605
|
+
symbol = base + '/' + quote + ':' + settle
|
606
|
+
multiplierString = Precise.string_abs(self.safe_string(market, 'multiplier'))
|
607
|
+
if linear:
|
608
|
+
contractSize = self.parse_number(Precise.string_div('1', market['underlyingToPositionMultiplier']))
|
609
|
+
else:
|
610
|
+
contractSize = self.parse_number(multiplierString)
|
611
|
+
if future:
|
612
|
+
expiryDatetime = self.safe_string(market, 'expiry')
|
613
|
+
expiry = self.parse8601(expiryDatetime)
|
614
|
+
symbol = symbol + '-' + self.yymmdd(expiry)
|
615
|
+
else:
|
616
|
+
# for index/exotic markets, default to id
|
617
|
+
symbol = id
|
443
618
|
positionId = self.safe_string_2(market, 'positionCurrency', 'underlying')
|
444
619
|
position = self.safe_currency_code(positionId)
|
445
620
|
positionIsQuote = (position == quote)
|
446
621
|
maxOrderQty = self.safe_number(market, 'maxOrderQty')
|
447
622
|
initMargin = self.safe_string(market, 'initMargin', '1')
|
448
623
|
maxLeverage = self.parse_number(Precise.string_div('1', initMargin))
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
624
|
+
result.append({
|
625
|
+
'id': id,
|
626
|
+
'symbol': symbol,
|
627
|
+
'base': base,
|
628
|
+
'quote': quote,
|
629
|
+
'settle': settle,
|
630
|
+
'baseId': baseId,
|
631
|
+
'quoteId': quoteId,
|
632
|
+
'settleId': settleId,
|
633
|
+
'type': type,
|
634
|
+
'spot': spot,
|
635
|
+
'margin': False,
|
636
|
+
'swap': swap,
|
637
|
+
'future': future,
|
638
|
+
'option': False,
|
639
|
+
'index': index,
|
640
|
+
'active': active,
|
641
|
+
'contract': contract,
|
642
|
+
'linear': linear,
|
643
|
+
'inverse': isInverse,
|
644
|
+
'quanto': isQuanto,
|
645
|
+
'taker': self.safe_number(market, 'takerFee'),
|
646
|
+
'maker': self.safe_number(market, 'makerFee'),
|
647
|
+
'contractSize': contractSize,
|
648
|
+
'expiry': expiry,
|
649
|
+
'expiryDatetime': expiryDatetime,
|
650
|
+
'strike': self.safe_number(market, 'optionStrikePrice'),
|
651
|
+
'optionType': None,
|
652
|
+
'precision': {
|
653
|
+
'amount': self.safe_number(market, 'lotSize'),
|
654
|
+
'price': self.safe_number(market, 'tickSize'),
|
655
|
+
'quote': self.safe_number(market, 'tickSize'),
|
656
|
+
'base': self.safe_number(market, 'tickSize'),
|
657
|
+
},
|
658
|
+
'limits': {
|
659
|
+
'leverage': {
|
660
|
+
'min': self.parse_number('1') if contract else None,
|
661
|
+
'max': maxLeverage if contract else None,
|
482
662
|
},
|
483
|
-
'
|
484
|
-
'
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
'
|
489
|
-
|
490
|
-
'max': None if positionIsQuote else maxOrderQty,
|
491
|
-
},
|
492
|
-
'price': {
|
493
|
-
'min': None,
|
494
|
-
'max': self.safe_number(market, 'maxPrice'),
|
495
|
-
},
|
496
|
-
'cost': {
|
497
|
-
'min': None,
|
498
|
-
'max': maxOrderQty if positionIsQuote else None,
|
499
|
-
},
|
663
|
+
'amount': {
|
664
|
+
'min': None,
|
665
|
+
'max': None if positionIsQuote else maxOrderQty,
|
666
|
+
},
|
667
|
+
'price': {
|
668
|
+
'min': None,
|
669
|
+
'max': self.safe_number(market, 'maxPrice'),
|
500
670
|
},
|
501
|
-
'
|
502
|
-
|
671
|
+
'cost': {
|
672
|
+
'min': None,
|
673
|
+
'max': maxOrderQty if positionIsQuote else None,
|
674
|
+
},
|
675
|
+
},
|
676
|
+
'info': market,
|
677
|
+
})
|
503
678
|
return result
|
504
679
|
|
505
680
|
def parse_balance(self, response):
|
@@ -558,24 +733,8 @@ class bitmex(Exchange, ImplicitAPI):
|
|
558
733
|
account = self.account()
|
559
734
|
free = self.safe_string(balance, 'availableMargin')
|
560
735
|
total = self.safe_string(balance, 'marginBalance')
|
561
|
-
|
562
|
-
|
563
|
-
# https://github.com/ccxt/ccxt/pull/15311
|
564
|
-
symbol = code + '_USDT'
|
565
|
-
market = self.safe_market(symbol)
|
566
|
-
info = self.safe_value(market, 'info', {})
|
567
|
-
multiplier = self.safe_string(info, 'underlyingToPositionMultiplier')
|
568
|
-
if multiplier is not None:
|
569
|
-
free = Precise.string_div(free, multiplier)
|
570
|
-
total = Precise.string_div(total, multiplier)
|
571
|
-
else:
|
572
|
-
free = Precise.string_div(free, '1e8')
|
573
|
-
total = Precise.string_div(total, '1e8')
|
574
|
-
else:
|
575
|
-
free = Precise.string_div(free, '1e6')
|
576
|
-
total = Precise.string_div(total, '1e6')
|
577
|
-
account['free'] = free
|
578
|
-
account['total'] = total
|
736
|
+
account['free'] = self.convert_to_real_amount(code, free)
|
737
|
+
account['total'] = self.convert_to_real_amount(code, total)
|
579
738
|
result[code] = account
|
580
739
|
return self.safe_balance(result)
|
581
740
|
|
@@ -666,7 +825,7 @@ class bitmex(Exchange, ImplicitAPI):
|
|
666
825
|
for i in range(0, len(response)):
|
667
826
|
order = response[i]
|
668
827
|
side = 'asks' if (order['side'] == 'Sell') else 'bids'
|
669
|
-
amount = self.
|
828
|
+
amount = self.convert_from_raw_quantity(symbol, self.safe_string(order, 'size'))
|
670
829
|
price = self.safe_number(order, 'price')
|
671
830
|
# https://github.com/ccxt/ccxt/issues/4926
|
672
831
|
# https://github.com/ccxt/ccxt/issues/4927
|
@@ -893,9 +1052,8 @@ class bitmex(Exchange, ImplicitAPI):
|
|
893
1052
|
type = self.parse_ledger_entry_type(self.safe_string(item, 'transactType'))
|
894
1053
|
currencyId = self.safe_string(item, 'currency')
|
895
1054
|
code = self.safe_currency_code(currencyId, currency)
|
896
|
-
|
897
|
-
|
898
|
-
amount = amount / 100000000
|
1055
|
+
amountString = self.safe_string(item, 'amount')
|
1056
|
+
amount = self.convert_to_real_amount(code, amountString)
|
899
1057
|
timestamp = self.parse8601(self.safe_string(item, 'transactTime'))
|
900
1058
|
if timestamp is None:
|
901
1059
|
# https://github.com/ccxt/ccxt/issues/6047
|
@@ -904,19 +1062,19 @@ class bitmex(Exchange, ImplicitAPI):
|
|
904
1062
|
timestamp = 0 # see comments above
|
905
1063
|
feeCost = self.safe_number(item, 'fee', 0)
|
906
1064
|
if feeCost is not None:
|
907
|
-
feeCost = feeCost
|
1065
|
+
feeCost = self.convert_to_real_amount(code, feeCost)
|
908
1066
|
fee = {
|
909
1067
|
'cost': feeCost,
|
910
1068
|
'currency': code,
|
911
1069
|
}
|
912
1070
|
after = self.safe_number(item, 'walletBalance')
|
913
1071
|
if after is not None:
|
914
|
-
after = after
|
915
|
-
before = self.
|
1072
|
+
after = self.convert_to_real_amount(code, after)
|
1073
|
+
before = self.parse_number(Precise.string_sub(self.number_to_string(after), self.number_to_string(amount)))
|
916
1074
|
direction = None
|
917
|
-
if
|
1075
|
+
if Precise.string_lt(amountString, '0'):
|
918
1076
|
direction = 'out'
|
919
|
-
amount =
|
1077
|
+
amount = self.convert_to_real_amount(code, Precise.string_abs(amountString))
|
920
1078
|
else:
|
921
1079
|
direction = 'in'
|
922
1080
|
status = self.parse_transaction_status(self.safe_string(item, 'transactStatus'))
|
@@ -948,9 +1106,6 @@ class bitmex(Exchange, ImplicitAPI):
|
|
948
1106
|
:returns dict: a `ledger structure <https://docs.ccxt.com/#/?id=ledger-structure>`
|
949
1107
|
"""
|
950
1108
|
await self.load_markets()
|
951
|
-
currency = None
|
952
|
-
if code is not None:
|
953
|
-
currency = self.currency(code)
|
954
1109
|
request = {
|
955
1110
|
# 'start': 123,
|
956
1111
|
}
|
@@ -961,6 +1116,10 @@ class bitmex(Exchange, ImplicitAPI):
|
|
961
1116
|
#
|
962
1117
|
if limit is not None:
|
963
1118
|
request['count'] = limit
|
1119
|
+
currency = None
|
1120
|
+
if code is not None:
|
1121
|
+
currency = self.currency(code)
|
1122
|
+
request['currency'] = currency['id']
|
964
1123
|
response = await self.privateGetUserWalletHistory(self.extend(request, params))
|
965
1124
|
#
|
966
1125
|
# [
|
@@ -1003,13 +1162,14 @@ class bitmex(Exchange, ImplicitAPI):
|
|
1003
1162
|
# # date-based pagination not supported
|
1004
1163
|
# }
|
1005
1164
|
#
|
1165
|
+
currency = None
|
1166
|
+
if code is not None:
|
1167
|
+
currency = self.currency(code)
|
1168
|
+
request['currency'] = currency['id']
|
1006
1169
|
if limit is not None:
|
1007
1170
|
request['count'] = limit
|
1008
1171
|
response = await self.privateGetUserWalletHistory(self.extend(request, params))
|
1009
1172
|
transactions = self.filter_by_array(response, 'transactType', ['Withdrawal', 'Deposit'], False)
|
1010
|
-
currency = None
|
1011
|
-
if code is not None:
|
1012
|
-
currency = self.currency(code)
|
1013
1173
|
return self.parse_transactions(transactions, currency, since, limit)
|
1014
1174
|
|
1015
1175
|
def parse_transaction_status(self, status):
|
@@ -1059,10 +1219,9 @@ class bitmex(Exchange, ImplicitAPI):
|
|
1059
1219
|
addressTo = self.safe_string(transaction, 'address')
|
1060
1220
|
addressFrom = self.safe_string(transaction, 'tx')
|
1061
1221
|
amountString = self.safe_string(transaction, 'amount')
|
1062
|
-
|
1063
|
-
amountString = Precise.string_div(Precise.string_abs(amountString), scale)
|
1222
|
+
amount = self.convert_to_real_amount(currency['code'], amountString)
|
1064
1223
|
feeCostString = self.safe_string(transaction, 'fee')
|
1065
|
-
|
1224
|
+
feeCost = self.convert_to_real_amount(currency['code'], feeCostString)
|
1066
1225
|
status = self.safe_string(transaction, 'transactStatus')
|
1067
1226
|
if status is not None:
|
1068
1227
|
status = self.parse_transaction_status(status)
|
@@ -1073,7 +1232,7 @@ class bitmex(Exchange, ImplicitAPI):
|
|
1073
1232
|
'type': type,
|
1074
1233
|
'currency': currency['code'],
|
1075
1234
|
'network': self.safe_string(transaction, 'network'),
|
1076
|
-
'amount':
|
1235
|
+
'amount': amount,
|
1077
1236
|
'status': status,
|
1078
1237
|
'timestamp': transactTime,
|
1079
1238
|
'datetime': self.iso8601(transactTime),
|
@@ -1087,7 +1246,7 @@ class bitmex(Exchange, ImplicitAPI):
|
|
1087
1246
|
'comment': None,
|
1088
1247
|
'fee': {
|
1089
1248
|
'currency': currency['code'],
|
1090
|
-
'cost':
|
1249
|
+
'cost': feeCost,
|
1091
1250
|
'rate': None,
|
1092
1251
|
},
|
1093
1252
|
}
|
@@ -1130,112 +1289,7 @@ class bitmex(Exchange, ImplicitAPI):
|
|
1130
1289
|
return self.filter_by_array(result, 'symbol', symbols)
|
1131
1290
|
|
1132
1291
|
def parse_ticker(self, ticker, market=None):
|
1133
|
-
#
|
1134
|
-
# { symbol: "ETHH19",
|
1135
|
-
# rootSymbol: "ETH",
|
1136
|
-
# state: "Open",
|
1137
|
-
# typ: "FFCCSX",
|
1138
|
-
# listing: "2018-12-17T04:00:00.000Z",
|
1139
|
-
# front: "2019-02-22T12:00:00.000Z",
|
1140
|
-
# expiry: "2019-03-29T12:00:00.000Z",
|
1141
|
-
# settle: "2019-03-29T12:00:00.000Z",
|
1142
|
-
# relistInterval: null,
|
1143
|
-
# inverseLeg: "",
|
1144
|
-
# sellLeg: "",
|
1145
|
-
# buyLeg: "",
|
1146
|
-
# optionStrikePcnt: null,
|
1147
|
-
# optionStrikeRound: null,
|
1148
|
-
# optionStrikePrice: null,
|
1149
|
-
# optionMultiplier: null,
|
1150
|
-
# positionCurrency: "ETH",
|
1151
|
-
# underlying: "ETH",
|
1152
|
-
# quoteCurrency: "XBT",
|
1153
|
-
# underlyingSymbol: "ETHXBT=",
|
1154
|
-
# reference: "BMEX",
|
1155
|
-
# referenceSymbol: ".BETHXBT30M",
|
1156
|
-
# calcInterval: null,
|
1157
|
-
# publishInterval: null,
|
1158
|
-
# publishTime: null,
|
1159
|
-
# maxOrderQty: 100000000,
|
1160
|
-
# maxPrice: 10,
|
1161
|
-
# lotSize: 1,
|
1162
|
-
# tickSize: 0.00001,
|
1163
|
-
# multiplier: 100000000,
|
1164
|
-
# settlCurrency: "XBt",
|
1165
|
-
# underlyingToPositionMultiplier: 1,
|
1166
|
-
# underlyingToSettleMultiplier: null,
|
1167
|
-
# quoteToSettleMultiplier: 100000000,
|
1168
|
-
# isQuanto: False,
|
1169
|
-
# isInverse: False,
|
1170
|
-
# initMargin: 0.02,
|
1171
|
-
# maintMargin: 0.01,
|
1172
|
-
# riskLimit: 5000000000,
|
1173
|
-
# riskStep: 5000000000,
|
1174
|
-
# limit: null,
|
1175
|
-
# capped: False,
|
1176
|
-
# taxed: True,
|
1177
|
-
# deleverage: True,
|
1178
|
-
# makerFee: -0.0005,
|
1179
|
-
# takerFee: 0.0025,
|
1180
|
-
# settlementFee: 0,
|
1181
|
-
# insuranceFee: 0,
|
1182
|
-
# fundingBaseSymbol: "",
|
1183
|
-
# fundingQuoteSymbol: "",
|
1184
|
-
# fundingPremiumSymbol: "",
|
1185
|
-
# fundingTimestamp: null,
|
1186
|
-
# fundingInterval: null,
|
1187
|
-
# fundingRate: null,
|
1188
|
-
# indicativeFundingRate: null,
|
1189
|
-
# rebalanceTimestamp: null,
|
1190
|
-
# rebalanceInterval: null,
|
1191
|
-
# openingTimestamp: "2019-02-13T08:00:00.000Z",
|
1192
|
-
# closingTimestamp: "2019-02-13T09:00:00.000Z",
|
1193
|
-
# sessionInterval: "2000-01-01T01:00:00.000Z",
|
1194
|
-
# prevClosePrice: 0.03347,
|
1195
|
-
# limitDownPrice: null,
|
1196
|
-
# limitUpPrice: null,
|
1197
|
-
# bankruptLimitDownPrice: null,
|
1198
|
-
# bankruptLimitUpPrice: null,
|
1199
|
-
# prevTotalVolume: 1386531,
|
1200
|
-
# totalVolume: 1387062,
|
1201
|
-
# volume: 531,
|
1202
|
-
# volume24h: 17118,
|
1203
|
-
# prevTotalTurnover: 4741294246000,
|
1204
|
-
# totalTurnover: 4743103466000,
|
1205
|
-
# turnover: 1809220000,
|
1206
|
-
# turnover24h: 57919845000,
|
1207
|
-
# homeNotional24h: 17118,
|
1208
|
-
# foreignNotional24h: 579.19845,
|
1209
|
-
# prevPrice24h: 0.03349,
|
1210
|
-
# vwap: 0.03383564,
|
1211
|
-
# highPrice: 0.03458,
|
1212
|
-
# lowPrice: 0.03329,
|
1213
|
-
# lastPrice: 0.03406,
|
1214
|
-
# lastPriceProtected: 0.03406,
|
1215
|
-
# lastTickDirection: "ZeroMinusTick",
|
1216
|
-
# lastChangePcnt: 0.017,
|
1217
|
-
# bidPrice: 0.03406,
|
1218
|
-
# midPrice: 0.034065,
|
1219
|
-
# askPrice: 0.03407,
|
1220
|
-
# impactBidPrice: 0.03406,
|
1221
|
-
# impactMidPrice: 0.034065,
|
1222
|
-
# impactAskPrice: 0.03407,
|
1223
|
-
# hasLiquidity: True,
|
1224
|
-
# openInterest: 83679,
|
1225
|
-
# openValue: 285010674000,
|
1226
|
-
# fairMethod: "ImpactMidPrice",
|
1227
|
-
# fairBasisRate: 0,
|
1228
|
-
# fairBasis: 0,
|
1229
|
-
# fairPrice: 0.03406,
|
1230
|
-
# markMethod: "FairPrice",
|
1231
|
-
# markPrice: 0.03406,
|
1232
|
-
# indicativeTaxRate: 0,
|
1233
|
-
# indicativeSettlePrice: 0.03406,
|
1234
|
-
# optionUnderlyingPrice: null,
|
1235
|
-
# settledPrice: null,
|
1236
|
-
# timestamp: "2019-02-13T08:40:30.000Z",
|
1237
|
-
# }
|
1238
|
-
#
|
1292
|
+
# see response sample under "fetchMarkets" because same endpoint is being used here
|
1239
1293
|
marketId = self.safe_string(ticker, 'symbol')
|
1240
1294
|
symbol = self.safe_symbol(marketId, market)
|
1241
1295
|
timestamp = self.parse8601(self.safe_string(ticker, 'timestamp'))
|
@@ -1259,8 +1313,8 @@ class bitmex(Exchange, ImplicitAPI):
|
|
1259
1313
|
'change': None,
|
1260
1314
|
'percentage': None,
|
1261
1315
|
'average': None,
|
1262
|
-
'baseVolume': self.safe_string(ticker, 'homeNotional24h'),
|
1263
|
-
'quoteVolume': self.safe_string(ticker, 'foreignNotional24h'),
|
1316
|
+
'baseVolume': self.convert_from_raw_quantity(symbol, self.safe_string(ticker, 'homeNotional24h')),
|
1317
|
+
'quoteVolume': self.convert_from_raw_quantity(symbol, self.safe_string(ticker, 'foreignNotional24h')),
|
1264
1318
|
'info': ticker,
|
1265
1319
|
}, market)
|
1266
1320
|
|
@@ -1282,13 +1336,16 @@ class bitmex(Exchange, ImplicitAPI):
|
|
1282
1336
|
# "foreignNotional":0
|
1283
1337
|
# }
|
1284
1338
|
#
|
1339
|
+
marketId = self.safe_string(ohlcv, 'symbol')
|
1340
|
+
market = self.safe_market(marketId, market)
|
1341
|
+
volume = self.convert_from_raw_quantity(market['symbol'], self.safe_string(ohlcv, 'volume'))
|
1285
1342
|
return [
|
1286
1343
|
self.parse8601(self.safe_string(ohlcv, 'timestamp')),
|
1287
1344
|
self.safe_number(ohlcv, 'open'),
|
1288
1345
|
self.safe_number(ohlcv, 'high'),
|
1289
1346
|
self.safe_number(ohlcv, 'low'),
|
1290
1347
|
self.safe_number(ohlcv, 'close'),
|
1291
|
-
|
1348
|
+
volume,
|
1292
1349
|
]
|
1293
1350
|
|
1294
1351
|
async def fetch_ohlcv(self, symbol: str, timeframe='1m', since: Optional[int] = None, limit: Optional[int] = None, params={}):
|
@@ -1418,17 +1475,18 @@ class bitmex(Exchange, ImplicitAPI):
|
|
1418
1475
|
# "timestamp": "2019-03-05T12:47:02.762Z"
|
1419
1476
|
# }
|
1420
1477
|
#
|
1478
|
+
marketId = self.safe_string(trade, 'symbol')
|
1479
|
+
symbol = self.safe_symbol(marketId, market)
|
1421
1480
|
timestamp = self.parse8601(self.safe_string(trade, 'timestamp'))
|
1422
1481
|
priceString = self.safe_string_2(trade, 'avgPx', 'price')
|
1423
|
-
amountString = self.safe_string_2(trade, 'size', 'lastQty')
|
1424
|
-
execCost = self.safe_string(trade, 'execCost')
|
1425
|
-
costString = Precise.string_div(Precise.string_abs(execCost), '1e8')
|
1482
|
+
amountString = self.convert_from_raw_quantity(symbol, self.safe_string_2(trade, 'size', 'lastQty'))
|
1483
|
+
execCost = self.number_to_string(self.convert_from_raw_cost(symbol, self.safe_string(trade, 'execCost')))
|
1426
1484
|
id = self.safe_string(trade, 'trdMatchID')
|
1427
1485
|
order = self.safe_string(trade, 'orderID')
|
1428
1486
|
side = self.safe_string_lower(trade, 'side')
|
1429
1487
|
# price * amount doesn't work for all symbols(e.g. XBT, ETH)
|
1430
1488
|
fee = None
|
1431
|
-
feeCostString =
|
1489
|
+
feeCostString = self.number_to_string(self.convert_from_raw_cost(symbol, self.safe_string(trade, 'execComm')))
|
1432
1490
|
if feeCostString is not None:
|
1433
1491
|
currencyId = self.safe_string(trade, 'settlCurrency')
|
1434
1492
|
feeCurrencyCode = self.safe_currency_code(currencyId)
|
@@ -1443,8 +1501,6 @@ class bitmex(Exchange, ImplicitAPI):
|
|
1443
1501
|
takerOrMaker = None
|
1444
1502
|
if feeCostString is not None and execType == 'Trade':
|
1445
1503
|
takerOrMaker = 'maker' if Precise.string_lt(feeCostString, '0') else 'taker'
|
1446
|
-
marketId = self.safe_string(trade, 'symbol')
|
1447
|
-
symbol = self.safe_symbol(marketId, market)
|
1448
1504
|
type = self.safe_string_lower(trade, 'ordType')
|
1449
1505
|
return self.safe_trade({
|
1450
1506
|
'info': trade,
|
@@ -1457,7 +1513,7 @@ class bitmex(Exchange, ImplicitAPI):
|
|
1457
1513
|
'takerOrMaker': takerOrMaker,
|
1458
1514
|
'side': side,
|
1459
1515
|
'price': priceString,
|
1460
|
-
'cost':
|
1516
|
+
'cost': Precise.string_abs(execCost),
|
1461
1517
|
'amount': amountString,
|
1462
1518
|
'fee': fee,
|
1463
1519
|
}, market)
|
@@ -1532,9 +1588,26 @@ class bitmex(Exchange, ImplicitAPI):
|
|
1532
1588
|
timestamp = self.parse8601(self.safe_string(order, 'timestamp'))
|
1533
1589
|
lastTradeTimestamp = self.parse8601(self.safe_string(order, 'transactTime'))
|
1534
1590
|
price = self.safe_string(order, 'price')
|
1535
|
-
|
1536
|
-
|
1591
|
+
qty = self.safe_string(order, 'orderQty')
|
1592
|
+
cost = None
|
1593
|
+
amount = None
|
1594
|
+
defaultSubType = self.safe_string(self.options, 'defaultSubType', 'linear')
|
1595
|
+
isInverse = False
|
1596
|
+
if market is None:
|
1597
|
+
isInverse = (defaultSubType == 'inverse')
|
1598
|
+
else:
|
1599
|
+
isInverse = self.safe_value(market, 'inverse', False)
|
1600
|
+
if isInverse:
|
1601
|
+
cost = self.convert_from_raw_quantity(symbol, qty)
|
1602
|
+
else:
|
1603
|
+
amount = self.convert_from_raw_quantity(symbol, qty)
|
1537
1604
|
average = self.safe_string(order, 'avgPx')
|
1605
|
+
filled = None
|
1606
|
+
cumQty = self.number_to_string(self.convert_from_raw_quantity(symbol, self.safe_string(order, 'cumQty')))
|
1607
|
+
if isInverse:
|
1608
|
+
filled = Precise.string_div(cumQty, average)
|
1609
|
+
else:
|
1610
|
+
filled = cumQty
|
1538
1611
|
id = self.safe_string(order, 'orderID')
|
1539
1612
|
type = self.safe_string_lower(order, 'ordType')
|
1540
1613
|
side = self.safe_string_lower(order, 'side')
|
@@ -1561,7 +1634,7 @@ class bitmex(Exchange, ImplicitAPI):
|
|
1561
1634
|
'stopPrice': stopPrice,
|
1562
1635
|
'triggerPrice': stopPrice,
|
1563
1636
|
'amount': amount,
|
1564
|
-
'cost':
|
1637
|
+
'cost': cost,
|
1565
1638
|
'average': average,
|
1566
1639
|
'filled': filled,
|
1567
1640
|
'remaining': None,
|
@@ -1641,10 +1714,11 @@ class bitmex(Exchange, ImplicitAPI):
|
|
1641
1714
|
if (market['type'] != 'swap') and (market['type'] != 'future'):
|
1642
1715
|
raise InvalidOrder(self.id + ' createOrder() does not support reduceOnly for ' + market['type'] + ' orders, reduceOnly orders are supported for swap and future markets only')
|
1643
1716
|
brokerId = self.safe_string(self.options, 'brokerId', 'CCXT')
|
1717
|
+
qty = self.parse_to_int(self.amount_to_precision(symbol, amount))
|
1644
1718
|
request = {
|
1645
1719
|
'symbol': market['id'],
|
1646
1720
|
'side': self.capitalize(side),
|
1647
|
-
'orderQty':
|
1721
|
+
'orderQty': qty, # lot size multiplied by the number of contracts
|
1648
1722
|
'ordType': orderType,
|
1649
1723
|
'text': brokerId,
|
1650
1724
|
}
|
@@ -1677,7 +1751,8 @@ class bitmex(Exchange, ImplicitAPI):
|
|
1677
1751
|
else:
|
1678
1752
|
request['orderID'] = id
|
1679
1753
|
if amount is not None:
|
1680
|
-
|
1754
|
+
qty = self.parse_to_int(self.amount_to_precision(symbol, amount))
|
1755
|
+
request['orderQty'] = qty
|
1681
1756
|
if price is not None:
|
1682
1757
|
request['price'] = price
|
1683
1758
|
brokerId = self.safe_string(self.options, 'brokerId', 'CCXT')
|
@@ -1995,14 +2070,19 @@ class bitmex(Exchange, ImplicitAPI):
|
|
1995
2070
|
datetime = self.safe_string(position, 'timestamp')
|
1996
2071
|
crossMargin = self.safe_value(position, 'crossMargin')
|
1997
2072
|
marginMode = 'cross' if (crossMargin is True) else 'isolated'
|
1998
|
-
|
1999
|
-
|
2000
|
-
|
2001
|
-
|
2002
|
-
|
2003
|
-
|
2004
|
-
|
2005
|
-
|
2073
|
+
notionalString = Precise.string_abs(self.safe_string(position, 'foreignNotional', 'homeNotional'))
|
2074
|
+
settleCurrencyCode = self.safe_string(market, 'settle')
|
2075
|
+
maintenanceMargin = self.convert_to_real_amount(settleCurrencyCode, self.safe_string(position, 'maintMargin'))
|
2076
|
+
unrealisedPnl = self.convert_to_real_amount(settleCurrencyCode, self.safe_string(position, 'unrealisedPnl'))
|
2077
|
+
contracts = self.parse_number(Precise.string_abs(self.safe_string(position, 'currentQty')))
|
2078
|
+
contractSize = self.safe_number(market, 'contractSize')
|
2079
|
+
side = None
|
2080
|
+
homeNotional = self.safe_string(position, 'homeNotional')
|
2081
|
+
if homeNotional is not None:
|
2082
|
+
if homeNotional[0] == '-':
|
2083
|
+
side = 'short'
|
2084
|
+
else:
|
2085
|
+
side = 'long'
|
2006
2086
|
return self.safe_position({
|
2007
2087
|
'info': position,
|
2008
2088
|
'id': self.safe_string(position, 'account'),
|
@@ -2011,52 +2091,26 @@ class bitmex(Exchange, ImplicitAPI):
|
|
2011
2091
|
'datetime': datetime,
|
2012
2092
|
'lastUpdateTimestamp': None,
|
2013
2093
|
'hedged': None,
|
2014
|
-
'side':
|
2015
|
-
'contracts':
|
2016
|
-
'contractSize':
|
2094
|
+
'side': side,
|
2095
|
+
'contracts': contracts,
|
2096
|
+
'contractSize': contractSize,
|
2017
2097
|
'entryPrice': self.safe_number(position, 'avgEntryPrice'),
|
2018
2098
|
'markPrice': self.safe_number(position, 'markPrice'),
|
2019
2099
|
'lastPrice': None,
|
2020
|
-
'notional':
|
2100
|
+
'notional': self.parse_number(notionalString),
|
2021
2101
|
'leverage': self.safe_number(position, 'leverage'),
|
2022
2102
|
'collateral': None,
|
2023
2103
|
'initialMargin': self.safe_number(position, 'initMargin'),
|
2024
2104
|
'initialMarginPercentage': self.safe_number(position, 'initMarginReq'),
|
2025
|
-
'maintenanceMargin':
|
2105
|
+
'maintenanceMargin': maintenanceMargin,
|
2026
2106
|
'maintenanceMarginPercentage': self.safe_number(position, 'maintMarginReq'),
|
2027
|
-
'unrealizedPnl':
|
2107
|
+
'unrealizedPnl': unrealisedPnl,
|
2028
2108
|
'liquidationPrice': self.safe_number(position, 'liquidationPrice'),
|
2029
2109
|
'marginMode': marginMode,
|
2030
2110
|
'marginRatio': None,
|
2031
2111
|
'percentage': self.safe_number(position, 'unrealisedPnlPcnt'),
|
2032
2112
|
})
|
2033
2113
|
|
2034
|
-
def convert_value(self, value, market=None):
|
2035
|
-
if (value is None) or (market is None):
|
2036
|
-
return value
|
2037
|
-
resultValue = None
|
2038
|
-
value = self.number_to_string(value)
|
2039
|
-
if (market['quote'] == 'USD') or (market['quote'] == 'EUR'):
|
2040
|
-
resultValue = Precise.string_mul(value, '0.00000001')
|
2041
|
-
elif market['quote'] == 'USDT':
|
2042
|
-
resultValue = Precise.string_mul(value, '0.000001')
|
2043
|
-
else:
|
2044
|
-
currency = None
|
2045
|
-
quote = market['quote']
|
2046
|
-
if quote is not None:
|
2047
|
-
currency = self.currency(market['quote'])
|
2048
|
-
if currency is not None:
|
2049
|
-
resultValue = Precise.string_mul(value, self.number_to_string(currency['precision']))
|
2050
|
-
resultValue = float(resultValue) if (resultValue is not None) else None
|
2051
|
-
return resultValue
|
2052
|
-
|
2053
|
-
def is_fiat(self, currency):
|
2054
|
-
if currency == 'EUR':
|
2055
|
-
return True
|
2056
|
-
if currency == 'PLN':
|
2057
|
-
return True
|
2058
|
-
return False
|
2059
|
-
|
2060
2114
|
async def withdraw(self, code: str, amount, address, tag=None, params={}):
|
2061
2115
|
"""
|
2062
2116
|
make a withdrawal
|
@@ -2070,14 +2124,15 @@ class bitmex(Exchange, ImplicitAPI):
|
|
2070
2124
|
tag, params = self.handle_withdraw_tag_and_params(tag, params)
|
2071
2125
|
self.check_address(address)
|
2072
2126
|
await self.load_markets()
|
2073
|
-
# currency = self.currency(code)
|
2074
|
-
if code != 'BTC':
|
2075
|
-
raise ExchangeError(self.id + ' supoprts BTC withdrawals only, other currencies coming soon...')
|
2076
2127
|
currency = self.currency(code)
|
2128
|
+
qty = self.convert_from_real_amount(code, amount)
|
2129
|
+
networkCode = None
|
2130
|
+
networkCode, params = self.handle_network_code_and_params(params)
|
2077
2131
|
request = {
|
2078
|
-
'currency': '
|
2079
|
-
'amount':
|
2132
|
+
'currency': currency['id'],
|
2133
|
+
'amount': qty,
|
2080
2134
|
'address': address,
|
2135
|
+
'network': self.network_code_to_id(networkCode, currency['code']),
|
2081
2136
|
# 'otpToken': '123456', # requires if two-factor auth(OTP) is enabled
|
2082
2137
|
# 'fee': 0.001, # bitcoin network fee
|
2083
2138
|
}
|
@@ -2122,115 +2177,7 @@ class bitmex(Exchange, ImplicitAPI):
|
|
2122
2177
|
return self.parse_funding_rates(filteredResponse, symbols)
|
2123
2178
|
|
2124
2179
|
def parse_funding_rate(self, contract, market=None):
|
2125
|
-
#
|
2126
|
-
# {
|
2127
|
-
# "symbol": "LTCUSDT",
|
2128
|
-
# "rootSymbol": "LTC",
|
2129
|
-
# "state": "Open",
|
2130
|
-
# "typ": "FFWCSX",
|
2131
|
-
# "listing": "2021-11-10T04:00:00.000Z",
|
2132
|
-
# "front": "2021-11-10T04:00:00.000Z",
|
2133
|
-
# "expiry": null,
|
2134
|
-
# "settle": null,
|
2135
|
-
# "listedSettle": null,
|
2136
|
-
# "relistInterval": null,
|
2137
|
-
# "inverseLeg": "",
|
2138
|
-
# "sellLeg": "",
|
2139
|
-
# "buyLeg": "",
|
2140
|
-
# "optionStrikePcnt": null,
|
2141
|
-
# "optionStrikeRound": null,
|
2142
|
-
# "optionStrikePrice": null,
|
2143
|
-
# "optionMultiplier": null,
|
2144
|
-
# "positionCurrency": "LTC",
|
2145
|
-
# "underlying": "LTC",
|
2146
|
-
# "quoteCurrency": "USDT",
|
2147
|
-
# "underlyingSymbol": "LTCT=",
|
2148
|
-
# "reference": "BMEX",
|
2149
|
-
# "referenceSymbol": ".BLTCT",
|
2150
|
-
# "calcInterval": null,
|
2151
|
-
# "publishInterval": null,
|
2152
|
-
# "publishTime": null,
|
2153
|
-
# "maxOrderQty": 1000000000,
|
2154
|
-
# "maxPrice": 1000000,
|
2155
|
-
# "lotSize": 1000,
|
2156
|
-
# "tickSize": 0.01,
|
2157
|
-
# "multiplier": 100,
|
2158
|
-
# "settlCurrency": "USDt",
|
2159
|
-
# "underlyingToPositionMultiplier": 10000,
|
2160
|
-
# "underlyingToSettleMultiplier": null,
|
2161
|
-
# "quoteToSettleMultiplier": 1000000,
|
2162
|
-
# "isQuanto": False,
|
2163
|
-
# "isInverse": False,
|
2164
|
-
# "initMargin": 0.03,
|
2165
|
-
# "maintMargin": 0.015,
|
2166
|
-
# "riskLimit": 1000000000000,
|
2167
|
-
# "riskStep": 1000000000000,
|
2168
|
-
# "limit": null,
|
2169
|
-
# "capped": False,
|
2170
|
-
# "taxed": True,
|
2171
|
-
# "deleverage": True,
|
2172
|
-
# "makerFee": -0.0001,
|
2173
|
-
# "takerFee": 0.0005,
|
2174
|
-
# "settlementFee": 0,
|
2175
|
-
# "insuranceFee": 0,
|
2176
|
-
# "fundingBaseSymbol": ".LTCBON8H",
|
2177
|
-
# "fundingQuoteSymbol": ".USDTBON8H",
|
2178
|
-
# "fundingPremiumSymbol": ".LTCUSDTPI8H",
|
2179
|
-
# "fundingTimestamp": "2022-01-14T20:00:00.000Z",
|
2180
|
-
# "fundingInterval": "2000-01-01T08:00:00.000Z",
|
2181
|
-
# "fundingRate": 0.0001,
|
2182
|
-
# "indicativeFundingRate": 0.0001,
|
2183
|
-
# "rebalanceTimestamp": null,
|
2184
|
-
# "rebalanceInterval": null,
|
2185
|
-
# "openingTimestamp": "2022-01-14T17:00:00.000Z",
|
2186
|
-
# "closingTimestamp": "2022-01-14T18:00:00.000Z",
|
2187
|
-
# "sessionInterval": "2000-01-01T01:00:00.000Z",
|
2188
|
-
# "prevClosePrice": 138.511,
|
2189
|
-
# "limitDownPrice": null,
|
2190
|
-
# "limitUpPrice": null,
|
2191
|
-
# "bankruptLimitDownPrice": null,
|
2192
|
-
# "bankruptLimitUpPrice": null,
|
2193
|
-
# "prevTotalVolume": 12699024000,
|
2194
|
-
# "totalVolume": 12702160000,
|
2195
|
-
# "volume": 3136000,
|
2196
|
-
# "volume24h": 114251000,
|
2197
|
-
# "prevTotalTurnover": 232418052349000,
|
2198
|
-
# "totalTurnover": 232463353260000,
|
2199
|
-
# "turnover": 45300911000,
|
2200
|
-
# "turnover24h": 1604331340000,
|
2201
|
-
# "homeNotional24h": 11425.1,
|
2202
|
-
# "foreignNotional24h": 1604331.3400000003,
|
2203
|
-
# "prevPrice24h": 135.48,
|
2204
|
-
# "vwap": 140.42165,
|
2205
|
-
# "highPrice": 146.42,
|
2206
|
-
# "lowPrice": 135.08,
|
2207
|
-
# "lastPrice": 144.36,
|
2208
|
-
# "lastPriceProtected": 144.36,
|
2209
|
-
# "lastTickDirection": "MinusTick",
|
2210
|
-
# "lastChangePcnt": 0.0655,
|
2211
|
-
# "bidPrice": 143.75,
|
2212
|
-
# "midPrice": 143.855,
|
2213
|
-
# "askPrice": 143.96,
|
2214
|
-
# "impactBidPrice": 143.75,
|
2215
|
-
# "impactMidPrice": 143.855,
|
2216
|
-
# "impactAskPrice": 143.96,
|
2217
|
-
# "hasLiquidity": True,
|
2218
|
-
# "openInterest": 38103000,
|
2219
|
-
# "openValue": 547963053300,
|
2220
|
-
# "fairMethod": "FundingRate",
|
2221
|
-
# "fairBasisRate": 0.1095,
|
2222
|
-
# "fairBasis": 0.004,
|
2223
|
-
# "fairPrice": 143.811,
|
2224
|
-
# "markMethod": "FairPrice",
|
2225
|
-
# "markPrice": 143.811,
|
2226
|
-
# "indicativeTaxRate": null,
|
2227
|
-
# "indicativeSettlePrice": 143.807,
|
2228
|
-
# "optionUnderlyingPrice": null,
|
2229
|
-
# "settledPriceAdjustmentRate": null,
|
2230
|
-
# "settledPrice": null,
|
2231
|
-
# "timestamp": "2022-01-14T17:49:55.000Z"
|
2232
|
-
# }
|
2233
|
-
#
|
2180
|
+
# see response sample under "fetchMarkets" because same endpoint is being used here
|
2234
2181
|
datetime = self.safe_string(contract, 'timestamp')
|
2235
2182
|
marketId = self.safe_string(contract, 'symbol')
|
2236
2183
|
fundingDatetime = self.safe_string(contract, 'fundingTimestamp')
|
@@ -2383,18 +2330,18 @@ class bitmex(Exchange, ImplicitAPI):
|
|
2383
2330
|
:returns dict: an `address structure <https://docs.ccxt.com/#/?id=address-structure>`
|
2384
2331
|
"""
|
2385
2332
|
await self.load_markets()
|
2386
|
-
networkCode =
|
2333
|
+
networkCode = None
|
2334
|
+
networkCode, params = self.handle_network_code_and_params(params)
|
2387
2335
|
if networkCode is None:
|
2388
2336
|
raise ArgumentsRequired(self.id + ' fetchDepositAddress requires params["network"]')
|
2389
2337
|
currency = self.currency(code)
|
2390
2338
|
currencyId = currency['id']
|
2391
|
-
networkId = self.network_code_to_id(networkCode, currency['code'])
|
2392
2339
|
idLength = len(currencyId)
|
2393
2340
|
currencyId = currencyId[0:idLength - 1] + currencyId[idLength - 1:idLength].lower() # make the last letter lowercase
|
2394
2341
|
params = self.omit(params, 'network')
|
2395
2342
|
request = {
|
2396
2343
|
'currency': currencyId,
|
2397
|
-
'network':
|
2344
|
+
'network': self.network_code_to_id(networkCode, currency['code']),
|
2398
2345
|
}
|
2399
2346
|
response = await self.privateGetUserDepositAddress(self.extend(request, params))
|
2400
2347
|
#
|
@@ -2404,10 +2351,111 @@ class bitmex(Exchange, ImplicitAPI):
|
|
2404
2351
|
'currency': code,
|
2405
2352
|
'address': response.replace('"', '').replace('"', ''), # Done twice because some languages only replace the first instance
|
2406
2353
|
'tag': None,
|
2407
|
-
'network':
|
2354
|
+
'network': networkCode,
|
2408
2355
|
'info': response,
|
2409
2356
|
}
|
2410
2357
|
|
2358
|
+
def parse_deposit_withdraw_fee(self, fee, currency=None):
|
2359
|
+
#
|
2360
|
+
# {
|
2361
|
+
# asset: 'XBT',
|
2362
|
+
# currency: 'XBt',
|
2363
|
+
# majorCurrency: 'XBT',
|
2364
|
+
# name: 'Bitcoin',
|
2365
|
+
# currencyType: 'Crypto',
|
2366
|
+
# scale: '8',
|
2367
|
+
# enabled: True,
|
2368
|
+
# isMarginCurrency: True,
|
2369
|
+
# minDepositAmount: '10000',
|
2370
|
+
# minWithdrawalAmount: '1000',
|
2371
|
+
# maxWithdrawalAmount: '100000000000000',
|
2372
|
+
# networks: [
|
2373
|
+
# {
|
2374
|
+
# asset: 'btc',
|
2375
|
+
# tokenAddress: '',
|
2376
|
+
# depositEnabled: True,
|
2377
|
+
# withdrawalEnabled: True,
|
2378
|
+
# withdrawalFee: '20000',
|
2379
|
+
# minFee: '20000',
|
2380
|
+
# maxFee: '10000000'
|
2381
|
+
# }
|
2382
|
+
# ]
|
2383
|
+
# }
|
2384
|
+
#
|
2385
|
+
networks = self.safe_value(fee, 'networks', [])
|
2386
|
+
networksLength = len(networks)
|
2387
|
+
result = {
|
2388
|
+
'info': fee,
|
2389
|
+
'withdraw': {
|
2390
|
+
'fee': None,
|
2391
|
+
'percentage': None,
|
2392
|
+
},
|
2393
|
+
'deposit': {
|
2394
|
+
'fee': None,
|
2395
|
+
'percentage': None,
|
2396
|
+
},
|
2397
|
+
'networks': {},
|
2398
|
+
}
|
2399
|
+
if networksLength != 0:
|
2400
|
+
scale = self.safe_string(fee, 'scale')
|
2401
|
+
precision = self.parse_precision(scale)
|
2402
|
+
for i in range(0, networksLength):
|
2403
|
+
network = networks[i]
|
2404
|
+
networkId = self.safe_string(network, 'asset')
|
2405
|
+
currencyCode = self.safe_string(currency, 'code')
|
2406
|
+
networkCode = self.network_id_to_code(networkId, currencyCode)
|
2407
|
+
withdrawalFeeId = self.safe_string(network, 'withdrawalFee')
|
2408
|
+
withdrawalFee = self.parse_number(Precise.string_mul(withdrawalFeeId, precision))
|
2409
|
+
result['networks'][networkCode] = {
|
2410
|
+
'deposit': {'fee': None, 'percentage': None},
|
2411
|
+
'withdraw': {'fee': withdrawalFee, 'percentage': False},
|
2412
|
+
}
|
2413
|
+
if networksLength == 1:
|
2414
|
+
result['withdraw']['fee'] = withdrawalFee
|
2415
|
+
result['withdraw']['percentage'] = False
|
2416
|
+
return result
|
2417
|
+
|
2418
|
+
async def fetch_deposit_withdraw_fees(self, codes: Optional[List[str]] = None, params={}):
|
2419
|
+
"""
|
2420
|
+
fetch deposit and withdraw fees
|
2421
|
+
see https://www.bitmex.com/api/explorer/#not /Wallet/Wallet_getAssetsConfig
|
2422
|
+
:param [str]|None codes: list of unified currency codes
|
2423
|
+
:param dict params: extra parameters specific to the bitmex api endpoint
|
2424
|
+
:returns dict: a list of `fee structures <https://docs.ccxt.com/en/latest/manual.html#fee-structure>`
|
2425
|
+
"""
|
2426
|
+
await self.load_markets()
|
2427
|
+
assets = await self.publicGetWalletAssets(params)
|
2428
|
+
#
|
2429
|
+
# [
|
2430
|
+
# {
|
2431
|
+
# asset: 'XBT',
|
2432
|
+
# currency: 'XBt',
|
2433
|
+
# majorCurrency: 'XBT',
|
2434
|
+
# name: 'Bitcoin',
|
2435
|
+
# currencyType: 'Crypto',
|
2436
|
+
# scale: '8',
|
2437
|
+
# enabled: True,
|
2438
|
+
# isMarginCurrency: True,
|
2439
|
+
# minDepositAmount: '10000',
|
2440
|
+
# minWithdrawalAmount: '1000',
|
2441
|
+
# maxWithdrawalAmount: '100000000000000',
|
2442
|
+
# networks: [
|
2443
|
+
# {
|
2444
|
+
# asset: 'btc',
|
2445
|
+
# tokenAddress: '',
|
2446
|
+
# depositEnabled: True,
|
2447
|
+
# withdrawalEnabled: True,
|
2448
|
+
# withdrawalFee: '20000',
|
2449
|
+
# minFee: '20000',
|
2450
|
+
# maxFee: '10000000'
|
2451
|
+
# }
|
2452
|
+
# ]
|
2453
|
+
# },
|
2454
|
+
# ...
|
2455
|
+
# ]
|
2456
|
+
#
|
2457
|
+
return self.parse_deposit_withdraw_fees(assets, codes, 'asset')
|
2458
|
+
|
2411
2459
|
def calculate_rate_limiter_cost(self, api, method, path, params, config={}):
|
2412
2460
|
isAuthenticated = self.check_required_credentials(False)
|
2413
2461
|
cost = self.safe_value(config, 'cost', 1)
|