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.

@@ -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
- 'AVAX': 'avax',
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': 'BSC',
258
- 'tron': 'TRX',
259
- 'avax': 'AVAX',
264
+ 'bsc': 'BEP20',
265
+ 'tron': 'TRC20',
266
+ 'avax': 'AVALANCHEC',
260
267
  'near': 'NEAR',
261
- 'xtz': 'XTZ',
262
- 'dot': 'DOT',
263
- 'sol': '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
- if contract:
431
- symbol = symbol + ':' + settle
432
- multiplierString = Precise.string_abs(self.safe_string(market, 'multiplier'))
433
- contractSize = self.parse_number(multiplierString)
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
- if future:
440
- expiryDatetime = self.safe_string(market, 'expiry')
441
- expiry = self.parse8601(expiryDatetime)
442
- symbol = symbol + '-' + self.yymmdd(expiry)
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
- # temporarily filter out unlisted markets to avoid symbol conflicts
450
- if active:
451
- result.append({
452
- 'id': id,
453
- 'symbol': symbol,
454
- 'base': base,
455
- 'quote': quote,
456
- 'settle': settle,
457
- 'baseId': baseId,
458
- 'quoteId': quoteId,
459
- 'settleId': settleId,
460
- 'type': type,
461
- 'spot': spot,
462
- 'margin': False,
463
- 'swap': swap,
464
- 'future': future,
465
- 'option': False,
466
- 'active': active,
467
- 'contract': contract,
468
- 'linear': not inverse if contract else None,
469
- 'inverse': inverse if contract else None,
470
- 'taker': self.safe_number(market, 'takerFee'),
471
- 'maker': self.safe_number(market, 'makerFee'),
472
- 'contractSize': contractSize,
473
- 'expiry': expiry,
474
- 'expiryDatetime': expiryDatetime,
475
- 'strike': self.safe_number(market, 'optionStrikePrice'),
476
- 'optionType': None,
477
- 'precision': {
478
- 'amount': self.safe_number(market, 'lotSize'),
479
- 'price': self.safe_number(market, 'tickSize'),
480
- 'quote': self.safe_number(market, 'tickSize'),
481
- 'base': self.safe_number(market, 'tickSize'),
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
- 'limits': {
484
- 'leverage': {
485
- 'min': self.parse_number('1') if contract else None,
486
- 'max': maxLeverage if contract else None,
487
- },
488
- 'amount': {
489
- 'min': None,
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
- 'info': market,
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
- if code != 'USDT':
562
- # tmp fix until self PR gets merged
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.safe_number(order, 'size')
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
- amount = self.safe_number(item, 'amount')
897
- if amount is not None:
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 / 100000000
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 / 100000000
915
- before = self.sum(after, -amount)
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 amount < 0:
1075
+ if Precise.string_lt(amountString, '0'):
918
1076
  direction = 'out'
919
- amount = abs(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
- scale = '1e8' if (currency['code'] == 'BTC') else '1e6'
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
- feeCostString = Precise.string_div(feeCostString, scale)
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': self.parse_number(amountString),
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': self.parse_number(feeCostString),
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
- self.safe_number(ohlcv, 'volume'),
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 = Precise.string_div(self.safe_string(trade, 'execComm'), '1e8')
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': costString,
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
- amount = self.safe_string(order, 'orderQty')
1536
- filled = self.safe_string(order, 'cumQty')
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': None,
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': float(self.amount_to_precision(symbol, amount)), # lot size multiplied by the number of contracts
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
- request['orderQty'] = amount
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
- notional = None
1999
- if market['quote'] == 'USDT' or market['quote'] == 'USD' or market['quote'] == 'EUR':
2000
- notional = Precise.string_mul(self.safe_string(position, 'foreignNotional'), '-1')
2001
- else:
2002
- notional = self.safe_string(position, 'homeNotional')
2003
- maintenanceMargin = self.safe_number(position, 'maintMargin')
2004
- unrealisedPnl = self.safe_number(position, 'unrealisedPnl')
2005
- contracts = self.omit_zero(self.safe_number(position, 'currentQty'))
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': None,
2015
- 'contracts': self.convert_value(contracts, market),
2016
- 'contractSize': None,
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': 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': self.convert_value(maintenanceMargin, market),
2105
+ 'maintenanceMargin': maintenanceMargin,
2026
2106
  'maintenanceMarginPercentage': self.safe_number(position, 'maintMarginReq'),
2027
- 'unrealizedPnl': self.convert_value(unrealisedPnl, market),
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': 'XBt', # temporarily
2079
- 'amount': 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 = self.safe_string_upper(params, 'network')
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': networkId,
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': self.network_id_to_code(networkId).upper(),
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)