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 hashlib
  import math
  from ccxt.base.errors import ExchangeError
  from ccxt.base.errors import AuthenticationError
  from ccxt.base.errors import AccountSuspended
  from ccxt.base.errors import BadRequest
  from ccxt.base.errors import BadSymbol
  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.errors import RequestTimeout
  from ccxt.base.decimal_to_precision import TICK_SIZE
  from ccxt.base.precise import Precise
  
  
  class crex24(Exchange):
  
      def describe(self):
          return self.deep_extend(super(crex24, self).describe(), {
              'id': 'crex24',
              'name': 'CREX24',
              'countries': ['EE'],  # Estonia
              'rateLimit': 500,
              'version': 'v2',
              # new metainfo interface
              'has': {
                  'cancelAllOrders': True,
                  'cancelOrder': True,
                  'CORS': None,
                  'createOrder': True,
                  'editOrder': True,
                  'fetchBalance': True,
                  'fetchBidsAsks': True,
                  'fetchClosedOrders': True,
                  'fetchCurrencies': True,
                  'fetchDepositAddress': True,
                  'fetchDeposits': True,
                  'fetchFundingFees': True,
                  'fetchMarkets': True,
                  'fetchMyTrades': True,
                  'fetchOHLCV': True,
                  'fetchOpenOrders': True,
                  'fetchOrder': True,
                  'fetchOrderBook': True,
                  'fetchOrders': True,
                  'fetchOrderTrades': True,
                  'fetchTicker': True,
                  'fetchTickers': True,
                  'fetchTrades': True,
                  'fetchTradingFee': None,  # actually, True, but will be implemented later
                  'fetchTradingFees': None,  # actually, True, but will be implemented later
                  'fetchTransactions': True,
                  'fetchWithdrawals': True,
                  'withdraw': True,
              },
              'timeframes': {
                  '1m': '1m',
                  '3m': '3m',
                  '5m': '5m',
                  '15m': '15m',
                  '30m': '30m',
                  '1h': '1h',
                  '4h': '4h',
                  '1d': '1d',
                  '1w': '1w',
                  '1M': '1mo',
              },
              'urls': {
                  'logo': 'https://user-images.githubusercontent.com/1294454/47813922-6f12cc00-dd5d-11e8-97c6-70f957712d47.jpg',
                  'api': 'https://api.crex24.com',
                  'www': 'https://crex24.com',
                  'referral': 'https://crex24.com/?refid=slxsjsjtil8xexl9hksr',
                  'doc': 'https://docs.crex24.com/trade-api/v2',
                  'fees': 'https://crex24.com/fees',
              },
              'api': {
                  'public': {
                      'get': [
                          'currencies',
                          'instruments',
                          'tickers',
                          'recentTrades',
                          'orderBook',
                          'ohlcv',
                          'tradingFeeSchedules',
                          'withdrawalFees',
                          'currencyTransport',
                          'currenciesWithdrawalFees',
                      ],
                  },
                  'trading': {
                      'get': [
                          'orderStatus',
                          'orderTrades',
                          'activeOrders',
                          'orderHistory',
                          'tradeHistory',
                          'tradingFee',
                          'tradeFee',  # The support of self method has been dropped on February 18, 2020. Please, use tradingFee method instead. https://docs.crex24.com/trade-api/v2/#trade-fee-and-rebate-discontinued
                      ],
                      'post': [
                          'placeOrder',
                          'modifyOrder',
                          'cancelOrdersById',
                          'cancelOrdersByInstrument',
                          'cancelAllOrders',
                      ],
                  },
                  'account': {
                      'get': [
                          'balance',
                          'depositAddress',
                          'moneyTransfers',
                          'moneyTransferStatus',
                          'previewWithdrawal',
                      ],
                      'post': [
                          'withdraw',
                      ],
                  },
              },
              'precisionMode': TICK_SIZE,
              'fees': {
                  'trading': {
                      'tierBased': True,
                      'percentage': True,
                      'taker': 0.001,
                      'maker': -0.0001,
                  },
                  # should be deleted, these are outdated and inaccurate
                  'funding': {
                      'tierBased': False,
                      'percentage': False,
                      'withdraw': {},
                      'deposit': {},
                  },
              },
              'commonCurrencies': {
                  'ACM': 'Actinium',
                  'BCC': 'BCH',
                  'BIT': 'BitMoney',
                  'BULL': 'BuySell',
                  'CLC': 'CaluraCoin',
                  'CREDIT': 'TerraCredit',
                  'EGG': 'NestEGG Coin',
                  'EPS': 'Epanus',  # conflict with EPS Ellipsis https://github.com/ccxt/ccxt/issues/8909
                  'FUND': 'FUNDChains',
                  'GHOST': 'GHOSTPRISM',
                  'GTC': 'GastroCoin',  # conflict with Gitcoin and Game.com
                  'IQ': 'IQ.Cash',
                  'ONE': 'One Hundred Coin',
                  'PUT': 'PutinCoin',
                  'SBTC': 'SBTCT',  # SiamBitcoin
                  'UNI': 'Universe',
                  'YOYO': 'YOYOW',
              },
              # exchange-specific options
              'options': {
                  'networks': {
                      'ETH': 'ERC20',
                      'TRX': 'TRC20',
                      'BSC': 'BEP20',
                  },
                  'fetchOrdersMethod': 'tradingGetOrderHistory',  # or 'tradingGetActiveOrders'
                  'fetchClosedOrdersMethod': 'tradingGetOrderHistory',  # or 'tradingGetActiveOrders'
                  'fetchTickersMethod': 'publicGetTicker24hr',
                  'defaultTimeInForce': 'GTC',  # 'GTC' = Good To Cancel(default), 'IOC' = Immediate Or Cancel
                  'hasAlreadyAuthenticatedSuccessfully': False,
                  'warnOnFetchOpenOrdersWithoutSymbol': True,
                  'parseOrderToPrecision': False,  # force amounts and costs in parseOrder to precision
                  'newOrderRespType': 'RESULT',  # 'ACK' for order id, 'RESULT' for full order or 'FULL' for order with fills
              },
              'exceptions': {
                  'exact': {
                      "Parameter 'filter' contains invalid value.": BadRequest,  # eslint-disable-quotes
                      "Mandatory parameter 'instrument' is missing.": BadRequest,  # eslint-disable-quotes
                      "The value of parameter 'till' must be greater than or equal to the value of parameter 'from'.": BadRequest,  # eslint-disable-quotes
                      'Failed to verify request signature.': AuthenticationError,  # eslint-disable-quotes
                      "Nonce error. Make sure that the value passed in the 'X-CREX24-API-NONCE' header is greater in each consecutive request than in the previous one for the corresponding API-Key provided in 'X-CREX24-API-KEY' header.": InvalidNonce,
                      'Market orders are not supported by the instrument currently.': InvalidOrder,
                      "Parameter 'instrument' contains invalid value.": BadSymbol,
                      "Trading has been disabled for the account until the verification is passed. To initiate the verification process, please log into your account at crex24.com and proceed to 'My account' -> 'Verification'.": AccountSuspended,  # {"errorDescription":"Trading has been disabled for the account until the verification is passed. To initiate the verification process, please log into your account at crex24.com and proceed to 'My account' -> 'Verification'."}
                  },
                  'broad': {
                      'try again later': ExchangeNotAvailable,  # {"errorDescription":"Failed to process the request. Please, try again later."}
                      'API Key': AuthenticationError,  # "API Key '9edc48de-d5b0-4248-8e7e-f59ffcd1c7f1' doesn't exist."
                      'Insufficient funds': InsufficientFunds,  # "Insufficient funds: new order requires 10 ETH which is more than the available balance."
                      'has been delisted.': BadSymbol,  # {"errorDescription":"Instrument '$PAC-BTC' has been delisted."}
                      'is currently suspended.': BadSymbol,  # {"errorDescription":"Trading in BITG-BTC is currently suspended."}
                      'Mandatory parameter': BadRequest,  # {"errorDescription":"Mandatory parameter 'feeCurrency' is missing."}
                      'can not trade': AccountSuspended,  # {"errorDescription":"User 123456 can not trade"}
                  },
              },
          })
  
      def nonce(self):
          return self.milliseconds()
  
      def fetch_markets(self, params={}):
          response = self.publicGetInstruments(params)
          #
          #         [{
          #             "symbol": "$PAC-BTC",
          #             "baseCurrency": "$PAC",
          #             "quoteCurrency": "BTC",
          #             "feeCurrency": "BTC",
          #             "feeSchedule": "OriginalSchedule",
          #             "tickSize": 0.00000001,
          #             "minPrice": 0.00000001,
          #             "maxPrice": 10000000000.0,
          #             "volumeIncrement": 0.00000001,
          #             "minVolume": 1.0,
          #             "maxVolume": 1000000000.0,
          #             "minQuoteVolume": 0.000000000000001,
          #             "maxQuoteVolume": 100000000000.0,
          #             "supportedOrderTypes": [
          #               "limit"
          #             ],
          #             "state": "delisted"
          #           },
          #           {
          #             "symbol": "1INCH-USDT",
          #             "baseCurrency": "1INCH",
          #             "quoteCurrency": "USDT",
          #             "feeCurrency": "USDT",
          #             "feeSchedule": "FeeSchedule10",
          #             "tickSize": 0.0001,
          #             "minPrice": 0.0001,
          #             "maxPrice": 10000000000.0,
          #             "volumeIncrement": 0.00000001,
          #             "minVolume": 0.01,
          #             "maxVolume": 1000000000.0,
          #             "minQuoteVolume": 0.000000000000001,
          #             "maxQuoteVolume": 100000000000.0,
          #             "supportedOrderTypes": [
          #               "limit"
          #             ],
          #             "state": "active"
          #           },]
          #
          response2 = self.publicGetTradingFeeSchedules(params)
          #
          #     [
          #         {
          #             "name": "FeeSchedule05",
          #             "feeRates": [
          #                 {
          #                     "volumeThreshold": 0.0,
          #                     "maker": 0.0005,
          #                     "taker": 0.0005
          #                 },
          #                 {
          #                     "volumeThreshold": 5.0,
          #                     "maker": 0.0004,
          #                     "taker": 0.0004
          #                 },
          #                 {
          #                     "volumeThreshold": 15.0,
          #                     "maker": 0.0003,
          #                     "taker": 0.0003
          #                 },
          #                 {
          #                     "volumeThreshold": 30.0,
          #                     "maker": 0.0002,
          #                     "taker": 0.0002
          #                 },
          #                 {
          #                     "volumeThreshold": 50.0,
          #                     "maker": 0.0001,
          #                     "taker": 0.0001
          #                 }
          #             ]
          #         },
          #     ]
          #
          result = []
          for i in range(0, len(response)):
              market = response[i]
              id = self.safe_string(market, 'symbol')
              baseId = self.safe_string(market, 'baseCurrency')
              quoteId = self.safe_string(market, 'quoteCurrency')
              base = self.safe_currency_code(baseId)
              quote = self.safe_currency_code(quoteId)
              symbol = base + '/' + quote
              tickSize = self.safe_number(market, 'tickSize')
              minPrice = self.safe_number(market, 'minPrice')
              maxPrice = self.safe_number(market, 'maxPrice')
              minAmount = self.safe_number(market, 'minVolume')
              maxAmount = self.safe_number(market, 'maxVolume')
              minCost = self.safe_number(market, 'minQuoteVolume')
              maxCost = self.safe_number(market, 'maxQuoteVolume')
              precision = {
                  'amount': minAmount,
                  'price': tickSize,
              }
              maker = None
              taker = None
              feeSchedule = self.safe_string(market, 'feeSchedule')
              for j in range(0, len(response2)):
                  feeScheduleName = self.safe_string(response2[j], 'name')
                  if feeScheduleName == feeSchedule:
                      feeRates = self.safe_value(response2[j], 'feeRates', [])
                      for k in range(0, len(feeRates)):
                          volumeThreshold = self.safe_number(feeRates[k], 'volumeThreshold')
                          if volumeThreshold == 0:
                              maker = self.safe_number(feeRates[k], 'maker')
                              taker = self.safe_number(feeRates[k], 'taker')
                              break
                      break
              active = (market['state'] == 'active')
              result.append({
                  'id': id,
                  'symbol': symbol,
                  'base': base,
                  'quote': quote,
                  'baseId': baseId,
                  'quoteId': quoteId,
                  'info': market,
                  'type': 'spot',
                  'spot': True,
                  'active': active,
                  'precision': precision,
                  'maker': maker,
                  'taker': taker,
                  'limits': {
                      'amount': {
                          'min': minAmount,
                          'max': maxAmount,
                      },
                      'price': {
                          'min': minPrice,
                          'max': maxPrice,
                      },
                      'cost': {
                          'min': minCost,
                          'max': maxCost,
                      },
                  },
              })
          return result
  
      def fetch_currencies(self, params={}):
          response = self.publicGetCurrencies(params)
          #
          #     [{                  symbol: "$PAC",
          #                             name: "PACCoin",
          #                           isFiat:  False,
          #                  depositsAllowed:  True,
          #         depositConfirmationCount:  8,
          #                       minDeposit:  0,
          #               withdrawalsAllowed:  True,
          #              withdrawalPrecision:  8,
          #                    minWithdrawal:  4,
          #                    maxWithdrawal:  1000000000,
          #                flatWithdrawalFee:  2,
          #                       isDelisted:  False       },
          #       {                  symbol: "ZZC",
          #                             name: "Zozo",
          #                           isFiat:  False,
          #                  depositsAllowed:  False,
          #         depositConfirmationCount:  8,
          #                       minDeposit:  0,
          #               withdrawalsAllowed:  False,
          #              withdrawalPrecision:  8,
          #                    minWithdrawal:  0.2,
          #                    maxWithdrawal:  1000000000,
          #                flatWithdrawalFee:  0.1,
          #                       isDelisted:  False       }]
          #
          result = {}
          for i in range(0, len(response)):
              currency = response[i]
              id = self.safe_string(currency, 'symbol')
              code = self.safe_currency_code(id)
              withdrawalPrecision = self.safe_integer(currency, 'withdrawalPrecision')
              precision = math.pow(10, -withdrawalPrecision)
              address = self.safe_value(currency, 'BaseAddress')
              active = (currency['depositsAllowed'] and currency['withdrawalsAllowed'] and not currency['isDelisted'])
              type = 'fiat' if currency['isFiat'] else 'crypto'
              result[code] = {
                  'id': id,
                  'code': code,
                  'address': address,
                  'info': currency,
                  'type': type,
                  'name': self.safe_string(currency, 'name'),
                  'active': active,
                  'fee': self.safe_number(currency, 'flatWithdrawalFee'),  # todo: redesign
                  'precision': precision,
                  'limits': {
                      'amount': {
                          'min': math.pow(10, -precision),
                          'max': math.pow(10, precision),
                      },
                      'deposit': {
                          'min': self.safe_number(currency, 'minDeposit'),
                          'max': None,
                      },
                      'withdraw': {
                          'min': self.safe_number(currency, 'minWithdrawal'),
                          'max': self.safe_number(currency, 'maxWithdrawal'),
                      },
                  },
              }
          return result
  
      def fetch_funding_fees(self, codes=None, params={}):
          self.load_markets()
          response = self.publicGetCurrenciesWithdrawalFees(params)
          #
          #     [
          #         {
          #             currency: '1INCH',
          #             fees: [
          #                 {feeCurrency: 'BTC', amount: 0.00032},
          #                 {feeCurrency: 'ETH', amount: 0.0054},
          #                 {feeCurrency: 'DOGE', amount: 63.06669},
          #                 {feeCurrency: 'LTC', amount: 0.0912},
          #                 {feeCurrency: 'BCH', amount: 0.02364},
          #                 {feeCurrency: 'USDT', amount: 12.717},
          #                 {feeCurrency: 'USDC', amount: 12.7367},
          #                 {feeCurrency: 'TRX', amount: 205.99108},
          #                 {feeCurrency: 'EOS', amount: 3.30141}
          #             ]
          #         }
          #     ]
          #
          withdrawFees = {}
          for i in range(0, len(response)):
              entry = response[i]
              currencyId = self.safe_string(entry, 'currency')
              code = self.safe_currency_code(currencyId)
              networkList = self.safe_value(entry, 'fees')
              withdrawFees[code] = {}
              for j in range(0, len(networkList)):
                  networkEntry = networkList[j]
                  networkId = self.safe_string(networkEntry, 'feeCurrency')
                  networkCode = self.safe_currency_code(networkId)
                  fee = self.safe_number(networkEntry, 'amount')
                  withdrawFees[code][networkCode] = fee
          return {
              'withdraw': withdrawFees,
              'deposit': {},
              'info': response,
          }
  
      def fetch_balance(self, params={}):
          self.load_markets()
          request = {
              # 'currency': 'ETH',  # comma-separated list of currency ids
              # 'nonZeroOnly': 'false',  # True by default
          }
          response = self.accountGetBalance(self.extend(request, params))
          #
          #     [
          #         {
          #           "currency": "ETH",
          #           "available": 0.0,
          #           "reserved": 0.0
          #         }
          #     ]
          #
          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()
              account['free'] = self.safe_string(balance, 'available')
              account['used'] = self.safe_string(balance, 'reserved')
              result[code] = account
          return self.parse_balance(result)
  
      def fetch_order_book(self, symbol, limit=None, params={}):
          self.load_markets()
          market = self.market(symbol)
          request = {
              'instrument': market['id'],
          }
          if limit is not None:
              request['limit'] = limit  # default = maximum = 100
          response = self.publicGetOrderBook(self.extend(request, params))
          #
          #     { buyLevels: [{price: 0.03099, volume: 0.00610063},
          #                     {price: 0.03097, volume: 1.33455158},
          #                     {price: 0.03096, volume: 0.0830889},
          #                     {price: 0.03095, volume: 0.0820356},
          #                     {price: 0.03093, volume: 0.5499419},
          #                     {price: 0.03092, volume: 0.23317494},
          #                     {price: 0.03091, volume: 0.62105322},
          #                     {price: 0.00620041, volume: 0.003}    ],
          #       sellLevels: [{price: 0.03117, volume: 5.47492315},
          #                     {price: 0.03118, volume: 1.97744139},
          #                     {price: 0.03119, volume: 0.012},
          #                     {price: 0.03121, volume: 0.741242},
          #                     {price: 0.03122, volume: 0.96178089},
          #                     {price: 0.03123, volume: 0.152326},
          #                     {price: 0.03124, volume: 2.63462933},
          #                     {price: 0.069, volume: 0.004}            ]}
          #
          return self.parse_order_book(response, symbol, None, 'buyLevels', 'sellLevels', 'price', 'volume')
  
      def parse_ticker(self, ticker, market=None):
          #
          #       {   instrument: "ZZC-USD",
          #                  last:  0.065,
          #         percentChange:  0,
          #                   low:  0.065,
          #                  high:  0.065,
          #            baseVolume:  0,
          #           quoteVolume:  0,
          #           volumeInBtc:  0,
          #           volumeInUsd:  0,
          #                   ask:  0.5,
          #                   bid:  0.0007,
          #             timestamp: "2018-10-31T09:21:25Z"}   ]
          #
          timestamp = self.parse8601(self.safe_string(ticker, 'timestamp'))
          marketId = self.safe_string(ticker, 'instrument')
          symbol = self.safe_symbol(marketId, market, '-')
          last = self.safe_number(ticker, 'last')
          return {
              'symbol': symbol,
              'timestamp': timestamp,
              'datetime': self.iso8601(timestamp),
              'high': self.safe_number(ticker, 'high'),
              'low': self.safe_number(ticker, 'low'),
              'bid': self.safe_number(ticker, 'bid'),
              'bidVolume': None,
              'ask': self.safe_number(ticker, 'ask'),
              'askVolume': None,
              'vwap': None,
              'open': None,
              'close': last,
              'last': last,
              'previousClose': None,  # previous day close
              'change': None,
              'percentage': self.safe_number(ticker, 'percentChange'),
              'average': None,
              'baseVolume': self.safe_number(ticker, 'baseVolume'),
              'quoteVolume': self.safe_number(ticker, 'quoteVolume'),
              'info': ticker,
          }
  
      def fetch_ticker(self, symbol, params={}):
          self.load_markets()
          market = self.market(symbol)
          request = {
              'instrument': market['id'],
          }
          response = self.publicGetTickers(self.extend(request, params))
          #
          #     [{   instrument: "$PAC-BTC",
          #                  last:  3.3e-7,
          #         percentChange:  3.125,
          #                   low:  2.7e-7,
          #                  high:  3.3e-7,
          #            baseVolume:  191700.79823187,
          #           quoteVolume:  0.0587930939346704,
          #           volumeInBtc:  0.0587930939346704,
          #           volumeInUsd:  376.2006339435353,
          #                   ask:  3.3e-7,
          #                   bid:  3.1e-7,
          #             timestamp: "2018-10-31T09:21:25Z"}   ]
          #
          numTickers = len(response)
          if numTickers < 1:
              raise ExchangeError(self.id + ' fetchTicker could not load quotes for symbol ' + symbol)
          return self.parse_ticker(response[0], market)
  
      def fetch_tickers(self, symbols=None, params={}):
          self.load_markets()
          request = {}
          if symbols is not None:
              ids = self.market_ids(symbols)
              request['instrument'] = ','.join(ids)
          response = self.publicGetTickers(self.extend(request, params))
          #
          #     [{   instrument: "$PAC-BTC",
          #                  last:  3.3e-7,
          #         percentChange:  3.125,
          #                   low:  2.7e-7,
          #                  high:  3.3e-7,
          #            baseVolume:  191700.79823187,
          #           quoteVolume:  0.0587930939346704,
          #           volumeInBtc:  0.0587930939346704,
          #           volumeInUsd:  376.2006339435353,
          #                   ask:  3.3e-7,
          #                   bid:  3.1e-7,
          #             timestamp: "2018-10-31T09:21:25Z"},
          #       {   instrument: "ZZC-USD",
          #                  last:  0.065,
          #         percentChange:  0,
          #                   low:  0.065,
          #                  high:  0.065,
          #            baseVolume:  0,
          #           quoteVolume:  0,
          #           volumeInBtc:  0,
          #           volumeInUsd:  0,
          #                   ask:  0.5,
          #                   bid:  0.0007,
          #             timestamp: "2018-10-31T09:21:25Z"}   ]
          #
          return self.parse_tickers(response, symbols)
  
      def parse_trade(self, trade, market=None):
          #
          # public fetchTrades
          #
          #       {    price:  0.03105,
          #            volume:  0.11,
          #              side: "sell",
          #         timestamp: "2018-10-31T04:19:35Z"}  ]
          #
          # private fetchMyTrades
          #
          #     {
          #         "id": 3005866,
          #         "orderId": 468533093,
          #         "timestamp": "2018-06-02T16:26:27Z",
          #         "instrument": "BCH-ETH",
          #         "side": "buy",
          #         "price": 1.78882,
          #         "volume": 0.027,
          #         "fee": 0.0000483,
          #         "feeCurrency": "ETH"
          #     }
          #
          timestamp = self.parse8601(self.safe_string(trade, 'timestamp'))
          priceString = self.safe_string(trade, 'price')
          amountString = self.safe_string(trade, 'volume')
          price = self.parse_number(priceString)
          amount = self.parse_number(amountString)
          cost = self.parse_number(Precise.string_mul(priceString, amountString))
          id = self.safe_string(trade, 'id')
          side = self.safe_string(trade, 'side')
          orderId = self.safe_string(trade, 'orderId')
          marketId = self.safe_string(trade, 'instrument')
          symbol = self.safe_symbol(marketId, market, '-')
          fee = None
          feeCurrencyId = self.safe_string(trade, 'feeCurrency')
          feeCode = self.safe_currency_code(feeCurrencyId)
          feeCost = self.safe_number(trade, 'fee')
          if feeCost is not None:
              fee = {
                  'cost': feeCost,
                  'currency': feeCode,
              }
          takerOrMaker = None
          return {
              'info': trade,
              'timestamp': timestamp,
              'datetime': self.iso8601(timestamp),
              'symbol': symbol,
              'id': id,
              'order': orderId,
              'type': None,
              'takerOrMaker': takerOrMaker,
              'side': side,
              'price': price,
              'cost': cost,
              'amount': amount,
              'fee': fee,
          }
  
      def fetch_trades(self, symbol, since=None, limit=None, params={}):
          self.load_markets()
          market = self.market(symbol)
          request = {
              'instrument': market['id'],
          }
          if limit is not None:
              request['limit'] = limit  # min 1, max 1000, default 100
          response = self.publicGetRecentTrades(self.extend(request, params))
          #
          #     [{    price:  0.03117,
          #            volume:  0.02597403,
          #              side: "buy",
          #         timestamp: "2018-10-31T09:37:46Z"},
          #       {    price:  0.03105,
          #            volume:  0.11,
          #              side: "sell",
          #         timestamp: "2018-10-31T04:19:35Z"}  ]
          #
          return self.parse_trades(response, market, since, limit)
  
      def parse_ohlcv(self, ohlcv, market=None):
          #
          #     {
          #         timestamp: '2019-09-21T10:36:00Z',
          #         open: 0.02152,
          #         high: 0.02156,
          #         low: 0.02152,
          #         close: 0.02156,
          #         volume: 0.01741259
          #     }
          #
          return [
              self.parse8601(self.safe_string(ohlcv, 'timestamp')),
              self.safe_number(ohlcv, 'open'),
              self.safe_number(ohlcv, 'high'),
              self.safe_number(ohlcv, 'low'),
              self.safe_number(ohlcv, 'close'),
              self.safe_number(ohlcv, 'volume'),
          ]
  
      def fetch_ohlcv(self, symbol, timeframe='1m', since=None, limit=None, params={}):
          self.load_markets()
          market = self.market(symbol)
          request = {
              'granularity': self.timeframes[timeframe],
              'instrument': market['id'],
          }
          if limit is not None:
              request['limit'] = limit  # Accepted values: 1 - 1000. If the parameter is not specified, the number of results is limited to 100
          response = self.publicGetOhlcv(self.extend(request, params))
          #
          #     [
          #         {
          #             "timestamp": "2020-06-06T17:36:00Z",
          #             "open": 0.025,
          #             "high": 0.025,
          #             "low": 0.02499,
          #             "close": 0.02499,
          #             "volume": 0.00643127
          #         }
          #     ]
          #
          return self.parse_ohlcvs(response, market, timeframe, since, limit)
  
      def parse_order_status(self, status):
          statuses = {
              'submitting': 'open',  # A newly created limit order has a status "submitting" until it has been processed.
              # This status changes during the lifetime of an order and can have different values depending on the value of the parameter Time In Force.
              'unfilledActive': 'open',  # order is active, no trades have been made
              'partiallyFilledActive': 'open',  # part of the order has been filled, the other part is active
              'filled': 'closed',  # order has been filled entirely
              'partiallyFilledCancelled': 'canceled',  # part of the order has been filled, the other part has been cancelled either by the trader or by the system(see the value of cancellationReason of an Order for more details on the reason of cancellation)
              'unfilledCancelled': 'canceled',  # order has been cancelled, no trades have taken place(see the value of cancellationReason of an Order for more details on the reason of cancellation)
          }
          return statuses[status] if (status in statuses) else status
  
      def parse_order(self, order, market=None):
          #
          # createOrder
          #
          #     {
          #         "id": 469594855,
          #         "timestamp": "2018-06-08T16:59:44Z",
          #         "instrument": "BTS-BTC",
          #         "side": "buy",
          #         "type": "limit",
          #         "status": "submitting",
          #         "cancellationReason": null,
          #         "timeInForce": "GTC",
          #         "volume": 4.0,
          #         "price": 0.000025,
          #         "stopPrice": null,
          #         "remainingVolume": 4.0,
          #         "lastUpdate": null,
          #         "parentOrderId": null,
          #         "childOrderId": null
          #     }
          #
          status = self.parse_order_status(self.safe_string(order, 'status'))
          marketId = self.safe_string(order, 'instrument')
          symbol = self.safe_symbol(marketId, market, '-')
          timestamp = self.parse8601(self.safe_string(order, 'timestamp'))
          price = self.safe_number(order, 'price')
          amount = self.safe_number(order, 'volume')
          remaining = self.safe_number(order, 'remainingVolume')
          lastTradeTimestamp = self.parse8601(self.safe_string(order, 'lastUpdate'))
          id = self.safe_string(order, 'id')
          type = self.safe_string(order, 'type')
          side = self.safe_string(order, 'side')
          fee = None
          trades = None
          average = None
          timeInForce = self.safe_string(order, 'timeInForce')
          stopPrice = self.safe_number(order, 'stopPrice')
          return self.safe_order({
              'info': order,
              'id': id,
              'clientOrderId': None,
              'timestamp': timestamp,
              'datetime': self.iso8601(timestamp),
              'lastTradeTimestamp': lastTradeTimestamp,
              'symbol': symbol,
              'type': type,
              'timeInForce': timeInForce,
              'side': side,
              'price': price,
              'stopPrice': stopPrice,
              'amount': amount,
              'cost': None,
              'average': average,
              'filled': None,
              'remaining': remaining,
              'status': status,
              'fee': fee,
              'trades': trades,
          })
  
      def create_order(self, symbol, type, side, amount, price=None, params={}):
          self.load_markets()
          market = self.market(symbol)
          request = {
              'instrument': market['id'],
              'volume': self.amount_to_precision(symbol, amount),
              # The value must comply with the list of order types supported by the instrument(see the value of parameter supportedOrderTypes of the Instrument)
              # If the parameter is not specified, the default value "limit" is used
              # More about order types in the corresponding section of documentation
              'type': type,  # 'limit', 'market', 'stopLimit', in fact as of 2018-10-31, only 'limit' orders are supported for all markets
              'side': side,  # 'buy' or 'sell'
              # "GTC" - Good-Til-Cancelled
              # "IOC" - Immediate-Or-Cancel(currently not supported by the exchange API, reserved for future use)
              # "FOK" - Fill-Or-Kill(currently not supported by the exchange API, reserved for future use)
              # 'timeInForce': 'GTC',  # IOC', 'FOK'
              # 'strictValidation': False,  # False - prices will be rounded to meet the requirement, True - execution of the method will be aborted and an error message will be returned
          }
          priceIsRequired = False
          stopPriceIsRequired = False
          if type == 'limit':
              priceIsRequired = True
          elif type == 'stopLimit':
              priceIsRequired = True
              stopPriceIsRequired = True
          if priceIsRequired:
              if price is None:
                  raise InvalidOrder(self.id + ' createOrder() requires a price argument for a ' + type + ' order')
              request['price'] = self.price_to_precision(symbol, price)
          if stopPriceIsRequired:
              stopPrice = self.safe_number(params, 'stopPrice')
              if stopPrice is None:
                  raise InvalidOrder(self.id + ' createOrder() requires a stopPrice extra param for a ' + type + ' order')
              else:
                  request['stopPrice'] = self.price_to_precision(symbol, stopPrice)
              params = self.omit(params, 'stopPrice')
          response = self.tradingPostPlaceOrder(self.extend(request, params))
          #
          #     {
          #         "id": 469594855,
          #         "timestamp": "2018-06-08T16:59:44Z",
          #         "instrument": "BTS-BTC",
          #         "side": "buy",
          #         "type": "limit",
          #         "status": "submitting",
          #         "cancellationReason": null,
          #         "timeInForce": "GTC",
          #         "volume": 4.0,
          #         "price": 0.000025,
          #         "stopPrice": null,
          #         "remainingVolume": 4.0,
          #         "lastUpdate": null,
          #         "parentOrderId": null,
          #         "childOrderId": null
          #     }
          #
          return self.parse_order(response, market)
  
      def fetch_order(self, id, symbol=None, params={}):
          self.load_markets()
          request = {
              'id': id,
          }
          response = self.tradingGetOrderStatus(self.extend(request, params))
          #
          #     [
          #         {
          #           "id": 466747915,
          #           "timestamp": "2018-05-26T06:43:49Z",
          #           "instrument": "UNI-BTC",
          #           "side": "sell",
          #           "type": "limit",
          #           "status": "partiallyFilledActive",
          #           "cancellationReason": null,
          #           "timeInForce": "GTC",
          #           "volume": 5700.0,
          #           "price": 0.000005,
          #           "stopPrice": null,
          #           "remainingVolume": 1.948051948052,
          #           "lastUpdate": null,
          #           "parentOrderId": null,
          #           "childOrderId": null
          #         }
          #     ]
          #
          numOrders = len(response)
          if numOrders < 1:
              raise OrderNotFound(self.id + ' fetchOrder could not fetch order id ' + id)
          return self.parse_order(response[0])
  
      def fetch_orders(self, symbol=None, since=None, limit=None, params={}):
          self.load_markets()
          request = {}
          if since is not None:
              request['from'] = self.ymdhms(since, 'T')
          if limit is not None:
              request['limit'] = limit
          if symbol is not None:
              market = self.market(symbol)
              request['instrument'] = market['id']
          method = self.safe_string(self.options, 'fetchOrdersMethod', 'tradingGetOrderHistory')
          response = getattr(self, method)(self.extend(request, params))
          #
          #     [
          #         {
          #             "id": 468535711,
          #             "timestamp": "2018-06-02T16:42:40Z",
          #             "instrument": "BTC-EUR",
          #             "side": "sell",
          #             "type": "limit",
          #             "status": "submitting",
          #             "cancellationReason": null,
          #             "timeInForce": "GTC",
          #             "volume": 0.00770733,
          #             "price": 6724.9,
          #             "stopPrice": null,
          #             "remainingVolume": 0.00770733,
          #             "lastUpdate": "2018-06-02T16:42:40Z",
          #             "parentOrderId": null,
          #             "childOrderId": null
          #         }
          #     ]
          #
          return self.parse_orders(response)
  
      def fetch_orders_by_ids(self, ids=None, since=None, limit=None, params={}):
          self.load_markets()
          request = {
              'id': ','.join(ids),
          }
          response = self.tradingGetOrderStatus(self.extend(request, params))
          #
          #     [
          #         {
          #           "id": 466747915,
          #           "timestamp": "2018-05-26T06:43:49Z",
          #           "instrument": "UNI-BTC",
          #           "side": "sell",
          #           "type": "limit",
          #           "status": "partiallyFilledActive",
          #           "cancellationReason": null,
          #           "timeInForce": "GTC",
          #           "volume": 5700.0,
          #           "price": 0.000005,
          #           "stopPrice": null,
          #           "remainingVolume": 1.948051948052,
          #           "lastUpdate": null,
          #           "parentOrderId": null,
          #           "childOrderId": null
          #         }
          #     ]
          #
          return self.parse_orders(response, None, since, limit)
  
      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['instrument'] = market['id']
          response = self.tradingGetActiveOrders(self.extend(request, params))
          #
          #     [
          #         {
          #             "id": 466747915,
          #             "timestamp": "2018-05-26T06:43:49Z",
          #             "instrument": "UNI-BTC",
          #             "side": "sell",
          #             "type": "limit",
          #             "status": "partiallyFilledActive",
          #             "cancellationReason": null,
          #             "timeInForce": "GTC",
          #             "volume": 5700.0,
          #             "price": 0.000005,
          #             "stopPrice": null,
          #             "remainingVolume": 1.948051948052,
          #             "lastUpdate": null,
          #             "parentOrderId": null,
          #             "childOrderId": null
          #         },
          #         {
          #             "id": 466748077,
          #             "timestamp": "2018-05-26T06:45:29Z",
          #             "instrument": "PRJ-BTC",
          #             "side": "sell",
          #             "type": "limit",
          #             "status": "partiallyFilledActive",
          #             "cancellationReason": null,
          #             "timeInForce": "GTC",
          #             "volume": 10000.0,
          #             "price": 0.0000007,
          #             "stopPrice": null,
          #             "remainingVolume": 9975.0,
          #             "lastUpdate": null,
          #             "parentOrderId": null,
          #             "childOrderId": null
          #         },
          #         ...
          #     ]
          #
          return self.parse_orders(response, market, since, limit)
  
      def fetch_closed_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['instrument'] = market['id']
          if since is not None:
              request['from'] = self.ymdhms(since, 'T')
          if limit is not None:
              request['limit'] = limit  # min 1, max 1000, default 100
          method = self.safe_string(self.options, 'fetchClosedOrdersMethod', 'tradingGetOrderHistory')
          response = getattr(self, method)(self.extend(request, params))
          #     [
          #         {
          #             "id": 468535711,
          #             "timestamp": "2018-06-02T16:42:40Z",
          #             "instrument": "BTC-EUR",
          #             "side": "sell",
          #             "type": "limit",
          #             "status": "submitting",
          #             "cancellationReason": null,
          #             "timeInForce": "GTC",
          #             "volume": 0.00770733,
          #             "price": 6724.9,
          #             "stopPrice": null,
          #             "remainingVolume": 0.00770733,
          #             "lastUpdate": null,
          #             "parentOrderId": null,
          #             "childOrderId": null
          #         },
          #         {
          #             "id": 468535707,
          #             "timestamp": "2018-06-02T16:42:37Z",
          #             "instrument": "BTG-BTC",
          #             "side": "buy",
          #             "type": "limit",
          #             "status": "unfilledActive",
          #             "cancellationReason": null,
          #             "timeInForce": "GTC",
          #             "volume": 0.0173737,
          #             "price": 0.00589027,
          #             "stopPrice": null,
          #             "remainingVolume": 0.0173737,
          #             "lastUpdate": null,
          #             "parentOrderId": null,
          #             "childOrderId": null
          #         },
          #         ...
          #     ]
          #
          return self.parse_orders(response, market, since, limit)
  
      def cancel_order(self, id, symbol=None, params={}):
          self.load_markets()
          request = {
              'ids': [
                  int(id),
              ],
          }
          response = self.tradingPostCancelOrdersById(self.extend(request, params))
          #
          #     [
          #         465448358,
          #         468364313
          #     ]
          #
          return self.parse_order(response)
  
      def cancel_all_orders(self, symbol=None, params={}):
          response = self.tradingPostCancelAllOrders(params)
          #
          #     [
          #         465448358,
          #         468364313
          #     ]
          #
          return response
  
      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['instrument'] = market['id']
          if since is not None:
              request['from'] = self.ymdhms(since, 'T')
          if limit is not None:
              request['limit'] = limit  # min 1, max 1000, default 100
          response = self.tradingGetTradeHistory(self.extend(request, params))
          #
          #     [
          #         {
          #             "id": 3005866,
          #             "orderId": 468533093,
          #             "timestamp": "2018-06-02T16:26:27Z",
          #             "instrument": "BCH-ETH",
          #             "side": "buy",
          #             "price": 1.78882,
          #             "volume": 0.027,
          #             "fee": 0.0000483,
          #             "feeCurrency": "ETH"
          #         },
          #         {
          #             "id": 3005812,
          #             "orderId": 468515771,
          #             "timestamp": "2018-06-02T16:16:05Z",
          #             "instrument": "ETC-BTC",
          #             "side": "sell",
          #             "price": 0.00210958,
          #             "volume": 0.05994006,
          #             "fee": -0.000000063224,
          #             "feeCurrency": "BTC"
          #         },
          #         ...
          #     ]
          #
          return self.parse_trades(response, market, since, limit)
  
      def fetch_transactions(self, code=None, since=None, limit=None, params={}):
          self.load_markets()
          currency = None
          request = {}
          if code is not None:
              currency = self.currency(code)
              request['currency'] = currency['id']
          if since is not None:
              request['from'] = self.ymd(since, 'T')
          response = self.accountGetMoneyTransfers(self.extend(request, params))
          #
          #     [
          #         {
          #           "id": 756446,
          #           "type": "deposit",
          #           "currency": "ETH",
          #           "address": "0x451d5a1b7519aa75164f440df78c74aac96023fe",
          #           "paymentId": null,
          #           "amount": 0.142,
          #           "fee": null,
          #           "txId": "0x2b49098749840a9482c4894be94f94864b498a1306b6874687a5640cc9871918",
          #           "createdAt": "2018-06-02T19:30:28Z",
          #           "processedAt": "2018-06-02T21:10:41Z",
          #           "confirmationsRequired": 12,
          #           "confirmationCount": 12,
          #           "status": "success",
          #           "errorDescription": null
          #         },
          #         {
          #           "id": 754618,
          #           "type": "deposit",
          #           "currency": "BTC",
          #           "address": "1IgNfmERVcier4IhfGEfutkLfu4AcmeiUC",
          #           "paymentId": null,
          #           "amount": 0.09,
          #           "fee": null,
          #           "txId": "6876541687a9187e987c9187654f7198b9718af974641687b19a87987f91874f",
          #           "createdAt": "2018-06-02T16:19:44Z",
          #           "processedAt": "2018-06-02T16:20:50Z",
          #           "confirmationsRequired": 1,
          #           "confirmationCount": 1,
          #           "status": "success",
          #           "errorDescription": null
          #         },
          #         ...
          #     ]
          #
          return self.parse_transactions(response, currency, since, limit)
  
      def fetch_deposits(self, code=None, since=None, limit=None, params={}):
          request = {
              'type': 'deposit',
          }
          return self.fetch_transactions(code, since, limit, self.extend(request, params))
  
      def fetch_withdrawals(self, code=None, since=None, limit=None, params={}):
          request = {
              'type': 'withdrawal',
          }
          return self.fetch_transactions(code, since, limit, self.extend(request, params))
  
      def parse_transaction_status(self, status):
          statuses = {
              'pending': 'pending',  # transfer is in progress
              'success': 'ok',  # completed successfully
              'failed': 'failed',  # aborted at some point(money will be credited back to the account of origin)
          }
          return self.safe_string(statuses, status, status)
  
      def parse_transaction(self, transaction, currency=None):
          #
          #     {
          #         "id": 756446,
          #         "type": "deposit",
          #         "currency": "ETH",
          #         "address": "0x451d5a1b7519aa75164f440df78c74aac96023fe",
          #         "paymentId": null,
          #         "amount": 0.142,
          #         "fee": null,
          #         "txId": "0x2b49098749840a9482c4894be94f94864b498a1306b6874687a5640cc9871918",
          #         "createdAt": "2018-06-02T19:30:28Z",
          #         "processedAt": "2018-06-02T21:10:41Z",
          #         "confirmationsRequired": 12,
          #         "confirmationCount": 12,
          #         "status": "success",
          #         "errorDescription": null,
          #     }
          #
          id = self.safe_string(transaction, 'id')
          address = self.safe_string(transaction, 'address')
          tag = self.safe_string(transaction, 'paymentId')
          txid = self.safe_value(transaction, 'txId')
          currencyId = self.safe_string(transaction, 'currency')
          code = self.safe_currency_code(currencyId, currency)
          type = self.safe_string(transaction, 'type')
          timestamp = self.parse8601(self.safe_string(transaction, 'createdAt'))
          updated = self.parse8601(self.safe_string(transaction, 'processedAt'))
          status = self.parse_transaction_status(self.safe_string(transaction, 'status'))
          amount = self.safe_number(transaction, 'amount')
          feeCost = self.safe_number(transaction, 'fee')
          fee = {
              'cost': feeCost,
              'currency': code,
          }
          return {
              'info': transaction,
              'id': id,
              'txid': txid,
              'timestamp': timestamp,
              'datetime': self.iso8601(timestamp),
              'address': address,
              'tag': tag,
              'type': type,
              'amount': amount,
              'currency': code,
              'status': status,
              'updated': updated,
              'fee': fee,
          }
  
      def fetch_deposit_address(self, code, params={}):
          self.load_markets()
          currency = self.currency(code)
          request = {
              'currency': currency['id'],
          }
          response = self.accountGetDepositAddress(self.extend(request, params))
          #
          #     {
          #         "currency": "BTS",
          #         "address": "crex24",
          #         "paymentId": "0fg4da4186741579"
          #     }
          #
          address = self.safe_string(response, 'address')
          tag = self.safe_string(response, 'paymentId')
          return {
              'currency': code,
              'address': self.check_address(address),
              'tag': tag,
              'network': None,
              'info': response,
          }
  
      def withdraw(self, code, amount, address, tag=None, params={}):
          tag, params = self.handle_withdraw_tag_and_params(tag, params)
          self.check_address(address)
          self.load_markets()
          currency = self.currency(code)
          request = {
              'currency': currency['id'],
              'address': address,
              'amount': float(self.currency_to_precision(code, amount)),
              # sets whether the specified amount includes fee, can have either of the two values
              # True - balance will be decreased by amount, whereas [amount - fee] will be transferred to the specified address
              # False - amount will be deposited to the specified address, whereas the balance will be decreased by [amount + fee]
              # 'includeFee': False,  # the default value is False
              'feeCurrency': currency['id'],  # https://github.com/ccxt/ccxt/issues/7544
          }
          if tag is not None:
              request['paymentId'] = tag
          networks = self.safe_value(self.options, 'networks', {})
          network = self.safe_string_upper(params, 'network')  # self line allows the user to specify either ERC20 or ETH
          network = self.safe_string(networks, network, network)  # handle ERC20>ETH alias
          if network is not None:
              request['transport'] = network
              params = self.omit(params, 'network')
          response = self.accountPostWithdraw(self.extend(request, params))
          return self.parse_transaction(response)
  
      def sign(self, path, api='public', method='GET', params={}, headers=None, body=None):
          request = '/' + self.version + '/' + api + '/' + self.implode_params(path, params)
          query = self.omit(params, self.extract_params(path))
          if method == 'GET':
              if query:
                  request += '?' + self.urlencode(query)
          url = self.urls['api'] + request
          if (api == 'trading') or (api == 'account'):
              self.check_required_credentials()
              nonce = str(self.nonce())
              secret = self.base64_to_binary(self.secret)
              auth = request + nonce
              headers = {
                  'X-CREX24-API-KEY': self.apiKey,
                  'X-CREX24-API-NONCE': nonce,
              }
              if method == 'POST':
                  headers['Content-Type'] = 'application/json'
                  body = self.json(params)
                  auth += body
              headers['X-CREX24-API-SIGN'] = self.hmac(self.encode(auth), secret, hashlib.sha512, 'base64')
          return {'url': url, 'method': method, 'body': body, 'headers': headers}
  
      def handle_errors(self, code, reason, url, method, headers, body, response, requestHeaders, requestBody):
          if not self.is_json_encoded_object(body):
              return  # fallback to default error handler
          if (code >= 200) and (code < 300):
              return  # no error
          message = self.safe_string(response, 'errorDescription')
          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)
          elif code == 401:
              raise AuthenticationError(feedback)
          elif code == 403:
              raise AuthenticationError(feedback)
          elif code == 429:
              raise DDoSProtection(feedback)
          elif code == 500:
              raise ExchangeError(feedback)
          elif code == 503:
              raise ExchangeNotAvailable(feedback)
          elif code == 504:
              raise RequestTimeout(feedback)
          raise ExchangeError(feedback)  # unknown message
  