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
  import math
  from ccxt.base.errors import ExchangeError
  from ccxt.base.errors import AuthenticationError
  from ccxt.base.errors import ArgumentsRequired
  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.errors import InvalidNonce
  from ccxt.base.decimal_to_precision import TICK_SIZE
  from ccxt.base.precise import Precise
  
  
  class currencycom(Exchange):
  
      def describe(self):
          return self.deep_extend(super(currencycom, self).describe(), {
              'id': 'currencycom',
              'name': 'Currency.com',
              'countries': ['BY'],  # Belarus
              'rateLimit': 500,
              'certified': True,
              'pro': True,
              'version': 'v1',
              # new metainfo interface
              'has': {
                  'cancelOrder': True,
                  'CORS': False,
                  'createOrder': True,
                  'fetchAccounts': True,
                  'fetchBalance': True,
                  'fetchMarkets': True,
                  'fetchMyTrades': True,
                  'fetchOHLCV': True,
                  'fetchOpenOrders': True,
                  'fetchOrderBook': True,
                  'fetchTicker': True,
                  'fetchTickers': True,
                  'fetchTime': True,
                  'fetchTradingFees': True,
                  'fetchTrades': True,
              },
              'timeframes': {
                  '1m': '1m',
                  '3m': '3m',
                  '5m': '5m',
                  '15m': '15m',
                  '30m': '30m',
                  '1h': '1h',
                  '4h': '4h',
                  '1d': '1d',
                  '1w': '1w',
              },
              'urls': {
                  'logo': 'https://user-images.githubusercontent.com/1294454/83718672-36745c00-a63e-11ea-81a9-677b1f789a4d.jpg',
                  'api': {
                      'public': 'https://api-adapter.backend.currency.com/api',
                      'private': 'https://api-adapter.backend.currency.com/api',
                  },
                  'www': 'https://www.currency.com',
                  'referral': 'https://currency.com/trading/signup?c=362jaimv&pid=referral',
                  'doc': [
                      'https://currency.com/api',
                  ],
                  'fees': 'https://currency.com/fees-charges',
              },
              'api': {
                  'public': {
                      'get': [
                          'time',
                          'exchangeInfo',
                          'depth',
                          'aggTrades',
                          'klines',
                          'ticker/24hr',
                      ],
                  },
                  'private': {
                      'get': [
                          'leverageSettings',
                          'openOrders',
                          'tradingPositions',
                          'account',
                          'myTrades',
                      ],
                      'post': [
                          'order',
                          'updateTradingPosition',
                          'updateTradingOrder',
                          'closeTradingPosition',
                      ],
                      'delete': [
                          'order',
                      ],
                  },
              },
              'fees': {
                  'trading': {
                      'feeSide': 'get',
                      'tierBased': False,
                      'percentage': True,
                      'taker': 0.002,
                      'maker': 0.002,
                  },
              },
              'precisionMode': TICK_SIZE,
              # exchange-specific options
              'options': {
                  'defaultTimeInForce': 'GTC',  # 'GTC' = Good To Cancel(default), 'IOC' = Immediate Or Cancel, 'FOK' = Fill Or Kill
                  'warnOnFetchOpenOrdersWithoutSymbol': True,
                  'recvWindow': 5 * 1000,  # 5 sec, default
                  'timeDifference': 0,  # the difference between system clock and Binance clock
                  'adjustForTimeDifference': False,  # controls the adjustment logic upon instantiation
                  'parseOrderToPrecision': False,  # force amounts and costs in parseOrder to precision
                  'newOrderRespType': {
                      'market': 'FULL',  # 'ACK' for order id, 'RESULT' for full order or 'FULL' for order with fills
                      'limit': 'RESULT',  # we change it from 'ACK' by default to 'RESULT'
                      'stop': 'RESULT',
                  },
              },
              'exceptions': {
                  'broad': {
                      'FIELD_VALIDATION_ERROR Cancel is available only for LIMIT order': InvalidOrder,
                      'API key does not exist': AuthenticationError,
                      'Order would trigger immediately.': InvalidOrder,
                      'Account has insufficient balance for requested action.': InsufficientFunds,
                      'Rest API trading is not enabled.': ExchangeNotAvailable,
                  },
                  'exact': {
                      '-1000': ExchangeNotAvailable,  # {"code":-1000,"msg":"An unknown error occured while processing the request."}
                      '-1013': InvalidOrder,  # createOrder -> 'invalid quantity'/'invalid price'/MIN_NOTIONAL
                      '-1021': InvalidNonce,  # 'your time is ahead of server'
                      '-1022': AuthenticationError,  # {"code":-1022,"msg":"Signature for self request is not valid."}
                      '-1100': InvalidOrder,  # createOrder(symbol, 1, asdf) -> 'Illegal characters found in parameter 'price'
                      '-1104': ExchangeError,  # Not all sent parameters were read, read 8 parameters but was sent 9
                      '-1025': AuthenticationError,  # {"code":-1025,"msg":"Invalid API-key, IP, or permissions for action"}
                      '-1128': BadRequest,  # {"code":-1128,"msg":"Combination of optional parameters invalid."}
                      '-2010': ExchangeError,  # generic error code for createOrder -> 'Account has insufficient balance for requested action.', {"code":-2010,"msg":"Rest API trading is not enabled."}, etc...
                      '-2011': OrderNotFound,  # cancelOrder(1, 'BTC/USDT') -> 'UNKNOWN_ORDER'
                      '-2013': OrderNotFound,  # fetchOrder(1, 'BTC/USDT') -> 'Order does not exist'
                      '-2014': AuthenticationError,  # {"code":-2014, "msg": "API-key format invalid."}
                      '-2015': AuthenticationError,  # "Invalid API-key, IP, or permissions for action."
                  },
              },
              'commonCurrencies': {
                  'IQ': 'iQIYI',
              },
          })
  
      def nonce(self):
          return self.milliseconds() - self.options['timeDifference']
  
      def fetch_time(self, params={}):
          response = self.publicGetTime(params)
          #
          #     {
          #         "serverTime": 1590998366609
          #     }
          #
          return self.safe_integer(response, 'serverTime')
  
      def load_time_difference(self, params={}):
          response = self.publicGetTime(params)
          after = self.milliseconds()
          self.options['timeDifference'] = int(after - response['serverTime'])
          return self.options['timeDifference']
  
      def fetch_markets(self, params={}):
          response = self.publicGetExchangeInfo(params)
          #
          #     {
          #         "timezone":"UTC",
          #         "serverTime":1603252990096,
          #         "rateLimits":[
          #             {"rateLimitType":"REQUEST_WEIGHT","interval":"MINUTE","intervalNum":1,"limit":1200},
          #             {"rateLimitType":"ORDERS","interval":"SECOND","intervalNum":1,"limit":10},
          #             {"rateLimitType":"ORDERS","interval":"DAY","intervalNum":1,"limit":864000},
          #         ],
          #         "exchangeFilters":[],
          #         "symbols":[
          #             {
          #                 "symbol":"EVK",
          #                 "name":"Evonik",
          #                 "status":"BREAK",
          #                 "baseAsset":"EVK",
          #                 "baseAssetPrecision":3,
          #                 "quoteAsset":"EUR",
          #                 "quoteAssetId":"EUR",
          #                 "quotePrecision":3,
          #                 "orderTypes":["LIMIT","MARKET"],
          #                 "filters":[
          #                     {"filterType":"LOT_SIZE","minQty":"1","maxQty":"27000","stepSize":"1"},
          #                     {"filterType":"MIN_NOTIONAL","minNotional":"23"}
          #                 ],
          #                 "marketType":"SPOT",
          #                 "country":"DE",
          #                 "sector":"Basic Materials",
          #                 "industry":"Diversified Chemicals",
          #                 "tradingHours":"UTC; Mon 07:02 - 15:30; Tue 07:02 - 15:30; Wed 07:02 - 15:30; Thu 07:02 - 15:30; Fri 07:02 - 15:30",
          #                 "tickSize":0.005,
          #                 "tickValue":0.11125,
          #                 "exchangeFee":0.05
          #             },
          #             {
          #                 "symbol":"BTC/USD_LEVERAGE",
          #                 "name":"Bitcoin / USD",
          #                 "status":"TRADING",
          #                 "baseAsset":"BTC",
          #                 "baseAssetPrecision":3,
          #                 "quoteAsset":"USD",
          #                 "quoteAssetId":"USD_LEVERAGE",
          #                 "quotePrecision":3,
          #                 "orderTypes":["LIMIT","MARKET","STOP"],
          #                 "filters":[
          #                     {"filterType":"LOT_SIZE","minQty":"0.001","maxQty":"100","stepSize":"0.001"},
          #                     {"filterType":"MIN_NOTIONAL","minNotional":"13"}
          #                 ],
          #                 "marketType":"LEVERAGE",
          #                 "longRate":-0.01,
          #                 "shortRate":0.01,
          #                 "swapChargeInterval":480,
          #                 "country":"",
          #                 "sector":"",
          #                 "industry":"",
          #                 "tradingHours":"UTC; Mon - 21:00, 21:05 -; Tue - 21:00, 21:05 -; Wed - 21:00, 21:05 -; Thu - 21:00, 21:05 -; Fri - 21:00, 22:01 -; Sat - 21:00, 21:05 -; Sun - 20:00, 21:05 -",
          #                 "tickSize":0.05,
          #                 "tickValue":610.20875,
          #                 "makerFee":-0.025,
          #                 "takerFee":0.075
          #             },
          #         ]
          #     }
          #
          if self.options['adjustForTimeDifference']:
              self.load_time_difference()
          markets = self.safe_value(response, 'symbols')
          result = []
          for i in range(0, len(markets)):
              market = markets[i]
              id = self.safe_string(market, 'symbol')
              baseId = self.safe_string(market, 'baseAsset')
              quoteId = self.safe_string(market, 'quoteAsset')
              base = self.safe_currency_code(baseId)
              quote = self.safe_currency_code(quoteId)
              symbol = base + '/' + quote
              if id.find('/') >= 0:
                  symbol = id
              filters = self.safe_value(market, 'filters', [])
              filtersByType = self.index_by(filters, 'filterType')
              precision = {
                  'amount': 1 / math.pow(1, self.safe_integer(market, 'baseAssetPrecision')),
                  'price': self.safe_number(market, 'tickSize'),
              }
              status = self.safe_string(market, 'status')
              active = (status == 'TRADING')
              type = self.safe_string_lower(market, 'marketType')
              if type == 'leverage':
                  type = 'margin'
              spot = (type == 'spot')
              margin = (type == 'margin')
              entry = {
                  'id': id,
                  'symbol': symbol,
                  'base': base,
                  'quote': quote,
                  'baseId': baseId,
                  'quoteId': quoteId,
                  'type': type,
                  'spot': spot,
                  'margin': margin,
                  'info': market,
                  'active': active,
                  'precision': precision,
                  'limits': {
                      'amount': {
                          'min': math.pow(10, -precision['amount']),
                          'max': None,
                      },
                      'price': {
                          'min': None,
                          'max': None,
                      },
                      'cost': {
                          'min': -math.log10(precision['amount']),
                          'max': None,
                      },
                  },
              }
              exchangeFee = self.safe_number_2(market, 'exchangeFee', 'tradingFee')
              makerFee = self.safe_number(market, 'makerFee', exchangeFee)
              takerFee = self.safe_number(market, 'takerFee', exchangeFee)
              if makerFee is not None:
                  entry['maker'] = makerFee / 100
              if takerFee is not None:
                  entry['taker'] = takerFee / 100
              if 'PRICE_FILTER' in filtersByType:
                  filter = self.safe_value(filtersByType, 'PRICE_FILTER', {})
                  entry['precision']['price'] = self.safe_number(filter, 'tickSize')
                  # PRICE_FILTER reports zero values for maxPrice
                  # since they updated filter types in November 2018
                  # https://github.com/ccxt/ccxt/issues/4286
                  # therefore limits['price']['max'] doesn't have any meaningful value except None
                  entry['limits']['price'] = {
                      'min': self.safe_number(filter, 'minPrice'),
                      'max': None,
                  }
                  maxPrice = self.safe_number(filter, 'maxPrice')
                  if (maxPrice is not None) and (maxPrice > 0):
                      entry['limits']['price']['max'] = maxPrice
              if 'LOT_SIZE' in filtersByType:
                  filter = self.safe_value(filtersByType, 'LOT_SIZE', {})
                  entry['precision']['amount'] = self.safe_number(filter, 'stepSize')
                  entry['limits']['amount'] = {
                      'min': self.safe_number(filter, 'minQty'),
                      'max': self.safe_number(filter, 'maxQty'),
                  }
              if 'MARKET_LOT_SIZE' in filtersByType:
                  filter = self.safe_value(filtersByType, 'MARKET_LOT_SIZE', {})
                  entry['limits']['market'] = {
                      'min': self.safe_number(filter, 'minQty'),
                      'max': self.safe_number(filter, 'maxQty'),
                  }
              if 'MIN_NOTIONAL' in filtersByType:
                  filter = self.safe_value(filtersByType, 'MIN_NOTIONAL', {})
                  entry['limits']['cost']['min'] = self.safe_number(filter, 'minNotional')
              result.append(entry)
          return result
  
      def fetch_accounts(self, params={}):
          response = self.privateGetAccount(params)
          #
          #     {
          #         "makerCommission":0.20,
          #         "takerCommission":0.20,
          #         "buyerCommission":0.20,
          #         "sellerCommission":0.20,
          #         "canTrade":true,
          #         "canWithdraw":true,
          #         "canDeposit":true,
          #         "updateTime":1591056268,
          #         "balances":[
          #             {
          #                 "accountId":5470306579272968,
          #                 "collateralCurrency":true,
          #                 "asset":"ETH",
          #                 "free":0.0,
          #                 "locked":0.0,
          #                 "default":false,
          #             },
          #         ]
          #     }
          #
          accounts = self.safe_value(response, 'balances', [])
          result = []
          for i in range(0, len(accounts)):
              account = accounts[i]
              accountId = self.safe_integer(account, 'accountId')
              currencyId = self.safe_string(account, 'asset')
              currencyCode = self.safe_currency_code(currencyId)
              result.append({
                  'id': accountId,
                  'type': None,
                  'currency': currencyCode,
                  'info': response,
              })
          return result
  
      def fetch_trading_fees(self, params={}):
          self.load_markets()
          response = self.privateGetAccount(params)
          return {
              'info': response,
              'maker': self.safe_number(response, 'makerCommission'),
              'taker': self.safe_number(response, 'takerCommission'),
          }
  
      def parse_balance_response(self, response):
          #
          #     {
          #         "makerCommission":0.20,
          #         "takerCommission":0.20,
          #         "buyerCommission":0.20,
          #         "sellerCommission":0.20,
          #         "canTrade":true,
          #         "canWithdraw":true,
          #         "canDeposit":true,
          #         "updateTime":1591056268,
          #         "balances":[
          #             {
          #                 "accountId":5470306579272968,
          #                 "collateralCurrency":true,
          #                 "asset":"ETH",
          #                 "free":0.0,
          #                 "locked":0.0,
          #                 "default":false,
          #             },
          #         ]
          #     }
          #
          result = {'info': response}
          balances = self.safe_value(response, 'balances', [])
          for i in range(0, len(balances)):
              balance = balances[i]
              currencyId = self.safe_string(balance, 'asset')
              code = self.safe_currency_code(currencyId)
              account = self.account()
              account['free'] = self.safe_string(balance, 'free')
              account['used'] = self.safe_string(balance, 'locked')
              result[code] = account
          return self.parse_balance(result, False)
  
      def fetch_balance(self, params={}):
          self.load_markets()
          response = self.privateGetAccount(params)
          #
          #     {
          #         "makerCommission":0.20,
          #         "takerCommission":0.20,
          #         "buyerCommission":0.20,
          #         "sellerCommission":0.20,
          #         "canTrade":true,
          #         "canWithdraw":true,
          #         "canDeposit":true,
          #         "updateTime":1591056268,
          #         "balances":[
          #             {
          #                 "accountId":5470306579272968,
          #                 "collateralCurrency":true,
          #                 "asset":"ETH",
          #                 "free":0.0,
          #                 "locked":0.0,
          #                 "default":false,
          #             },
          #         ]
          #     }
          #
          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['limit'] = limit  # default 100, max 1000, valid limits 5, 10, 20, 50, 100, 500, 1000, 5000
          response = self.publicGetDepth(self.extend(request, params))
          #
          #     {
          #         "lastUpdateId":1590999849037,
          #         "asks":[
          #             [0.02495,60.0000],
          #             [0.02496,120.0000],
          #             [0.02497,240.0000],
          #         ],
          #         "bids":[
          #             [0.02487,60.0000],
          #             [0.02486,120.0000],
          #             [0.02485,240.0000],
          #         ]
          #     }
          #
          orderbook = self.parse_order_book(response)
          orderbook['nonce'] = self.safe_integer(response, 'lastUpdateId')
          return orderbook
  
      def parse_ticker(self, ticker, market=None):
          #
          # fetchTicker
          #
          #     {
          #         "symbol":"ETH/BTC",
          #         "priceChange":"0.00030",
          #         "priceChangePercent":"1.21",
          #         "weightedAvgPrice":"0.02481",
          #         "prevClosePrice":"0.02447",
          #         "lastPrice":"0.02477",
          #         "lastQty":"60.0",
          #         "bidPrice":"0.02477",
          #         "askPrice":"0.02484",
          #         "openPrice":"0.02447",
          #         "highPrice":"0.02524",
          #         "lowPrice":"0.02438",
          #         "volume":"11.97",
          #         "quoteVolume":"0.298053",
          #         "openTime":1590969600000,
          #         "closeTime":1591000072693
          #     }
          #
          # fetchTickers
          #
          #     {
          #         "symbol":"EVK",
          #         "highPrice":"22.57",
          #         "lowPrice":"22.16",
          #         "volume":"1",
          #         "quoteVolume":"22.2",
          #         "openTime":1590699364000,
          #         "closeTime":1590785764000
          #     }
          #
          timestamp = self.safe_integer(ticker, 'closeTime')
          marketId = self.safe_string(ticker, 'symbol')
          symbol = self.safe_symbol(marketId, market)
          last = self.safe_number(ticker, 'lastPrice')
          open = self.safe_number(ticker, 'openPrice')
          average = None
          if (open is not None) and (last is not None):
              average = self.sum(open, last) / 2
          return {
              'symbol': symbol,
              'timestamp': timestamp,
              'datetime': self.iso8601(timestamp),
              'high': self.safe_number(ticker, 'highPrice'),
              'low': self.safe_number(ticker, 'lowPrice'),
              'bid': self.safe_number(ticker, 'bidPrice'),
              'bidVolume': self.safe_number(ticker, 'bidQty'),
              'ask': self.safe_number(ticker, 'askPrice'),
              'askVolume': self.safe_number(ticker, 'askQty'),
              'vwap': self.safe_number(ticker, 'weightedAvgPrice'),
              'open': open,
              'close': last,
              'last': last,
              'previousClose': self.safe_number(ticker, 'prevClosePrice'),  # previous day close
              'change': self.safe_number(ticker, 'priceChange'),
              'percentage': self.safe_number(ticker, 'priceChangePercent'),
              'average': average,
              'baseVolume': self.safe_number(ticker, 'volume'),
              'quoteVolume': self.safe_number(ticker, 'quoteVolume'),
              'info': ticker,
          }
  
      def fetch_ticker(self, symbol, params={}):
          self.load_markets()
          market = self.market(symbol)
          request = {
              'symbol': market['id'],
          }
          response = self.publicGetTicker24hr(self.extend(request, params))
          #
          #     {
          #         "symbol":"ETH/BTC",
          #         "priceChange":"0.00030",
          #         "priceChangePercent":"1.21",
          #         "weightedAvgPrice":"0.02481",
          #         "prevClosePrice":"0.02447",
          #         "lastPrice":"0.02477",
          #         "lastQty":"60.0",
          #         "bidPrice":"0.02477",
          #         "askPrice":"0.02484",
          #         "openPrice":"0.02447",
          #         "highPrice":"0.02524",
          #         "lowPrice":"0.02438",
          #         "volume":"11.97",
          #         "quoteVolume":"0.298053",
          #         "openTime":1590969600000,
          #         "closeTime":1591000072693
          #     }
          #
          return self.parse_ticker(response, market)
  
      def fetch_tickers(self, symbols=None, params={}):
          self.load_markets()
          response = self.publicGetTicker24hr(params)
          #
          #     [
          #         {
          #             "symbol":"EVK",
          #             "highPrice":"22.57",
          #             "lowPrice":"22.16",
          #             "volume":"1",
          #             "quoteVolume":"22.2",
          #             "openTime":1590699364000,
          #             "closeTime":1590785764000
          #         }
          #     ]
          #
          return self.parse_tickers(response, symbols)
  
      def parse_ohlcv(self, ohlcv, market=None):
          #
          #     [
          #         1590971040000,
          #         "0.02454",
          #         "0.02456",
          #         "0.02452",
          #         "0.02456",
          #         249
          #     ]
          #
          return [
              self.safe_integer(ohlcv, 0),
              self.safe_number(ohlcv, 1),
              self.safe_number(ohlcv, 2),
              self.safe_number(ohlcv, 3),
              self.safe_number(ohlcv, 4),
              self.safe_number(ohlcv, 5),
          ]
  
      def fetch_ohlcv(self, symbol, timeframe='1m', since=None, limit=None, params={}):
          self.load_markets()
          market = self.market(symbol)
          request = {
              'symbol': market['id'],
              'interval': self.timeframes[timeframe],
          }
          if since is not None:
              request['startTime'] = since
          if limit is not None:
              request['limit'] = limit  # default 500, max 1000
          response = self.publicGetKlines(self.extend(request, params))
          #
          #     [
          #         [1590971040000,"0.02454","0.02456","0.02452","0.02456",249],
          #         [1590971100000,"0.02455","0.02457","0.02452","0.02456",300],
          #         [1590971160000,"0.02455","0.02456","0.02453","0.02454",286],
          #     ]
          #
          return self.parse_ohlcvs(response, market, timeframe, since, limit)
  
      def parse_trade(self, trade, market=None):
          #
          # fetchTrades(public aggregate trades)
          #
          #     {
          #         "a":1658318071,
          #         "p":"0.02476",
          #         "q":"0.0",
          #         "T":1591001423382,
          #         "m":false
          #     }
          #
          # createOrder fills(private)
          #
          #     {
          #         "price": "9807.05",
          #         "qty": "0.01",
          #         "commission": "0",
          #         "commissionAsset": "dUSD"
          #     }
          #
          # fetchMyTrades
          #
          #     {
          #         "symbol": "BNBBTC",
          #         "id": 28457,
          #         "orderId": 100234,
          #         "price": "4.00000100",
          #         "qty": "12.00000000",
          #         "commission": "10.10000000",
          #         "commissionAsset": "BNB",
          #         "time": 1499865549590,
          #         "isBuyer": True,
          #         "isMaker": False,
          #         "isBestMatch": True
          #     }
          #
          timestamp = self.safe_integer_2(trade, 'T', 'time')
          priceString = self.safe_string_2(trade, 'p', 'price')
          amountString = self.safe_string_2(trade, 'q', 'qty')
          price = self.parse_number(priceString)
          amount = self.parse_number(amountString)
          cost = self.parse_number(Precise.string_mul(priceString, amountString))
          id = self.safe_string_2(trade, 'a', 'id')
          side = None
          orderId = self.safe_string(trade, 'orderId')
          if 'm' in trade:
              side = 'sell' if trade['m'] else 'buy'  # self is reversed intentionally
          elif 'isBuyerMaker' in trade:
              side = 'sell' if trade['isBuyerMaker'] else 'buy'
          else:
              if 'isBuyer' in trade:
                  side = 'buy' if (trade['isBuyer']) else 'sell'  # self is a True side
          fee = None
          if 'commission' in trade:
              fee = {
                  'cost': self.safe_number(trade, 'commission'),
                  'currency': self.safe_currency_code(self.safe_string(trade, 'commissionAsset')),
              }
          takerOrMaker = None
          if 'isMaker' in trade:
              takerOrMaker = 'maker' if trade['isMaker'] else 'taker'
          marketId = self.safe_string(trade, 'symbol')
          symbol = self.safe_symbol(marketId, market)
          return {
              'info': trade,
              'timestamp': timestamp,
              'datetime': self.iso8601(timestamp),
              'symbol': symbol,
              'id': id,
              'order': orderId,
              'type': None,
              'takerOrMaker': takerOrMaker,
              'side': side,
              'price': price,
              'amount': amount,
              'cost': cost,
              'fee': fee,
          }
  
      def fetch_trades(self, symbol, since=None, limit=None, params={}):
          self.load_markets()
          market = self.market(symbol)
          request = {
              'symbol': market['id'],
              # 'limit': 500,  # default 500, max 1000
          }
          if limit is not None:
              request['limit'] = limit  # default 500, max 1000
          response = self.publicGetAggTrades(self.extend(request, params))
          #
          #     [
          #         {
          #             "a":1658318071,
          #             "p":"0.02476",
          #             "q":"0.0",
          #             "T":1591001423382,
          #             "m":false
          #         }
          #     ]
          #
          return self.parse_trades(response, market, since, limit)
  
      def parse_order_status(self, status):
          statuses = {
              'NEW': 'open',
              'PARTIALLY_FILLED': 'open',
              'FILLED': 'closed',
              'CANCELED': 'canceled',
              'PENDING_CANCEL': 'canceling',  # currently unused
              'REJECTED': 'rejected',
              'EXPIRED': 'expired',
          }
          return self.safe_string(statuses, status, status)
  
      def parse_order(self, order, market=None):
          #
          #     {
          #         "symbol": "BTC/USD",
          #         "orderId": "00000000-0000-0000-0000-0000000c0263",
          #         "clientOrderId": "00000000-0000-0000-0000-0000000c0263",
          #         "transactTime": 1589878206426,
          #         "price": "9825.66210000",
          #         "origQty": "0.01",
          #         "executedQty": "0.01",
          #         "status": "FILLED",
          #         "timeInForce": "FOK",
          #         "type": "MARKET",
          #         "side": "BUY",
          #         "fills": [
          #             {
          #                 "price": "9807.05",
          #                 "qty": "0.01",
          #                 "commission": "0",
          #                 "commissionAsset": "dUSD"
          #             }
          #         ]
          #     }
          #
          status = self.parse_order_status(self.safe_string(order, 'status'))
          marketId = self.safe_string(order, 'symbol')
          symbol = self.safe_symbol(marketId, market, '/')
          timestamp = None
          if 'time' in order:
              timestamp = self.safe_integer(order, 'time')
          elif 'transactTime' in order:
              timestamp = self.safe_integer(order, 'transactTime')
          price = self.safe_number(order, 'price')
          amount = self.safe_number(order, 'origQty')
          filled = self.safe_number(order, 'executedQty')
          remaining = None
          cost = self.safe_number(order, 'cummulativeQuoteQty')
          id = self.safe_string(order, 'orderId')
          type = self.safe_string_lower(order, 'type')
          side = self.safe_string_lower(order, 'side')
          trades = None
          fills = self.safe_value(order, 'fills')
          if fills is not None:
              trades = self.parse_trades(fills, market)
          timeInForce = self.safe_string(order, 'timeInForce')
          return self.safe_order({
              'info': order,
              'id': id,
              'timestamp': timestamp,
              'datetime': self.iso8601(timestamp),
              'lastTradeTimestamp': None,
              'symbol': symbol,
              'type': type,
              'timeInForce': timeInForce,
              'side': side,
              'price': price,
              'stopPrice': None,
              'amount': amount,
              'cost': cost,
              'average': None,
              'filled': filled,
              'remaining': remaining,
              'status': status,
              'fee': None,
              'trades': trades,
          })
  
      def create_order(self, symbol, type, side, amount, price=None, params={}):
          self.load_markets()
          market = self.market(symbol)
          accountId = None
          if market['margin']:
              accountId = self.safe_integer(params, 'accountId')
              if accountId is None:
                  raise ArgumentsRequired(self.id + ' createOrder() requires an accountId parameter for ' + market['type'] + ' market ' + symbol)
          uppercaseType = type.upper()
          newOrderRespType = self.safe_value(self.options['newOrderRespType'], type, 'RESULT')
          request = {
              'symbol': market['id'],
              'quantity': self.amount_to_precision(symbol, amount),
              'type': uppercaseType,
              'side': side.upper(),
              'newOrderRespType': newOrderRespType,  # 'RESULT' for full order or 'FULL' for order with fills
              # 'leverage': 1,
              # 'accountId': 5470306579272968,  # required for leverage markets
              # 'takeProfit': '123.45',
              # 'stopLoss': '54.321'
              # 'guaranteedStopLoss': '54.321',
          }
          if uppercaseType == 'LIMIT':
              request['price'] = self.price_to_precision(symbol, price)
              request['timeInForce'] = self.options['defaultTimeInForce']  # 'GTC' = Good To Cancel(default), 'IOC' = Immediate Or Cancel, 'FOK' = Fill Or Kill
          elif uppercaseType == 'STOP':
              request['price'] = self.price_to_precision(symbol, price)
          response = self.privatePostOrder(self.extend(request, params))
          #
          #     {
          #         "symbol": "BTC/USD",
          #         "orderId": "00000000-0000-0000-0000-0000000c0263",
          #         "clientOrderId": "00000000-0000-0000-0000-0000000c0263",
          #         "transactTime": 1589878206426,
          #         "price": "9825.66210000",
          #         "origQty": "0.01",
          #         "executedQty": "0.01",
          #         "status": "FILLED",
          #         "timeInForce": "FOK",
          #         "type": "MARKET",
          #         "side": "BUY",
          #         "fills": [
          #             {
          #                 "price": "9807.05",
          #                 "qty": "0.01",
          #                 "commission": "0",
          #                 "commissionAsset": "dUSD"
          #             }
          #         ]
          #     }
          #
          return self.parse_order(response, market)
  
      def fetch_open_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']
          elif self.options['warnOnFetchOpenOrdersWithoutSymbol']:
              symbols = self.symbols
              numSymbols = len(symbols)
              fetchOpenOrdersRateLimit = int(numSymbols / 2)
              raise ExchangeError(self.id + ' fetchOpenOrders() WARNING: fetching open orders without specifying a symbol is rate-limited to one call per ' + str(fetchOpenOrdersRateLimit) + ' seconds. Do not call self method frequently to avoid ban. Set ' + self.id + '.options["warnOnFetchOpenOrdersWithoutSymbol"] = False to suppress self warning message.')
          response = self.privateGetOpenOrders(self.extend(request, params))
          return self.parse_orders(response, market, since, limit)
  
      def cancel_order(self, id, symbol=None, params={}):
          if symbol is None:
              raise ArgumentsRequired(self.id + ' cancelOrder() requires a symbol argument')
          self.load_markets()
          market = self.market(symbol)
          origClientOrderId = self.safe_value(params, 'origClientOrderId')
          request = {
              'symbol': market['id'],
              # 'orderId': int(id),
              # 'origClientOrderId': id,
          }
          if origClientOrderId is None:
              request['orderId'] = id
          else:
              request['origClientOrderId'] = origClientOrderId
          response = self.privateDeleteOrder(self.extend(request, params))
          #
          #     {
          #         "symbol":"ETH/USD",
          #         "orderId":"00000000-0000-0000-0000-00000024383b",
          #         "clientOrderId":"00000000-0000-0000-0000-00000024383b",
          #         "price":"150",
          #         "origQty":"0.1",
          #         "executedQty":"0.0",
          #         "status":"CANCELED",
          #         "timeInForce":"GTC",
          #         "type":"LIMIT",
          #         "side":"BUY"
          #     }
          #
          return self.parse_order(response, market)
  
      def fetch_my_trades(self, symbol=None, since=None, limit=None, params={}):
          if symbol is None:
              raise ArgumentsRequired(self.id + ' fetchMyTrades() requires a symbol argument')
          self.load_markets()
          market = self.market(symbol)
          request = {
              'symbol': market['id'],
          }
          if limit is not None:
              request['limit'] = limit
          response = self.privateGetMyTrades(self.extend(request, params))
          #
          #     [
          #         {
          #             "symbol": "BNBBTC",
          #             "id": 28457,
          #             "orderId": 100234,
          #             "price": "4.00000100",
          #             "qty": "12.00000000",
          #             "commission": "10.10000000",
          #             "commissionAsset": "BNB",
          #             "time": 1499865549590,
          #             "isBuyer": True,
          #             "isMaker": False,
          #             "isBestMatch": True
          #         }
          #     ]
          #
          return self.parse_trades(response, market, since, limit)
  
      def sign(self, path, api='public', method='GET', params={}, headers=None, body=None):
          url = self.urls['api'][api] + '/' + self.version + '/' + path
          if path == 'historicalTrades':
              headers = {
                  'X-MBX-APIKEY': self.apiKey,
              }
          if api == 'private':
              self.check_required_credentials()
              query = self.urlencode(self.extend({
                  'timestamp': self.nonce(),
                  'recvWindow': self.options['recvWindow'],
              }, params))
              signature = self.hmac(self.encode(query), self.encode(self.secret))
              query += '&' + 'signature=' + signature
              headers = {
                  'X-MBX-APIKEY': self.apiKey,
              }
              if (method == 'GET') or (method == 'DELETE'):
                  url += '?' + query
              else:
                  body = query
                  headers['Content-Type'] = 'application/x-www-form-urlencoded'
          else:
              if params:
                  url += '?' + self.urlencode(params)
          return {'url': url, 'method': method, 'body': body, 'headers': headers}
  
      def handle_errors(self, httpCode, reason, url, method, headers, body, response, requestHeaders, requestBody):
          if (httpCode == 418) or (httpCode == 429):
              raise DDoSProtection(self.id + ' ' + str(httpCode) + ' ' + reason + ' ' + body)
          # error response in a form: {"code": -1013, "msg": "Invalid quantity."}
          # following block cointains legacy checks against message patterns in "msg" property
          # will switch "code" checks eventually, when we know all of them
          if httpCode >= 400:
              if body.find('Price * QTY is zero or less') >= 0:
                  raise InvalidOrder(self.id + ' order cost = amount * price is zero or less ' + body)
              if body.find('LOT_SIZE') >= 0:
                  raise InvalidOrder(self.id + ' order amount should be evenly divisible by lot size ' + body)
              if body.find('PRICE_FILTER') >= 0:
                  raise InvalidOrder(self.id + ' order price is invalid, i.e. exceeds allowed price precision, exceeds min price or max price limits or is invalid float value in general, use self.price_to_precision(symbol, amount) ' + body)
          if response is None:
              return  # fallback to default error handler
          #
          #     {"code":-1128,"msg":"Combination of optional parameters invalid."}
          #
          errorCode = self.safe_string(response, 'code')
          if (errorCode is not None) and (errorCode != '0'):
              feedback = self.id + ' ' + self.json(response)
              self.throw_exactly_matched_exception(self.exceptions['exact'], errorCode, feedback)
              message = self.safe_string(response, 'msg')
              self.throw_broadly_matched_exception(self.exceptions['broad'], message, feedback)
              raise ExchangeError(feedback)
  