text: # -*- coding: utf-8 -*-
  
  # PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
  # https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
  
  from ccxt.base.exchange import Exchange
  from ccxt.base.errors import ExchangeError
  from ccxt.base.errors import AuthenticationError
  from ccxt.base.errors import PermissionDenied
  from ccxt.base.errors import BadRequest
  from ccxt.base.errors import InsufficientFunds
  from ccxt.base.errors import InvalidOrder
  from ccxt.base.errors import OrderNotFound
  from ccxt.base.errors import DDoSProtection
  from ccxt.base.errors import ExchangeNotAvailable
  from ccxt.base.decimal_to_precision import TICK_SIZE
  
  
  class bitmex(Exchange):
  
      def describe(self):
          return self.deep_extend(super(bitmex, self).describe(), {
              'id': 'bitmex',
              'name': 'BitMEX',
              'countries': ['SC'],  # Seychelles
              'version': 'v1',
              'userAgent': None,
              'rateLimit': 2000,
              'pro': True,
              'has': {
                  'cancelAllOrders': True,
                  'cancelOrder': True,
                  'CORS': False,
                  'createOrder': True,
                  'editOrder': True,
                  'fetchBalance': True,
                  'fetchClosedOrders': True,
                  'fetchLedger': True,
                  'fetchMarkets': True,
                  'fetchMyTrades': True,
                  'fetchOHLCV': True,
                  'fetchOpenOrders': True,
                  'fetchOrder': True,
                  'fetchOrderBook': True,
                  'fetchOrders': True,
                  'fetchTicker': True,
                  'fetchTickers': True,
                  'fetchTrades': True,
                  'fetchTransactions': 'emulated',
                  'withdraw': True,
              },
              'timeframes': {
                  '1m': '1m',
                  '5m': '5m',
                  '1h': '1h',
                  '1d': '1d',
              },
              'urls': {
                  'test': {
                      'public': 'https://testnet.bitmex.com',
                      'private': 'https://testnet.bitmex.com',
                  },
                  'logo': 'https://user-images.githubusercontent.com/1294454/27766319-f653c6e6-5ed4-11e7-933d-f0bc3699ae8f.jpg',
                  'api': {
                      'public': 'https://www.bitmex.com',
                      'private': 'https://www.bitmex.com',
                  },
                  'www': 'https://www.bitmex.com',
                  'doc': [
                      'https://www.bitmex.com/app/apiOverview',
                      'https://github.com/BitMEX/api-connectors/tree/master/official-http',
                  ],
                  'fees': 'https://www.bitmex.com/app/fees',
                  'referral': 'https://www.bitmex.com/register/upZpOX',
              },
              'api': {
                  'public': {
                      'get': [
                          'announcement',
                          'announcement/urgent',
                          'funding',
                          'instrument',
                          'instrument/active',
                          'instrument/activeAndIndices',
                          'instrument/activeIntervals',
                          'instrument/compositeIndex',
                          'instrument/indices',
                          'insurance',
                          'leaderboard',
                          'liquidation',
                          'orderBook',
                          'orderBook/L2',
                          'quote',
                          'quote/bucketed',
                          'schema',
                          'schema/websocketHelp',
                          'settlement',
                          'stats',
                          'stats/history',
                          'trade',
                          'trade/bucketed',
                      ],
                  },
                  'private': {
                      'get': [
                          'apiKey',
                          'chat',
                          'chat/channels',
                          'chat/connected',
                          'execution',
                          'execution/tradeHistory',
                          'notification',
                          'order',
                          'position',
                          'user',
                          'user/affiliateStatus',
                          'user/checkReferralCode',
                          'user/commission',
                          'user/depositAddress',
                          'user/executionHistory',
                          'user/margin',
                          'user/minWithdrawalFee',
                          'user/wallet',
                          'user/walletHistory',
                          'user/walletSummary',
                      ],
                      'post': [
                          'apiKey',
                          'apiKey/disable',
                          'apiKey/enable',
                          'chat',
                          'order',
                          'order/bulk',
                          'order/cancelAllAfter',
                          'order/closePosition',
                          'position/isolate',
                          'position/leverage',
                          'position/riskLimit',
                          'position/transferMargin',
                          'user/cancelWithdrawal',
                          'user/confirmEmail',
                          'user/confirmEnableTFA',
                          'user/confirmWithdrawal',
                          'user/disableTFA',
                          'user/logout',
                          'user/logoutAll',
                          'user/preferences',
                          'user/requestEnableTFA',
                          'user/requestWithdrawal',
                      ],
                      'put': [
                          'order',
                          'order/bulk',
                          'user',
                      ],
                      'delete': [
                          'apiKey',
                          'order',
                          'order/all',
                      ],
                  },
              },
              'exceptions': {
                  'exact': {
                      'Invalid API Key.': AuthenticationError,
                      'This key is disabled.': PermissionDenied,
                      'Access Denied': PermissionDenied,
                      'Duplicate clOrdID': InvalidOrder,
                      'orderQty is invalid': InvalidOrder,
                      'Invalid price': InvalidOrder,
                      'Invalid stopPx for ordType': InvalidOrder,
                  },
                  'broad': {
                      'Signature not valid': AuthenticationError,
                      'overloaded': ExchangeNotAvailable,
                      'Account has insufficient Available Balance': InsufficientFunds,
                      'Service unavailable': ExchangeNotAvailable,  # {"error":{"message":"Service unavailable","name":"HTTPError"}}
                      'Server Error': ExchangeError,  # {"error":{"message":"Server Error","name":"HTTPError"}}
                  },
              },
              'precisionMode': TICK_SIZE,
              'options': {
                  # https://blog.bitmex.com/api_announcement/deprecation-of-api-nonce-header/
                  # https://github.com/ccxt/ccxt/issues/4789
                  'api-expires': 5,  # in seconds
                  'fetchOHLCVOpenTimestamp': True,
              },
          })
  
      def fetch_markets(self, params={}):
          response = self.publicGetInstrumentActiveAndIndices(params)
          result = []
          for i in range(0, len(response)):
              market = response[i]
              active = (market['state'] != 'Unlisted')
              id = market['symbol']
              baseId = market['underlying']
              quoteId = market['quoteCurrency']
              basequote = baseId + quoteId
              base = self.safe_currency_code(baseId)
              quote = self.safe_currency_code(quoteId)
              swap = (id == basequote)
              # 'positionCurrency' may be empty("", as Bitmex currently returns for ETHUSD)
              # so let's take the quote currency first and then adjust if needed
              positionId = self.safe_string_2(market, 'positionCurrency', 'quoteCurrency')
              type = None
              future = False
              prediction = False
              position = self.safe_currency_code(positionId)
              symbol = id
              if swap:
                  type = 'swap'
                  symbol = base + '/' + quote
              elif id.find('B_') >= 0:
                  prediction = True
                  type = 'prediction'
              else:
                  future = True
                  type = 'future'
              precision = {
                  'amount': None,
                  'price': None,
              }
              lotSize = self.safe_float(market, 'lotSize')
              tickSize = self.safe_float(market, 'tickSize')
              if lotSize is not None:
                  precision['amount'] = lotSize
              if tickSize is not None:
                  precision['price'] = tickSize
              limits = {
                  'amount': {
                      'min': None,
                      'max': None,
                  },
                  'price': {
                      'min': tickSize,
                      'max': self.safe_float(market, 'maxPrice'),
                  },
                  'cost': {
                      'min': None,
                      'max': None,
                  },
              }
              limitField = 'cost' if (position == quote) else 'amount'
              limits[limitField] = {
                  'min': lotSize,
                  'max': self.safe_float(market, 'maxOrderQty'),
              }
              result.append({
                  'id': id,
                  'symbol': symbol,
                  'base': base,
                  'quote': quote,
                  'baseId': baseId,
                  'quoteId': quoteId,
                  'active': active,
                  'precision': precision,
                  'limits': limits,
                  'taker': self.safe_float(market, 'takerFee'),
                  'maker': self.safe_float(market, 'makerFee'),
                  'type': type,
                  'spot': False,
                  'swap': swap,
                  'future': future,
                  'prediction': prediction,
                  'info': market,
              })
          return result
  
      def parse_balance_response(self, response):
          #
          #     [
          #         {
          #             "account":1455728,
          #             "currency":"XBt",
          #             "riskLimit":1000000000000,
          #             "prevState":"",
          #             "state":"",
          #             "action":"",
          #             "amount":263542,
          #             "pendingCredit":0,
          #             "pendingDebit":0,
          #             "confirmedDebit":0,
          #             "prevRealisedPnl":0,
          #             "prevUnrealisedPnl":0,
          #             "grossComm":0,
          #             "grossOpenCost":0,
          #             "grossOpenPremium":0,
          #             "grossExecCost":0,
          #             "grossMarkValue":0,
          #             "riskValue":0,
          #             "taxableMargin":0,
          #             "initMargin":0,
          #             "maintMargin":0,
          #             "sessionMargin":0,
          #             "targetExcessMargin":0,
          #             "varMargin":0,
          #             "realisedPnl":0,
          #             "unrealisedPnl":0,
          #             "indicativeTax":0,
          #             "unrealisedProfit":0,
          #             "syntheticMargin":null,
          #             "walletBalance":263542,
          #             "marginBalance":263542,
          #             "marginBalancePcnt":1,
          #             "marginLeverage":0,
          #             "marginUsedPcnt":0,
          #             "excessMargin":263542,
          #             "excessMarginPcnt":1,
          #             "availableMargin":263542,
          #             "withdrawableMargin":263542,
          #             "timestamp":"2020-08-03T12:01:01.246Z",
          #             "grossLastValue":0,
          #             "commission":null
          #         }
          #     ]
          #
          result = {'info': response}
          for i in range(0, len(response)):
              balance = response[i]
              currencyId = self.safe_string(balance, 'currency')
              code = self.safe_currency_code(currencyId)
              account = self.account()
              free = self.safe_float(balance, 'availableMargin')
              total = self.safe_float(balance, 'marginBalance')
              if code == 'BTC':
                  if free is not None:
                      free /= 100000000
                  if total is not None:
                      total /= 100000000
              account['free'] = free
              account['total'] = total
              result[code] = account
          return self.parse_balance(result)
  
      def fetch_balance(self, params={}):
          self.load_markets()
          request = {
              'currency': 'all',
          }
          response = self.privateGetUserMargin(self.extend(request, params))
          #
          #     [
          #         {
          #             "account":1455728,
          #             "currency":"XBt",
          #             "riskLimit":1000000000000,
          #             "prevState":"",
          #             "state":"",
          #             "action":"",
          #             "amount":263542,
          #             "pendingCredit":0,
          #             "pendingDebit":0,
          #             "confirmedDebit":0,
          #             "prevRealisedPnl":0,
          #             "prevUnrealisedPnl":0,
          #             "grossComm":0,
          #             "grossOpenCost":0,
          #             "grossOpenPremium":0,
          #             "grossExecCost":0,
          #             "grossMarkValue":0,
          #             "riskValue":0,
          #             "taxableMargin":0,
          #             "initMargin":0,
          #             "maintMargin":0,
          #             "sessionMargin":0,
          #             "targetExcessMargin":0,
          #             "varMargin":0,
          #             "realisedPnl":0,
          #             "unrealisedPnl":0,
          #             "indicativeTax":0,
          #             "unrealisedProfit":0,
          #             "syntheticMargin":null,
          #             "walletBalance":263542,
          #             "marginBalance":263542,
          #             "marginBalancePcnt":1,
          #             "marginLeverage":0,
          #             "marginUsedPcnt":0,
          #             "excessMargin":263542,
          #             "excessMarginPcnt":1,
          #             "availableMargin":263542,
          #             "withdrawableMargin":263542,
          #             "timestamp":"2020-08-03T12:01:01.246Z",
          #             "grossLastValue":0,
          #             "commission":null
          #         }
          #     ]
          #
          return self.parse_balance_response(response)
  
      def fetch_order_book(self, symbol, limit=None, params={}):
          self.load_markets()
          market = self.market(symbol)
          request = {
              'symbol': market['id'],
          }
          if limit is not None:
              request['depth'] = limit
          response = self.publicGetOrderBookL2(self.extend(request, params))
          result = {
              'bids': [],
              'asks': [],
              'timestamp': None,
              'datetime': None,
              'nonce': None,
          }
          for i in range(0, len(response)):
              order = response[i]
              side = 'asks' if (order['side'] == 'Sell') else 'bids'
              amount = self.safe_float(order, 'size')
              price = self.safe_float(order, 'price')
              # https://github.com/ccxt/ccxt/issues/4926
              # https://github.com/ccxt/ccxt/issues/4927
              # the exchange sometimes returns null price in the orderbook
              if price is not None:
                  result[side].append([price, amount])
          result['bids'] = self.sort_by(result['bids'], 0, True)
          result['asks'] = self.sort_by(result['asks'], 0)
          return result
  
      def fetch_order(self, id, symbol=None, params={}):
          filter = {
              'filter': {
                  'orderID': id,
              },
          }
          response = self.fetch_orders(symbol, None, None, self.deep_extend(filter, params))
          numResults = len(response)
          if numResults == 1:
              return response[0]
          raise OrderNotFound(self.id + ': The order ' + id + ' not found.')
  
      def fetch_orders(self, symbol=None, since=None, limit=None, params={}):
          self.load_markets()
          market = None
          request = {}
          if symbol is not None:
              market = self.market(symbol)
              request['symbol'] = market['id']
          if since is not None:
              request['startTime'] = self.iso8601(since)
          if limit is not None:
              request['count'] = limit
          request = self.deep_extend(request, params)
          # why the hassle? urlencode in python is kinda broken for nested dicts.
          # E.g. self.urlencode({"filter": {"open": True}}) will return "filter={'open':+True}"
          # Bitmex doesn't like that. Hence resorting to self hack.
          if 'filter' in request:
              request['filter'] = self.json(request['filter'])
          response = self.privateGetOrder(request)
          return self.parse_orders(response, market, since, limit)
  
      def fetch_open_orders(self, symbol=None, since=None, limit=None, params={}):
          request = {
              'filter': {
                  'open': True,
              },
          }
          return self.fetch_orders(symbol, since, limit, self.deep_extend(request, params))
  
      def fetch_closed_orders(self, symbol=None, since=None, limit=None, params={}):
          # Bitmex barfs if you set 'open': False in the filter...
          orders = self.fetch_orders(symbol, since, limit, params)
          return self.filter_by(orders, 'status', 'closed')
  
      def fetch_my_trades(self, symbol=None, since=None, limit=None, params={}):
          self.load_markets()
          market = None
          request = {}
          if symbol is not None:
              market = self.market(symbol)
              request['symbol'] = market['id']
          if since is not None:
              request['startTime'] = self.iso8601(since)
          if limit is not None:
              request['count'] = limit
          request = self.deep_extend(request, params)
          # why the hassle? urlencode in python is kinda broken for nested dicts.
          # E.g. self.urlencode({"filter": {"open": True}}) will return "filter={'open':+True}"
          # Bitmex doesn't like that. Hence resorting to self hack.
          if 'filter' in request:
              request['filter'] = self.json(request['filter'])
          response = self.privateGetExecutionTradeHistory(request)
          #
          #     [
          #         {
          #             "execID": "string",
          #             "orderID": "string",
          #             "clOrdID": "string",
          #             "clOrdLinkID": "string",
          #             "account": 0,
          #             "symbol": "string",
          #             "side": "string",
          #             "lastQty": 0,
          #             "lastPx": 0,
          #             "underlyingLastPx": 0,
          #             "lastMkt": "string",
          #             "lastLiquidityInd": "string",
          #             "simpleOrderQty": 0,
          #             "orderQty": 0,
          #             "price": 0,
          #             "displayQty": 0,
          #             "stopPx": 0,
          #             "pegOffsetValue": 0,
          #             "pegPriceType": "string",
          #             "currency": "string",
          #             "settlCurrency": "string",
          #             "execType": "string",
          #             "ordType": "string",
          #             "timeInForce": "string",
          #             "execInst": "string",
          #             "contingencyType": "string",
          #             "exDestination": "string",
          #             "ordStatus": "string",
          #             "triggered": "string",
          #             "workingIndicator": True,
          #             "ordRejReason": "string",
          #             "simpleLeavesQty": 0,
          #             "leavesQty": 0,
          #             "simpleCumQty": 0,
          #             "cumQty": 0,
          #             "avgPx": 0,
          #             "commission": 0,
          #             "tradePublishIndicator": "string",
          #             "multiLegReportingType": "string",
          #             "text": "string",
          #             "trdMatchID": "string",
          #             "execCost": 0,
          #             "execComm": 0,
          #             "homeNotional": 0,
          #             "foreignNotional": 0,
          #             "transactTime": "2019-03-05T12:47:02.762Z",
          #             "timestamp": "2019-03-05T12:47:02.762Z"
          #         }
          #     ]
          #
          return self.parse_trades(response, market, since, limit)
  
      def parse_ledger_entry_type(self, type):
          types = {
              'Withdrawal': 'transaction',
              'RealisedPNL': 'margin',
              'UnrealisedPNL': 'margin',
              'Deposit': 'transaction',
              'Transfer': 'transfer',
              'AffiliatePayout': 'referral',
          }
          return self.safe_string(types, type, type)
  
      def parse_ledger_entry(self, item, currency=None):
          #
          #     {
          #         transactID: "69573da3-7744-5467-3207-89fd6efe7a47",
          #         account:  24321,
          #         currency: "XBt",
          #         transactType: "Withdrawal",  # "AffiliatePayout", "Transfer", "Deposit", "RealisedPNL", ...
          #         amount:  -1000000,
          #         fee:  300000,
          #         transactStatus: "Completed",  # "Canceled", ...
          #         address: "1Ex4fkF4NhQaQdRWNoYpqiPbDBbq18Kdd9",
          #         tx: "3BMEX91ZhhKoWtsH9QRb5dNXnmnGpiEetA",
          #         text: "",
          #         transactTime: "2017-03-21T20:05:14.388Z",
          #         walletBalance:  0,  # balance after
          #         marginBalance:  null,
          #         timestamp: "2017-03-22T13:09:23.514Z"
          #     }
          #
          # ButMEX returns the unrealized pnl from the wallet history endpoint.
          # The unrealized pnl transaction has an empty timestamp.
          # It is not related to historical pnl it has status set to "Pending".
          # Therefore it's not a part of the history at all.
          # https://github.com/ccxt/ccxt/issues/6047
          #
          #     {
          #         "transactID":"00000000-0000-0000-0000-000000000000",
          #         "account":121210,
          #         "currency":"XBt",
          #         "transactType":"UnrealisedPNL",
          #         "amount":-5508,
          #         "fee":0,
          #         "transactStatus":"Pending",
          #         "address":"XBTUSD",
          #         "tx":"",
          #         "text":"",
          #         "transactTime":null,  # ←---------------------------- null
          #         "walletBalance":139198767,
          #         "marginBalance":139193259,
          #         "timestamp":null  # ←---------------------------- null
          #     }
          #
          id = self.safe_string(item, 'transactID')
          account = self.safe_string(item, 'account')
          referenceId = self.safe_string(item, 'tx')
          referenceAccount = None
          type = self.parse_ledger_entry_type(self.safe_string(item, 'transactType'))
          currencyId = self.safe_string(item, 'currency')
          code = self.safe_currency_code(currencyId, currency)
          amount = self.safe_float(item, 'amount')
          if amount is not None:
              amount = amount / 100000000
          timestamp = self.parse8601(self.safe_string(item, 'transactTime'))
          if timestamp is None:
              # https://github.com/ccxt/ccxt/issues/6047
              # set the timestamp to zero, 1970 Jan 1 00:00:00
              # for unrealized pnl and other transactions without a timestamp
              timestamp = 0  # see comments above
          feeCost = self.safe_float(item, 'fee', 0)
          if feeCost is not None:
              feeCost = feeCost / 100000000
          fee = {
              'cost': feeCost,
              'currency': code,
          }
          after = self.safe_float(item, 'walletBalance')
          if after is not None:
              after = after / 100000000
          before = self.sum(after, -amount)
          direction = None
          if amount < 0:
              direction = 'out'
              amount = abs(amount)
          else:
              direction = 'in'
          status = self.parse_transaction_status(self.safe_string(item, 'transactStatus'))
          return {
              'id': id,
              'info': item,
              'timestamp': timestamp,
              'datetime': self.iso8601(timestamp),
              'direction': direction,
              'account': account,
              'referenceId': referenceId,
              'referenceAccount': referenceAccount,
              'type': type,
              'currency': code,
              'amount': amount,
              'before': before,
              'after': after,
              'status': status,
              'fee': fee,
          }
  
      def fetch_ledger(self, code=None, since=None, limit=None, params={}):
          self.load_markets()
          currency = None
          if code is not None:
              currency = self.currency(code)
          request = {
              # 'start': 123,
          }
          #
          #     if since is not None:
          #         # date-based pagination not supported
          #     }
          #
          if limit is not None:
              request['count'] = limit
          response = self.privateGetUserWalletHistory(self.extend(request, params))
          #
          #     [
          #         {
          #             transactID: "69573da3-7744-5467-3207-89fd6efe7a47",
          #             account:  24321,
          #             currency: "XBt",
          #             transactType: "Withdrawal",  # "AffiliatePayout", "Transfer", "Deposit", "RealisedPNL", ...
          #             amount:  -1000000,
          #             fee:  300000,
          #             transactStatus: "Completed",  # "Canceled", ...
          #             address: "1Ex4fkF4NhQaQdRWNoYpqiPbDBbq18Kdd9",
          #             tx: "3BMEX91ZhhKoWtsH9QRb5dNXnmnGpiEetA",
          #             text: "",
          #             transactTime: "2017-03-21T20:05:14.388Z",
          #             walletBalance:  0,  # balance after
          #             marginBalance:  null,
          #             timestamp: "2017-03-22T13:09:23.514Z"
          #         }
          #     ]
          #
          return self.parse_ledger(response, currency, since, limit)
  
      def fetch_transactions(self, code=None, since=None, limit=None, params={}):
          self.load_markets()
          request = {
              # 'start': 123,
          }
          #
          #     if since is not None:
          #         # date-based pagination not supported
          #     }
          #
          if limit is not None:
              request['count'] = limit
          response = self.privateGetUserWalletHistory(self.extend(request, params))
          transactions = self.filter_by_array(response, 'transactType', ['Withdrawal', 'Deposit'], False)
          currency = None
          if code is not None:
              currency = self.currency(code)
          return self.parse_transactions(transactions, currency, since, limit)
  
      def parse_transaction_status(self, status):
          statuses = {
              'Canceled': 'canceled',
              'Completed': 'ok',
              'Pending': 'pending',
          }
          return self.safe_string(statuses, status, status)
  
      def parse_transaction(self, transaction, currency=None):
          #
          #   {
          #      'transactID': 'ffe699c2-95ee-4c13-91f9-0faf41daec25',
          #      'account': 123456,
          #      'currency': 'XBt',
          #      'transactType': 'Withdrawal',
          #      'amount': -100100000,
          #      'fee': 100000,
          #      'transactStatus': 'Completed',
          #      'address': '385cR5DM96n1HvBDMzLHPYcw89fZAXULJP',
          #      'tx': '3BMEXabcdefghijklmnopqrstuvwxyz123',
          #      'text': '',
          #      'transactTime': '2019-01-02T01:00:00.000Z',
          #      'walletBalance': 99900000,
          #      'marginBalance': None,
          #      'timestamp': '2019-01-02T13:00:00.000Z'
          #   }
          #
          id = self.safe_string(transaction, 'transactID')
          # For deposits, transactTime == timestamp
          # For withdrawals, transactTime is submission, timestamp is processed
          transactTime = self.parse8601(self.safe_string(transaction, 'transactTime'))
          timestamp = self.parse8601(self.safe_string(transaction, 'timestamp'))
          type = self.safe_string_lower(transaction, 'transactType')
          # Deposits have no from address or to address, withdrawals have both
          address = None
          addressFrom = None
          addressTo = None
          if type == 'withdrawal':
              address = self.safe_string(transaction, 'address')
              addressFrom = self.safe_string(transaction, 'tx')
              addressTo = address
          amount = self.safe_integer(transaction, 'amount')
          if amount is not None:
              amount = abs(amount) / 10000000
          feeCost = self.safe_integer(transaction, 'fee')
          if feeCost is not None:
              feeCost = feeCost / 10000000
          fee = {
              'cost': feeCost,
              'currency': 'BTC',
          }
          status = self.safe_string(transaction, 'transactStatus')
          if status is not None:
              status = self.parse_transaction_status(status)
          return {
              'info': transaction,
              'id': id,
              'txid': None,
              'timestamp': transactTime,
              'datetime': self.iso8601(transactTime),
              'addressFrom': addressFrom,
              'address': address,
              'addressTo': addressTo,
              'tagFrom': None,
              'tag': None,
              'tagTo': None,
              'type': type,
              'amount': amount,
              # BTC is the only currency on Bitmex
              'currency': 'BTC',
              'status': status,
              'updated': timestamp,
              'comment': None,
              'fee': fee,
          }
  
      def fetch_ticker(self, symbol, params={}):
          self.load_markets()
          market = self.market(symbol)
          if not market['active']:
              raise ExchangeError(self.id + ': symbol ' + symbol + ' is delisted')
          tickers = self.fetch_tickers([symbol], params)
          ticker = self.safe_value(tickers, symbol)
          if ticker is None:
              raise ExchangeError(self.id + ' ticker symbol ' + symbol + ' not found')
          return ticker
  
      def fetch_tickers(self, symbols=None, params={}):
          self.load_markets()
          response = self.publicGetInstrumentActiveAndIndices(params)
          result = {}
          for i in range(0, len(response)):
              ticker = self.parse_ticker(response[i])
              symbol = self.safe_string(ticker, 'symbol')
              if symbol is not None:
                  result[symbol] = ticker
          return self.filter_by_array(result, 'symbol', symbols)
  
      def parse_ticker(self, ticker, market=None):
          #
          #     {                        symbol: "ETHH19",
          #                           rootSymbol: "ETH",
          #                                state: "Open",
          #                                  typ: "FFCCSX",
          #                              listing: "2018-12-17T04:00:00.000Z",
          #                                front: "2019-02-22T12:00:00.000Z",
          #                               expiry: "2019-03-29T12:00:00.000Z",
          #                               settle: "2019-03-29T12:00:00.000Z",
          #                       relistInterval:  null,
          #                           inverseLeg: "",
          #                              sellLeg: "",
          #                               buyLeg: "",
          #                     optionStrikePcnt:  null,
          #                    optionStrikeRound:  null,
          #                    optionStrikePrice:  null,
          #                     optionMultiplier:  null,
          #                     positionCurrency: "ETH",
          #                           underlying: "ETH",
          #                        quoteCurrency: "XBT",
          #                     underlyingSymbol: "ETHXBT=",
          #                            reference: "BMEX",
          #                      referenceSymbol: ".BETHXBT30M",
          #                         calcInterval:  null,
          #                      publishInterval:  null,
          #                          publishTime:  null,
          #                          maxOrderQty:  100000000,
          #                             maxPrice:  10,
          #                              lotSize:  1,
          #                             tickSize:  0.00001,
          #                           multiplier:  100000000,
          #                        settlCurrency: "XBt",
          #       underlyingToPositionMultiplier:  1,
          #         underlyingToSettleMultiplier:  null,
          #              quoteToSettleMultiplier:  100000000,
          #                             isQuanto:  False,
          #                            isInverse:  False,
          #                           initMargin:  0.02,
          #                          maintMargin:  0.01,
          #                            riskLimit:  5000000000,
          #                             riskStep:  5000000000,
          #                                limit:  null,
          #                               capped:  False,
          #                                taxed:  True,
          #                           deleverage:  True,
          #                             makerFee:  -0.0005,
          #                             takerFee:  0.0025,
          #                        settlementFee:  0,
          #                         insuranceFee:  0,
          #                    fundingBaseSymbol: "",
          #                   fundingQuoteSymbol: "",
          #                 fundingPremiumSymbol: "",
          #                     fundingTimestamp:  null,
          #                      fundingInterval:  null,
          #                          fundingRate:  null,
          #                indicativeFundingRate:  null,
          #                   rebalanceTimestamp:  null,
          #                    rebalanceInterval:  null,
          #                     openingTimestamp: "2019-02-13T08:00:00.000Z",
          #                     closingTimestamp: "2019-02-13T09:00:00.000Z",
          #                      sessionInterval: "2000-01-01T01:00:00.000Z",
          #                       prevClosePrice:  0.03347,
          #                       limitDownPrice:  null,
          #                         limitUpPrice:  null,
          #               bankruptLimitDownPrice:  null,
          #                 bankruptLimitUpPrice:  null,
          #                      prevTotalVolume:  1386531,
          #                          totalVolume:  1387062,
          #                               volume:  531,
          #                            volume24h:  17118,
          #                    prevTotalTurnover:  4741294246000,
          #                        totalTurnover:  4743103466000,
          #                             turnover:  1809220000,
          #                          turnover24h:  57919845000,
          #                      homeNotional24h:  17118,
          #                   foreignNotional24h:  579.19845,
          #                         prevPrice24h:  0.03349,
          #                                 vwap:  0.03383564,
          #                            highPrice:  0.03458,
          #                             lowPrice:  0.03329,
          #                            lastPrice:  0.03406,
          #                   lastPriceProtected:  0.03406,
          #                    lastTickDirection: "ZeroMinusTick",
          #                       lastChangePcnt:  0.017,
          #                             bidPrice:  0.03406,
          #                             midPrice:  0.034065,
          #                             askPrice:  0.03407,
          #                       impactBidPrice:  0.03406,
          #                       impactMidPrice:  0.034065,
          #                       impactAskPrice:  0.03407,
          #                         hasLiquidity:  True,
          #                         openInterest:  83679,
          #                            openValue:  285010674000,
          #                           fairMethod: "ImpactMidPrice",
          #                        fairBasisRate:  0,
          #                            fairBasis:  0,
          #                            fairPrice:  0.03406,
          #                           markMethod: "FairPrice",
          #                            markPrice:  0.03406,
          #                    indicativeTaxRate:  0,
          #                indicativeSettlePrice:  0.03406,
          #                optionUnderlyingPrice:  null,
          #                         settledPrice:  null,
          #                            timestamp: "2019-02-13T08:40:30.000Z",
          #     }
          #
          symbol = None
          marketId = self.safe_string(ticker, 'symbol')
          market = self.safe_value(self.markets_by_id, marketId, market)
          if market is not None:
              symbol = market['symbol']
          timestamp = self.parse8601(self.safe_string(ticker, 'timestamp'))
          open = self.safe_float(ticker, 'prevPrice24h')
          last = self.safe_float(ticker, 'lastPrice')
          change = None
          percentage = None
          if last is not None and open is not None:
              change = last - open
              if open > 0:
                  percentage = change / open * 100
          return {
              'symbol': symbol,
              'timestamp': timestamp,
              'datetime': self.iso8601(timestamp),
              'high': self.safe_float(ticker, 'highPrice'),
              'low': self.safe_float(ticker, 'lowPrice'),
              'bid': self.safe_float(ticker, 'bidPrice'),
              'bidVolume': None,
              'ask': self.safe_float(ticker, 'askPrice'),
              'askVolume': None,
              'vwap': self.safe_float(ticker, 'vwap'),
              'open': open,
              'close': last,
              'last': last,
              'previousClose': None,
              'change': change,
              'percentage': percentage,
              'average': self.sum(open, last) / 2,
              'baseVolume': self.safe_float(ticker, 'homeNotional24h'),
              'quoteVolume': self.safe_float(ticker, 'foreignNotional24h'),
              'info': ticker,
          }
  
      def parse_ohlcv(self, ohlcv, market=None):
          #
          #     {
          #         "timestamp":"2015-09-25T13:38:00.000Z",
          #         "symbol":"XBTUSD",
          #         "open":237.45,
          #         "high":237.45,
          #         "low":237.45,
          #         "close":237.45,
          #         "trades":0,
          #         "volume":0,
          #         "vwap":null,
          #         "lastSize":null,
          #         "turnover":0,
          #         "homeNotional":0,
          #         "foreignNotional":0
          #     }
          #
          return [
              self.parse8601(self.safe_string(ohlcv, 'timestamp')),
              self.safe_float(ohlcv, 'open'),
              self.safe_float(ohlcv, 'high'),
              self.safe_float(ohlcv, 'low'),
              self.safe_float(ohlcv, 'close'),
              self.safe_float(ohlcv, 'volume'),
          ]
  
      def fetch_ohlcv(self, symbol, timeframe='1m', since=None, limit=None, params={}):
          self.load_markets()
          # send JSON key/value pairs, such as {"key": "value"}
          # filter by individual fields and do advanced queries on timestamps
          # filter = {'key': 'value'}
          # send a bare series(e.g. XBU) to nearest expiring contract in that series
          # you can also send a timeframe, e.g. XBU:monthly
          # timeframes: daily, weekly, monthly, quarterly, and biquarterly
          market = self.market(symbol)
          request = {
              'symbol': market['id'],
              'binSize': self.timeframes[timeframe],
              'partial': True,     # True == include yet-incomplete current bins
              # 'filter': filter,  # filter by individual fields and do advanced queries
              # 'columns': [],    # will return all columns if omitted
              # 'start': 0,       # starting point for results(wtf?)
              # 'reverse': False,  # True == newest first
              # 'endTime': '',    # ending date filter for results
          }
          if limit is not None:
              request['count'] = limit  # default 100, max 500
          duration = self.parse_timeframe(timeframe) * 1000
          fetchOHLCVOpenTimestamp = self.safe_value(self.options, 'fetchOHLCVOpenTimestamp', True)
          # if since is not set, they will return candles starting from 2017-01-01
          if since is not None:
              timestamp = since
              if fetchOHLCVOpenTimestamp:
                  timestamp = self.sum(timestamp, duration)
              ymdhms = self.ymdhms(timestamp)
              request['startTime'] = ymdhms  # starting date filter for results
          else:
              request['reverse'] = True
          response = self.publicGetTradeBucketed(self.extend(request, params))
          #
          #     [
          #         {"timestamp":"2015-09-25T13:38:00.000Z","symbol":"XBTUSD","open":237.45,"high":237.45,"low":237.45,"close":237.45,"trades":0,"volume":0,"vwap":null,"lastSize":null,"turnover":0,"homeNotional":0,"foreignNotional":0},
          #         {"timestamp":"2015-09-25T13:39:00.000Z","symbol":"XBTUSD","open":237.45,"high":237.45,"low":237.45,"close":237.45,"trades":0,"volume":0,"vwap":null,"lastSize":null,"turnover":0,"homeNotional":0,"foreignNotional":0},
          #         {"timestamp":"2015-09-25T13:40:00.000Z","symbol":"XBTUSD","open":237.45,"high":237.45,"low":237.45,"close":237.45,"trades":0,"volume":0,"vwap":null,"lastSize":null,"turnover":0,"homeNotional":0,"foreignNotional":0}
          #     ]
          #
          result = self.parse_ohlcvs(response, market, timeframe, since, limit)
          if fetchOHLCVOpenTimestamp:
              # bitmex returns the candle's close timestamp - https://github.com/ccxt/ccxt/issues/4446
              # we can emulate the open timestamp by shifting all the timestamps one place
              # so the previous close becomes the current open, and we drop the first candle
              for i in range(0, len(result)):
                  result[i][0] = result[i][0] - duration
          return result
  
      def parse_trade(self, trade, market=None):
          #
          # fetchTrades(public)
          #
          #     {
          #         timestamp: '2018-08-28T00:00:02.735Z',
          #         symbol: 'XBTUSD',
          #         side: 'Buy',
          #         size: 2000,
          #         price: 6906.5,
          #         tickDirection: 'PlusTick',
          #         trdMatchID: 'b9a42432-0a46-6a2f-5ecc-c32e9ca4baf8',
          #         grossValue: 28958000,
          #         homeNotional: 0.28958,
          #         foreignNotional: 2000
          #     }
          #
          # fetchMyTrades(private)
          #
          #     {
          #         "execID": "string",
          #         "orderID": "string",
          #         "clOrdID": "string",
          #         "clOrdLinkID": "string",
          #         "account": 0,
          #         "symbol": "string",
          #         "side": "string",
          #         "lastQty": 0,
          #         "lastPx": 0,
          #         "underlyingLastPx": 0,
          #         "lastMkt": "string",
          #         "lastLiquidityInd": "string",
          #         "simpleOrderQty": 0,
          #         "orderQty": 0,
          #         "price": 0,
          #         "displayQty": 0,
          #         "stopPx": 0,
          #         "pegOffsetValue": 0,
          #         "pegPriceType": "string",
          #         "currency": "string",
          #         "settlCurrency": "string",
          #         "execType": "string",
          #         "ordType": "string",
          #         "timeInForce": "string",
          #         "execInst": "string",
          #         "contingencyType": "string",
          #         "exDestination": "string",
          #         "ordStatus": "string",
          #         "triggered": "string",
          #         "workingIndicator": True,
          #         "ordRejReason": "string",
          #         "simpleLeavesQty": 0,
          #         "leavesQty": 0,
          #         "simpleCumQty": 0,
          #         "cumQty": 0,
          #         "avgPx": 0,
          #         "commission": 0,
          #         "tradePublishIndicator": "string",
          #         "multiLegReportingType": "string",
          #         "text": "string",
          #         "trdMatchID": "string",
          #         "execCost": 0,
          #         "execComm": 0,
          #         "homeNotional": 0,
          #         "foreignNotional": 0,
          #         "transactTime": "2019-03-05T12:47:02.762Z",
          #         "timestamp": "2019-03-05T12:47:02.762Z"
          #     }
          #
          timestamp = self.parse8601(self.safe_string(trade, 'timestamp'))
          price = self.safe_float_2(trade, 'avgPx', 'price')
          amount = self.safe_float_2(trade, 'size', 'lastQty')
          id = self.safe_string(trade, 'trdMatchID')
          order = self.safe_string(trade, 'orderID')
          side = self.safe_string_lower(trade, 'side')
          # price * amount doesn't work for all symbols(e.g. XBT, ETH)
          cost = self.safe_float(trade, 'execCost')
          if cost is not None:
              cost = abs(cost) / 100000000
          fee = None
          if 'execComm' in trade:
              feeCost = self.safe_float(trade, 'execComm')
              feeCost = feeCost / 100000000
              currencyId = self.safe_string(trade, 'settlCurrency')
              feeCurrency = self.safe_currency_code(currencyId)
              feeRate = self.safe_float(trade, 'commission')
              fee = {
                  'cost': feeCost,
                  'currency': feeCurrency,
                  'rate': feeRate,
              }
          takerOrMaker = None
          if fee is not None:
              takerOrMaker = 'maker' if (fee['cost'] < 0) else 'taker'
          marketId = self.safe_string(trade, 'symbol')
          symbol = self.safe_symbol(marketId, market)
          type = self.safe_string_lower(trade, 'ordType')
          return {
              'info': trade,
              'timestamp': timestamp,
              'datetime': self.iso8601(timestamp),
              'symbol': symbol,
              'id': id,
              'order': order,
              'type': type,
              'takerOrMaker': takerOrMaker,
              'side': side,
              'price': price,
              'cost': cost,
              'amount': amount,
              'fee': fee,
          }
  
      def parse_order_status(self, status):
          statuses = {
              'New': 'open',
              'PartiallyFilled': 'open',
              'Filled': 'closed',
              'DoneForDay': 'open',
              'Canceled': 'canceled',
              'PendingCancel': 'open',
              'PendingNew': 'open',
              'Rejected': 'rejected',
              'Expired': 'expired',
              'Stopped': 'open',
              'Untriggered': 'open',
              'Triggered': 'open',
          }
          return self.safe_string(statuses, status, status)
  
      def parse_time_in_force(self, timeInForce):
          timeInForces = {
              'Day': 'Day',
              'GoodTillCancel': 'GTC',
              'ImmediateOrCancel': 'IOC',
              'FillOrKill': 'FOK',
          }
          return self.safe_string(timeInForces, timeInForce, timeInForce)
  
      def parse_order(self, order, market=None):
          status = self.parse_order_status(self.safe_string(order, 'ordStatus'))
          marketId = self.safe_string(order, 'symbol')
          symbol = self.safe_symbol(marketId, market)
          timestamp = self.parse8601(self.safe_string(order, 'timestamp'))
          lastTradeTimestamp = self.parse8601(self.safe_string(order, 'transactTime'))
          price = self.safe_float(order, 'price')
          amount = self.safe_float(order, 'orderQty')
          filled = self.safe_float(order, 'cumQty', 0.0)
          remaining = None
          if amount is not None:
              if filled is not None:
                  remaining = max(amount - filled, 0.0)
          average = self.safe_float(order, 'avgPx')
          cost = None
          if filled is not None:
              if average is not None:
                  cost = average * filled
              elif price is not None:
                  cost = price * filled
          id = self.safe_string(order, 'orderID')
          type = self.safe_string_lower(order, 'ordType')
          side = self.safe_string_lower(order, 'side')
          clientOrderId = self.safe_string(order, 'clOrdID')
          timeInForce = self.parse_time_in_force(self.safe_string(order, 'timeInForce'))
          stopPrice = self.safe_float(order, 'stopPx')
          return {
              'info': order,
              'id': id,
              'clientOrderId': clientOrderId,
              'timestamp': timestamp,
              'datetime': self.iso8601(timestamp),
              'lastTradeTimestamp': lastTradeTimestamp,
              'symbol': symbol,
              'type': type,
              'timeInForce': timeInForce,
              'side': side,
              'price': price,
              'stopPrice': stopPrice,
              'amount': amount,
              'cost': cost,
              'average': average,
              'filled': filled,
              'remaining': remaining,
              'status': status,
              'fee': None,
              'trades': None,
          }
  
      def fetch_trades(self, symbol, since=None, limit=None, params={}):
          self.load_markets()
          market = self.market(symbol)
          request = {
              'symbol': market['id'],
          }
          if since is not None:
              request['startTime'] = self.iso8601(since)
          else:
              # by default reverse=false, i.e. trades are fetched since the time of market inception(year 2015 for XBTUSD)
              request['reverse'] = True
          if limit is not None:
              request['count'] = limit
          response = self.publicGetTrade(self.extend(request, params))
          #
          #     [
          #         {
          #             timestamp: '2018-08-28T00:00:02.735Z',
          #             symbol: 'XBTUSD',
          #             side: 'Buy',
          #             size: 2000,
          #             price: 6906.5,
          #             tickDirection: 'PlusTick',
          #             trdMatchID: 'b9a42432-0a46-6a2f-5ecc-c32e9ca4baf8',
          #             grossValue: 28958000,
          #             homeNotional: 0.28958,
          #             foreignNotional: 2000
          #         },
          #         {
          #             timestamp: '2018-08-28T00:00:03.778Z',
          #             symbol: 'XBTUSD',
          #             side: 'Sell',
          #             size: 1000,
          #             price: 6906,
          #             tickDirection: 'MinusTick',
          #             trdMatchID: '0d4f1682-5270-a800-569b-4a0eb92db97c',
          #             grossValue: 14480000,
          #             homeNotional: 0.1448,
          #             foreignNotional: 1000
          #         },
          #     ]
          #
          return self.parse_trades(response, market, since, limit)
  
      def create_order(self, symbol, type, side, amount, price=None, params={}):
          self.load_markets()
          market = self.market(symbol)
          orderType = self.capitalize(type)
          request = {
              'symbol': market['id'],
              'side': self.capitalize(side),
              'orderQty': amount,
              'ordType': orderType,
          }
          if price is not None:
              if orderType == 'Stop':
                  stopPrice = self.safe_float_2(params, 'stopPx', 'stopPrice')
                  request['stopPx'] = stopPrice
                  params = self.omit(params, ['stopPx', 'stopPrice'])
              else:
                  request['price'] = price
          clientOrderId = self.safe_string_2(params, 'clOrdID', 'clientOrderId')
          if clientOrderId is not None:
              request['clOrdID'] = clientOrderId
              params = self.omit(params, ['clOrdID', 'clientOrderId'])
          response = self.privatePostOrder(self.extend(request, params))
          return self.parse_order(response, market)
  
      def edit_order(self, id, symbol, type, side, amount=None, price=None, params={}):
          self.load_markets()
          request = {}
          origClOrdID = self.safe_string_2(params, 'origClOrdID', 'clientOrderId')
          if origClOrdID is not None:
              request['origClOrdID'] = origClOrdID
              clientOrderId = self.safe_string(params, 'clOrdID', 'clientOrderId')
              if clientOrderId is not None:
                  request['clOrdID'] = clientOrderId
              params = self.omit(params, ['origClOrdID', 'clOrdID', 'clientOrderId'])
          else:
              request['orderID'] = id
          if amount is not None:
              request['orderQty'] = amount
          if price is not None:
              request['price'] = price
          response = self.privatePutOrder(self.extend(request, params))
          return self.parse_order(response)
  
      def cancel_order(self, id, symbol=None, params={}):
          self.load_markets()
          # https://github.com/ccxt/ccxt/issues/6507
          clientOrderId = self.safe_string_2(params, 'clOrdID', 'clientOrderId')
          request = {}
          if clientOrderId is None:
              request['orderID'] = id
          else:
              request['clOrdID'] = clientOrderId
              params = self.omit(params, ['clOrdID', 'clientOrderId'])
          response = self.privateDeleteOrder(self.extend(request, params))
          order = self.safe_value(response, 0, {})
          error = self.safe_string(order, 'error')
          if error is not None:
              if error.find('Unable to cancel order due to existing state') >= 0:
                  raise OrderNotFound(self.id + ' cancelOrder() failed: ' + error)
          return self.parse_order(order)
  
      def cancel_all_orders(self, symbol=None, params={}):
          self.load_markets()
          request = {}
          market = None
          if symbol is not None:
              market = self.market(symbol)
              request['symbol'] = market['id']
          response = self.privateDeleteOrderAll(self.extend(request, params))
          #
          #     [
          #         {
          #             "orderID": "string",
          #             "clOrdID": "string",
          #             "clOrdLinkID": "string",
          #             "account": 0,
          #             "symbol": "string",
          #             "side": "string",
          #             "simpleOrderQty": 0,
          #             "orderQty": 0,
          #             "price": 0,
          #             "displayQty": 0,
          #             "stopPx": 0,
          #             "pegOffsetValue": 0,
          #             "pegPriceType": "string",
          #             "currency": "string",
          #             "settlCurrency": "string",
          #             "ordType": "string",
          #             "timeInForce": "string",
          #             "execInst": "string",
          #             "contingencyType": "string",
          #             "exDestination": "string",
          #             "ordStatus": "string",
          #             "triggered": "string",
          #             "workingIndicator": True,
          #             "ordRejReason": "string",
          #             "simpleLeavesQty": 0,
          #             "leavesQty": 0,
          #             "simpleCumQty": 0,
          #             "cumQty": 0,
          #             "avgPx": 0,
          #             "multiLegReportingType": "string",
          #             "text": "string",
          #             "transactTime": "2020-06-01T09:36:35.290Z",
          #             "timestamp": "2020-06-01T09:36:35.290Z"
          #         }
          #     ]
          #
          return self.parse_orders(response, market)
  
      def fetch_positions(self, symbols=None, since=None, limit=None, params={}):
          self.load_markets()
          response = self.privateGetPosition(params)
          #     [
          #         {
          #             "account": 0,
          #             "symbol": "string",
          #             "currency": "string",
          #             "underlying": "string",
          #             "quoteCurrency": "string",
          #             "commission": 0,
          #             "initMarginReq": 0,
          #             "maintMarginReq": 0,
          #             "riskLimit": 0,
          #             "leverage": 0,
          #             "crossMargin": True,
          #             "deleveragePercentile": 0,
          #             "rebalancedPnl": 0,
          #             "prevRealisedPnl": 0,
          #             "prevUnrealisedPnl": 0,
          #             "prevClosePrice": 0,
          #             "openingTimestamp": "2020-11-09T06:53:59.892Z",
          #             "openingQty": 0,
          #             "openingCost": 0,
          #             "openingComm": 0,
          #             "openOrderBuyQty": 0,
          #             "openOrderBuyCost": 0,
          #             "openOrderBuyPremium": 0,
          #             "openOrderSellQty": 0,
          #             "openOrderSellCost": 0,
          #             "openOrderSellPremium": 0,
          #             "execBuyQty": 0,
          #             "execBuyCost": 0,
          #             "execSellQty": 0,
          #             "execSellCost": 0,
          #             "execQty": 0,
          #             "execCost": 0,
          #             "execComm": 0,
          #             "currentTimestamp": "2020-11-09T06:53:59.893Z",
          #             "currentQty": 0,
          #             "currentCost": 0,
          #             "currentComm": 0,
          #             "realisedCost": 0,
          #             "unrealisedCost": 0,
          #             "grossOpenCost": 0,
          #             "grossOpenPremium": 0,
          #             "grossExecCost": 0,
          #             "isOpen": True,
          #             "markPrice": 0,
          #             "markValue": 0,
          #             "riskValue": 0,
          #             "homeNotional": 0,
          #             "foreignNotional": 0,
          #             "posState": "string",
          #             "posCost": 0,
          #             "posCost2": 0,
          #             "posCross": 0,
          #             "posInit": 0,
          #             "posComm": 0,
          #             "posLoss": 0,
          #             "posMargin": 0,
          #             "posMaint": 0,
          #             "posAllowance": 0,
          #             "taxableMargin": 0,
          #             "initMargin": 0,
          #             "maintMargin": 0,
          #             "sessionMargin": 0,
          #             "targetExcessMargin": 0,
          #             "varMargin": 0,
          #             "realisedGrossPnl": 0,
          #             "realisedTax": 0,
          #             "realisedPnl": 0,
          #             "unrealisedGrossPnl": 0,
          #             "longBankrupt": 0,
          #             "shortBankrupt": 0,
          #             "taxBase": 0,
          #             "indicativeTaxRate": 0,
          #             "indicativeTax": 0,
          #             "unrealisedTax": 0,
          #             "unrealisedPnl": 0,
          #             "unrealisedPnlPcnt": 0,
          #             "unrealisedRoePcnt": 0,
          #             "simpleQty": 0,
          #             "simpleCost": 0,
          #             "simpleValue": 0,
          #             "simplePnl": 0,
          #             "simplePnlPcnt": 0,
          #             "avgCostPrice": 0,
          #             "avgEntryPrice": 0,
          #             "breakEvenPrice": 0,
          #             "marginCallPrice": 0,
          #             "liquidationPrice": 0,
          #             "bankruptPrice": 0,
          #             "timestamp": "2020-11-09T06:53:59.894Z",
          #             "lastPrice": 0,
          #             "lastValue": 0
          #         }
          #     ]
          #
          # todo unify parsePosition/parsePositions
          return response
  
      def is_fiat(self, currency):
          if currency == 'EUR':
              return True
          if currency == 'PLN':
              return True
          return False
  
      def withdraw(self, code, amount, address, tag=None, params={}):
          self.check_address(address)
          self.load_markets()
          # currency = self.currency(code)
          if code != 'BTC':
              raise ExchangeError(self.id + ' supoprts BTC withdrawals only, other currencies coming soon...')
          request = {
              'currency': 'XBt',  # temporarily
              'amount': amount,
              'address': address,
              # 'otpToken': '123456',  # requires if two-factor auth(OTP) is enabled
              # 'fee': 0.001,  # bitcoin network fee
          }
          response = self.privatePostUserRequestWithdrawal(self.extend(request, params))
          return {
              'info': response,
              'id': self.safe_string(response, 'transactID'),
          }
  
      def handle_errors(self, code, reason, url, method, headers, body, response, requestHeaders, requestBody):
          if response is None:
              return
          if code == 429:
              raise DDoSProtection(self.id + ' ' + body)
          if code >= 400:
              error = self.safe_value(response, 'error', {})
              message = self.safe_string(error, 'message')
              feedback = self.id + ' ' + body
              self.throw_exactly_matched_exception(self.exceptions['exact'], message, feedback)
              self.throw_broadly_matched_exception(self.exceptions['broad'], message, feedback)
              if code == 400:
                  raise BadRequest(feedback)
              raise ExchangeError(feedback)  # unknown message
  
      def nonce(self):
          return self.milliseconds()
  
      def sign(self, path, api='public', method='GET', params={}, headers=None, body=None):
          query = '/api/' + self.version + '/' + path
          if method == 'GET':
              if params:
                  query += '?' + self.urlencode(params)
          else:
              format = self.safe_string(params, '_format')
              if format is not None:
                  query += '?' + self.urlencode({'_format': format})
                  params = self.omit(params, '_format')
          url = self.urls['api'][api] + query
          if self.apiKey and self.secret:
              auth = method + query
              expires = self.safe_integer(self.options, 'api-expires')
              headers = {
                  'Content-Type': 'application/json',
                  'api-key': self.apiKey,
              }
              expires = self.sum(self.seconds(), expires)
              expires = str(expires)
              auth += expires
              headers['api-expires'] = expires
              if method == 'POST' or method == 'PUT' or method == 'DELETE':
                  if params:
                      body = self.json(params)
                      auth += body
              headers['api-signature'] = self.hmac(self.encode(auth), self.encode(self.secret))
          return {'url': url, 'method': method, 'body': body, 'headers': headers}
  