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
  
  # -----------------------------------------------------------------------------
  
  try:
      basestring  # Python 3
  except NameError:
      basestring = str  # Python 2
  import hashlib
  from ccxt.base.errors import ExchangeError
  from ccxt.base.errors import AuthenticationError
  from ccxt.base.errors import ArgumentsRequired
  from ccxt.base.errors import InsufficientFunds
  from ccxt.base.errors import InvalidOrder
  from ccxt.base.errors import OrderNotFound
  from ccxt.base.errors import NotSupported
  from ccxt.base.errors import RateLimitExceeded
  from ccxt.base.errors import OnMaintenance
  from ccxt.base.errors import InvalidNonce
  
  
  class exmo(Exchange):
  
      def describe(self):
          return self.deep_extend(super(exmo, self).describe(), {
              'id': 'exmo',
              'name': 'EXMO',
              'countries': ['ES', 'RU'],  # Spain, Russia
              'rateLimit': 350,  # once every 350 ms ≈ 180 requests per minute ≈ 3 requests per second
              'version': 'v1',
              'has': {
                  'CORS': False,
                  'fetchClosedOrders': 'emulated',
                  'fetchDepositAddress': True,
                  'fetchOpenOrders': True,
                  'fetchOrder': 'emulated',
                  'fetchOrders': 'emulated',
                  'fetchOrderTrades': True,
                  'fetchOrderBooks': True,
                  'fetchMyTrades': True,
                  'fetchTickers': True,
                  'withdraw': True,
                  'fetchTradingFee': True,
                  'fetchTradingFees': True,
                  'fetchFundingFees': True,
                  'fetchCurrencies': True,
                  'fetchTransactions': True,
              },
              'urls': {
                  'logo': 'https://user-images.githubusercontent.com/1294454/27766491-1b0ea956-5eda-11e7-9225-40d67b481b8d.jpg',
                  'api': {
                      'public': 'https://api.exmo.com',
                      'private': 'https://api.exmo.com',
                      'web': 'https://exmo.me',
                  },
                  'www': 'https://exmo.me',
                  'referral': 'https://exmo.me/?ref=131685',
                  'doc': [
                      'https://exmo.me/en/api_doc?ref=131685',
                      'https://github.com/exmo-dev/exmo_api_lib/tree/master/nodejs',
                  ],
                  'fees': 'https://exmo.com/en/docs/fees',
              },
              'api': {
                  'web': {
                      'get': [
                          'ctrl/feesAndLimits',
                          'en/docs/fees',
                      ],
                  },
                  'public': {
                      'get': [
                          'currency',
                          'order_book',
                          'pair_settings',
                          'ticker',
                          'trades',
                      ],
                  },
                  'private': {
                      'post': [
                          'user_info',
                          'order_create',
                          'order_cancel',
                          'user_open_orders',
                          'user_trades',
                          'user_cancelled_orders',
                          'order_trades',
                          'required_amount',
                          'deposit_address',
                          'withdraw_crypt',
                          'withdraw_get_txid',
                          'excode_create',
                          'excode_load',
                          'wallet_history',
                      ],
                  },
              },
              'fees': {
                  'trading': {
                      'tierBased': False,
                      'percentage': True,
                      'maker': 0.2 / 100,
                      'taker': 0.2 / 100,
                  },
                  'funding': {
                      'tierBased': False,
                      'percentage': False,  # fixed funding fees for crypto, see fetchFundingFees below
                  },
              },
              'options': {
                  'useWebapiForFetchingFees': False,  # TODO: figure why Exmo bans us when we try to fetch() their web urls
                  'feesAndLimits': {
                      'success': 1,
                      'ctlr': 'feesAndLimits',
                      'error': '',
                      'data': {
                          'limits': [
                              {'pair': 'EXM/USDT', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '100000'},
                              {'pair': 'EXM/ETH', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '5000'},
                              {'pair': 'BTC/USD', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '1', 'max_p': '30000', 'min_a': '1', 'max_a': '500000'},
                              {'pair': 'BTC/KZT', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '1000', 'max_p': '12000000', 'min_a': '1000', 'max_a': '100000000'},
                              {'pair': 'ETH/KZT', 'min_q': '0.001', 'max_q': '5000', 'min_p': '4', 'max_p': '40000000', 'min_a': '3', 'max_a': '500000'},
                              {'pair': 'USDT/KZT', 'min_q': '1', 'max_q': '500000', 'min_p': '200', 'max_p': '4000', 'min_a': '0.1', 'max_a': '500000'},
                              {'pair': 'ONT/EXM', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '200', 'max_a': '15000000'},
                              {'pair': 'ONT/BTC', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.00001', 'max_a': '10'},
                              {'pair': 'ONT/RUB', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '100', 'max_a': '6000000'},
                              {'pair': 'ONT/UAH', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '200', 'max_a': '250000'},
                              {'pair': 'ONG/EXM', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '100', 'max_a': '15000000'},
                              {'pair': 'ONG/BTC', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.00001', 'max_a': '10'},
                              {'pair': 'ONG/RUB', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '100', 'max_a': '250000'},
                              {'pair': 'ONG/UAH', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '50', 'max_a': '6000000'},
                              {'pair': 'CRON/BTC', 'min_q': '1', 'max_q': '100000', 'min_p': '0.0000001', 'max_p': '1', 'min_a': '0.00001', 'max_a': '100'},
                              {'pair': 'CRON/ETH', 'min_q': '1', 'max_q': '100000', 'min_p': '0.0000001', 'max_p': '10', 'min_a': '0.00001', 'max_a': '5000'},
                              {'pair': 'CRON/USDT', 'min_q': '1', 'max_q': '100000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.001', 'max_a': '500000'},
                              {'pair': 'CRON/EXM', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '100000'},
                              {'pair': 'BTC/RUB', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '1', 'max_p': '2000000', 'min_a': '10', 'max_a': '50000000'},
                              {'pair': 'BTC/EUR', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '1', 'max_p': '30000', 'min_a': '1', 'max_a': '500000'},
                              {'pair': 'BTC/UAH', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '1', 'max_p': '15000000', 'min_a': '10', 'max_a': '15000000'},
                              {'pair': 'BTC/PLN', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '1', 'max_p': '20000000', 'min_a': '50', 'max_a': '2000000'},
                              {'pair': 'BTC/TRY', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '1', 'max_p': '800000', 'min_a': '40', 'max_a': '6000000'},
                              {'pair': 'BTC/USDT', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '0.01', 'max_p': '30000', 'min_a': '3', 'max_a': '500000'},
                              {'pair': 'ETH/BTC', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.001', 'max_a': '100'},
                              {'pair': 'ETH/USD', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '3', 'max_a': '500000'},
                              {'pair': 'ETH/RUB', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '150', 'max_a': '50000000'},
                              {'pair': 'XRP/BTC', 'min_q': '1', 'max_q': '100000', 'min_p': '0.0000001', 'max_p': '1', 'min_a': '0.00001', 'max_a': '100'},
                              {'pair': 'XRP/USD', 'min_q': '1', 'max_q': '100000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.001', 'max_a': '500000'},
                              {'pair': 'XRP/RUB', 'min_q': '1', 'max_q': '100000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '50000000'},
                              {'pair': 'ADA/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100'},
                              {'pair': 'ADA/ETH', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.001', 'max_a': '5000'},
                              {'pair': 'ADA/USD', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '500000'},
                              {'pair': 'BCH/USD', 'min_q': '0.003', 'max_q': '10000', 'min_p': '0.00000001', 'max_p': '30000', 'min_a': '0.0001', 'max_a': '500000'},
                              {'pair': 'BCH/RUB', 'min_q': '0.003', 'max_q': '10000', 'min_p': '0.00000001', 'max_p': '2000000', 'min_a': '0.0001', 'max_a': '50000000'},
                              {'pair': 'BCH/EUR', 'min_q': '0.003', 'max_q': '100000', 'min_p': '0.01', 'max_p': '300000', 'min_a': '3', 'max_a': '500000'},
                              {'pair': 'BCH/UAH', 'min_q': '0.003', 'max_q': '100000', 'min_p': '0.1', 'max_p': '30000', 'min_a': '10', 'max_a': '15000000'},
                              {'pair': 'BCH/BTC', 'min_q': '0.003', 'max_q': '10000', 'min_p': '0.00000001', 'max_p': '5', 'min_a': '0.0001', 'max_a': '100'},
                              {'pair': 'BCH/ETH', 'min_q': '0.003', 'max_q': '10000', 'min_p': '0.0000001', 'max_p': '200', 'min_a': '0.0001', 'max_a': '5000'},
                              {'pair': 'BCH/USDT', 'min_q': '0.003', 'max_q': '100000', 'min_p': '0.01', 'max_p': '5000', 'min_a': '3', 'max_a': '500000'},
                              {'pair': 'BTCZ/BTC', 'min_q': '100', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100'},
                              {'pair': 'BTG/USD', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '3', 'max_a': '500000'},
                              {'pair': 'BTG/BTC', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100'},
                              {'pair': 'BTG/ETH', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.0001', 'max_p': '100', 'min_a': '0.01', 'max_a': '5000'},
                              {'pair': 'BTT/RUB', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '0.000001', 'max_a': '100'},
                              {'pair': 'BTT/UAH', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '0.000001', 'max_a': '100'},
                              {'pair': 'BTT/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '0.1', 'min_a': '0.00001', 'max_a': '100'},
                              {'pair': 'DAI/USD', 'min_q': '1', 'max_q': '500000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000'},
                              {'pair': 'DAI/RUB', 'min_q': '1', 'max_q': '500000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '0.5', 'max_a': '30000000'},
                              {'pair': 'DAI/BTC', 'min_q': '1', 'max_q': '500000', 'min_p': '0.0000001', 'max_p': '0.1', 'min_a': '0.00001', 'max_a': '100'},
                              {'pair': 'DAI/ETH', 'min_q': '1', 'max_q': '500000', 'min_p': '0.000001', 'max_p': '10', 'min_a': '0.0001', 'max_a': '5000'},
                              {'pair': 'DASH/USD', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '3', 'max_a': '500000'},
                              {'pair': 'DASH/RUB', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '150', 'max_a': '50000000'},
                              {'pair': 'DASH/UAH', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.01', 'max_p': '200000', 'min_a': '10', 'max_a': '15000000'},
                              {'pair': 'DASH/BTC', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.0001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100'},
                              {'pair': 'DASH/USDT', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.01', 'max_p': '5000', 'min_a': '3', 'max_a': '500000'},
                              {'pair': 'DCR/RUB', 'min_q': '0.01', 'max_q': '50000', 'min_p': '0.00001', 'max_p': '100000', 'min_a': '0.5', 'max_a': '3000000'},
                              {'pair': 'DCR/UAH', 'min_q': '0.01', 'max_q': '50000', 'min_p': '0.00001', 'max_p': '100000', 'min_a': '0.25', 'max_a': '1000000'},
                              {'pair': 'DCR/BTC', 'min_q': '0.01', 'max_q': '50000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100'},
                              {'pair': 'DOGE/USD', 'min_q': '100', 'max_q': '1000000000', 'min_p': '0.0000001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '500000'},
                              {'pair': 'DOGE/BTC', 'min_q': '100', 'max_q': '100000000', 'min_p': '0.0000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '100'},
                              {'pair': 'DXT/USD', 'min_q': '100', 'max_q': '10000000', 'min_p': '0.00001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000'},
                              {'pair': 'DXT/BTC', 'min_q': '100', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '100'},
                              {'pair': 'EOS/USD', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.01', 'max_p': '1000', 'min_a': '0.5', 'max_a': '500000'},
                              {'pair': 'EOS/EUR', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.5', 'max_a': '500000'},
                              {'pair': 'EOS/BTC', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100'},
                              {'pair': 'ETC/USD', 'min_q': '0.2', 'max_q': '1000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '0.01', 'max_a': '500000'},
                              {'pair': 'ETC/RUB', 'min_q': '0.2', 'max_q': '1000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '0.01', 'max_a': '50000000'},
                              {'pair': 'ETC/BTC', 'min_q': '0.2', 'max_q': '1000', 'min_p': '0.0001', 'max_p': '0.5', 'min_a': '0.001', 'max_a': '100'},
                              {'pair': 'ETH/EUR', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '3', 'max_a': '500000'},
                              {'pair': 'ETH/UAH', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.01', 'max_p': '1000000', 'min_a': '90', 'max_a': '15000000'},
                              {'pair': 'ETH/PLN', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '50', 'max_a': '2000000'},
                              {'pair': 'ETH/TRY', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.1', 'max_p': '80000', 'min_a': '10', 'max_a': '6000000'},
                              {'pair': 'ETH/USDT', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '3', 'max_a': '500000'},
                              {'pair': 'ETH/LTC', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.00000001', 'max_p': '100000', 'min_a': '0.05', 'max_a': '100000'},
                              {'pair': 'ETZ/BTC', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '10'},
                              {'pair': 'ETZ/ETH', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.00000001', 'max_p': '100', 'min_a': '0.001', 'max_a': '100'},
                              {'pair': 'ETZ/USDT', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '1000'},
                              {'pair': 'GAS/USD', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.01', 'max_p': '50000', 'min_a': '0.1', 'max_a': '500000'},
                              {'pair': 'GAS/BTC', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100'},
                              {'pair': 'GNT/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100'},
                              {'pair': 'GNT/ETH', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.01', 'max_a': '5000'},
                              {'pair': 'GUSD/USD', 'min_q': '1', 'max_q': '500000', 'min_p': '0.1', 'max_p': '10', 'min_a': '0.1', 'max_a': '500000'},
                              {'pair': 'GUSD/RUB', 'min_q': '1', 'max_q': '500000', 'min_p': '0.01', 'max_p': '1000', 'min_a': '10', 'max_a': '50000000'},
                              {'pair': 'GUSD/BTC', 'min_q': '1', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0015', 'max_a': '100'},
                              {'pair': 'HP/BTC', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '0.1', 'min_a': '0.00001', 'max_a': '100'},
                              {'pair': 'HB/BTC', 'min_q': '10', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.000001', 'max_a': '100'},
                              {'pair': 'INK/USD', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '500000'},
                              {'pair': 'INK/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100'},
                              {'pair': 'INK/ETH', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.001', 'max_a': '5000'},
                              {'pair': 'KICK/RUB', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '10', 'max_a': '50000000'},
                              {'pair': 'KICK/USDT', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '100000'},
                              {'pair': 'KICK/BTC', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '0.1', 'min_a': '0.00001', 'max_a': '100'},
                              {'pair': 'KICK/ETH', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '5000'},
                              {'pair': 'LSK/USD', 'min_q': '0.1', 'max_q': '200000', 'min_p': '0.1', 'max_p': '1000', 'min_a': '1', 'max_a': '500000'},
                              {'pair': 'LSK/RUB', 'min_q': '0.1', 'max_q': '200000', 'min_p': '0.001', 'max_p': '100000', 'min_a': '0.5', 'max_a': '50000000'},
                              {'pair': 'LSK/BTC', 'min_q': '1', 'max_q': '200000', 'min_p': '0.0000001', 'max_p': '1', 'min_a': '0.0015', 'max_a': '100'},
                              {'pair': 'LTC/USD', 'min_q': '0.05', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '3', 'max_a': '500000'},
                              {'pair': 'LTC/RUB', 'min_q': '0.05', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '150', 'max_a': '50000000'},
                              {'pair': 'LTC/EUR', 'min_q': '0.05', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '3', 'max_a': '500000'},
                              {'pair': 'LTC/UAH', 'min_q': '0.05', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '300000', 'min_a': '5', 'max_a': '18000000'},
                              {'pair': 'LTC/BTC', 'min_q': '0.05', 'max_q': '1000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100'},
                              {'pair': 'MKR/BTC', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '0.0001', 'max_p': '100', 'min_a': '0.000001', 'max_a': '100'},
                              {'pair': 'MKR/DAI', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '0.5', 'max_p': '500000', 'min_a': '0.005', 'max_a': '500000'},
                              {'pair': 'MNC/USD', 'min_q': '10', 'max_q': '100000000', 'min_p': '0.000001', 'max_p': '10000', 'min_a': '0.01', 'max_a': '100000'},
                              {'pair': 'MNC/BTC', 'min_q': '10', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.000001', 'max_a': '100'},
                              {'pair': 'MNC/ETH', 'min_q': '10', 'max_q': '100000000', 'min_p': '0.0000001', 'max_p': '10', 'min_a': '0.00001', 'max_a': '1000'},
                              {'pair': 'MNX/USD', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.5', 'max_a': '500000'},
                              {'pair': 'MNX/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100'},
                              {'pair': 'MNX/ETH', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.01', 'max_a': '5000'},
                              {'pair': 'NEO/USD', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.01', 'max_p': '50000', 'min_a': '0.1', 'max_a': '500000'},
                              {'pair': 'NEO/RUB', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.001', 'max_p': '1500000', 'min_a': '50', 'max_a': '50000000'},
                              {'pair': 'NEO/BTC', 'min_q': '0.1', 'max_q': '200000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100'},
                              {'pair': 'OMG/USD', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.01', 'max_p': '1000', 'min_a': '0.5', 'max_a': '500000'},
                              {'pair': 'OMG/BTC', 'min_q': '1', 'max_q': '100000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100'},
                              {'pair': 'OMG/ETH', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.01', 'max_a': '5000'},
                              {'pair': 'PTI/RUB', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '600000', 'min_a': '10', 'max_a': '600000'},
                              {'pair': 'PTI/BTC', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.000001', 'max_a': '10'},
                              {'pair': 'PTI/EOS', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.0000001', 'max_p': '5000', 'min_a': '0.01', 'max_a': '20000'},
                              {'pair': 'PTI/USDT', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.000001', 'max_p': '10000', 'min_a': '0.01', 'max_a': '100000'},
                              {'pair': 'QTUM/USD', 'min_q': '0.1', 'max_q': '200000', 'min_p': '0.00000001', 'max_p': '10000', 'min_a': '0.1', 'max_a': '500000'},
                              {'pair': 'QTUM/BTC', 'min_q': '0.1', 'max_q': '200000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '100'},
                              {'pair': 'QTUM/ETH', 'min_q': '0.1', 'max_q': '200000', 'min_p': '0.00000001', 'max_p': '100', 'min_a': '0.001', 'max_a': '5000'},
                              {'pair': 'ROOBEE/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '0.1', 'min_a': '0.00001', 'max_a': '100'},
                              {'pair': 'SMART/USD', 'min_q': '10', 'max_q': '10000000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '1', 'max_a': '500000'},
                              {'pair': 'SMART/RUB', 'min_q': '10', 'max_q': '10000000', 'min_p': '0.0001', 'max_p': '100000', 'min_a': '10', 'max_a': '50000000'},
                              {'pair': 'SMART/EUR', 'min_q': '10', 'max_q': '10000000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '1', 'max_a': '500000'},
                              {'pair': 'SMART/BTC', 'min_q': '10', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.00001', 'max_a': '100'},
                              {'pair': 'TRX/USD', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '500000'},
                              {'pair': 'TRX/RUB', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.000001', 'max_p': '100000', 'min_a': '0.1', 'max_a': '50000000'},
                              {'pair': 'TRX/UAH', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.000001', 'max_p': '100000', 'min_a': '0.1', 'max_a': '50000000'},
                              {'pair': 'TRX/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100'},
                              {'pair': 'USDC/USD', 'min_q': '1', 'max_q': '500000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '3', 'max_a': '500000'},
                              {'pair': 'USDC/BTC', 'min_q': '1', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '100'},
                              {'pair': 'USDC/ETH', 'min_q': '1', 'max_q': '500000', 'min_p': '0.0000001', 'max_p': '100', 'min_a': '0.001', 'max_a': '1000'},
                              {'pair': 'USDC/USDT', 'min_q': '1', 'max_q': '500000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '3', 'max_a': '500000'},
                              {'pair': 'USDT/USD', 'min_q': '1', 'max_q': '500000', 'min_p': '0.5', 'max_p': '10', 'min_a': '0.1', 'max_a': '500000'},
                              {'pair': 'USDT/RUB', 'min_q': '1', 'max_q': '500000', 'min_p': '0.01', 'max_p': '1000', 'min_a': '10', 'max_a': '50000000'},
                              {'pair': 'USDT/EUR', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.1', 'max_p': '10', 'min_a': '0.1', 'max_a': '500000'},
                              {'pair': 'USDT/UAH', 'min_q': '0.01', 'max_q': '100000', 'min_p': '1', 'max_p': '3000', 'min_a': '2', 'max_a': '15000000'},
                              {'pair': 'VLX/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '0.1', 'min_a': '0.00001', 'max_a': '100'},
                              {'pair': 'WAVES/USD', 'min_q': '0.5', 'max_q': '10000', 'min_p': '0.001', 'max_p': '3500', 'min_a': '0.5', 'max_a': '500000'},
                              {'pair': 'WAVES/RUB', 'min_q': '0.5', 'max_q': '10000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '1', 'max_a': '50000000'},
                              {'pair': 'WAVES/BTC', 'min_q': '0.5', 'max_q': '10000', 'min_p': '0.000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '100'},
                              {'pair': 'WAVES/ETH', 'min_q': '0.5', 'max_q': '10000', 'min_p': '0.00001', 'max_p': '30', 'min_a': '0.0035', 'max_a': '3500'},
                              {'pair': 'XEM/USD', 'min_q': '10', 'max_q': '5000000', 'min_p': '0.00001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000'},
                              {'pair': 'XEM/EUR', 'min_q': '10', 'max_q': '5000000', 'min_p': '0.00001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000'},
                              {'pair': 'XEM/UAH', 'min_q': '1', 'max_q': '5000000', 'min_p': '0.0001', 'max_p': '30000', 'min_a': '10', 'max_a': '15000000'},
                              {'pair': 'XEM/BTC', 'min_q': '10', 'max_q': '5000000', 'min_p': '0.0000001', 'max_p': '1', 'min_a': '0.00015', 'max_a': '100'},
                              {'pair': 'XLM/USD', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '500000'},
                              {'pair': 'XLM/RUB', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.00001', 'max_p': '100000', 'min_a': '0.1', 'max_a': '50000000'},
                              {'pair': 'XLM/TRY', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.00001', 'max_p': '100000', 'min_a': '0.1', 'max_a': '6000000'},
                              {'pair': 'XLM/BTC', 'min_q': '1', 'max_q': '200000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100'},
                              {'pair': 'XMR/USD', 'min_q': '0.01', 'max_q': '1000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000'},
                              {'pair': 'XMR/RUB', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.001', 'max_p': '600000', 'min_a': '10', 'max_a': '16000000'},
                              {'pair': 'XMR/EUR', 'min_q': '0.01', 'max_q': '1000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000'},
                              {'pair': 'XMR/UAH', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.001', 'max_p': '300000', 'min_a': '5', 'max_a': '16000000'},
                              {'pair': 'XMR/BTC', 'min_q': '0.01', 'max_q': '1000', 'min_p': '0.0001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100'},
                              {'pair': 'XMR/ETH', 'min_q': '0.01', 'max_q': '1000', 'min_p': '0.00000001', 'max_p': '100', 'min_a': '0.001', 'max_a': '5000'},
                              {'pair': 'XRP/EUR', 'min_q': '1', 'max_q': '100000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.001', 'max_a': '500000'},
                              {'pair': 'XRP/TRY', 'min_q': '1', 'max_q': '100000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '6000000'},
                              {'pair': 'XRP/UAH', 'min_q': '1', 'max_q': '100000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '15000000'},
                              {'pair': 'XRP/USDT', 'min_q': '1', 'max_q': '100000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.001', 'max_a': '500000'},
                              {'pair': 'XRP/ETH', 'min_q': '1', 'max_q': '100000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.00001', 'max_a': '5000'},
                              {'pair': 'XTZ/USD', 'min_q': '0.1', 'max_q': '100000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '100000'},
                              {'pair': 'XTZ/RUB', 'min_q': '0.1', 'max_q': '100000', 'min_p': '0.00001', 'max_p': '100000', 'min_a': '0.5', 'max_a': '500000'},
                              {'pair': 'XTZ/BTC', 'min_q': '0.1', 'max_q': '100000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.00001', 'max_a': '10'},
                              {'pair': 'XTZ/ETH', 'min_q': '0.1', 'max_q': '100000', 'min_p': '0.0000001', 'max_p': '10', 'min_a': '0.0001', 'max_a': '1000'},
                              {'pair': 'ZEC/USD', 'min_q': '0.01', 'max_q': '1000', 'min_p': '0.001', 'max_p': '5000', 'min_a': '0.1', 'max_a': '500000'},
                              {'pair': 'ZEC/RUB', 'min_q': '0.01', 'max_q': '1000', 'min_p': '0.001', 'max_p': '100000', 'min_a': '0.1', 'max_a': '50000000'},
                              {'pair': 'ZEC/EUR', 'min_q': '0.01', 'max_q': '1000', 'min_p': '0.001', 'max_p': '5000', 'min_a': '0.1', 'max_a': '500000'},
                              {'pair': 'ZEC/BTC', 'min_q': '0.01', 'max_q': '1000', 'min_p': '0.00001', 'max_p': '10', 'min_a': '0.001', 'max_a': '100'},
                              {'pair': 'ZRX/USD', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000'},
                              {'pair': 'ZRX/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100'},
                              {'pair': 'ZRX/ETH', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.01', 'max_a': '5000'},
                              {'pair': 'ZAG/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '0.1', 'min_a': '0.00001', 'max_a': '100'},
                              {'pair': 'USD/RUB', 'min_q': '1', 'max_q': '500000', 'min_p': '0.01', 'max_p': '1000', 'min_a': '10', 'max_a': '50000000'},
                              {'pair': 'EXM/BTC', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0000001', 'max_a': '1'},
                              {'pair': 'ATMCASH/BTC', 'min_q': '10', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.000001', 'max_a': '10'},
                          ],
                          'fees': [
                              {
                                  'group': 'crypto',
                                  'title': 'Криптовалюта',
                                  'items': [
                                      {'prov': 'EXM', 'dep': '0%', 'wd': '1 EXM'},
                                      {'prov': 'BTC', 'dep': '0%', 'wd': '0.0005 BTC'},
                                      {'prov': 'LTC', 'dep': '0%', 'wd': '0.01 LTC'},
                                      {'prov': 'DOGE', 'dep': '0%', 'wd': '1 DOGE'},
                                      {'prov': 'DASH', 'dep': '0%', 'wd': '0.01 DASH'},
                                      {'prov': 'ETH', 'dep': '0%', 'wd': '0.01 ETH'},
                                      {'prov': 'WAVES', 'dep': '0%', 'wd': '0.001 WAVES'},
                                      {'prov': 'ZEC', 'dep': '0%', 'wd': '0.001 ZEC'},
                                      {'prov': 'USDT', 'dep': '0%', 'wd': '5 USDT'},
                                      {'prov': 'XMR', 'dep': '0%', 'wd': '0.05 XMR'},
                                      {'prov': 'XRP', 'dep': '0%', 'wd': '0.02 XRP'},
                                      {'prov': 'KICK', 'dep': '0%', 'wd': '50 KICK'},
                                      {'prov': 'ETC', 'dep': '0%', 'wd': '0.01 ETC'},
                                      {'prov': 'BCH', 'dep': '0%', 'wd': '0.001 BCH'},
                                      {'prov': 'BTG', 'dep': '0%', 'wd': '0.001 BTG'},
                                      {'prov': 'EOS', 'dep': '0%', 'wd': '0.05 EOS'},
                                      {'prov': 'BTCZ', 'dep': '0%', 'wd': '5 BTCZ'},
                                      {'prov': 'DXT', 'dep': '20 DXT', 'wd': '20 DXT'},
                                      {'prov': 'XLM', 'dep': '0%', 'wd': '0.01 XLM'},
                                      {'prov': 'MNX', 'dep': '0%', 'wd': '0.01 MNX'},
                                      {'prov': 'OMG', 'dep': '0.1 OMG', 'wd': '0.5 OMG'},
                                      {'prov': 'TRX', 'dep': '0%', 'wd': '1 TRX'},
                                      {'prov': 'ADA', 'dep': '0%', 'wd': '1 ADA'},
                                      {'prov': 'INK', 'dep': '10 INK', 'wd': '50 INK'},
                                      {'prov': 'NEO', 'dep': '0%', 'wd': '0%'},
                                      {'prov': 'GAS', 'dep': '0%', 'wd': '0%'},
                                      {'prov': 'ZRX', 'dep': '0%', 'wd': '1 ZRX'},
                                      {'prov': 'GNT', 'dep': '0%', 'wd': '1 GNT'},
                                      {'prov': 'GUSD', 'dep': '0%', 'wd': '0.5 GUSD'},
                                      {'prov': 'LSK', 'dep': '0%', 'wd': '0.1 LSK'},
                                      {'prov': 'XEM', 'dep': '0%', 'wd': '5 XEM'},
                                      {'prov': 'SMART', 'dep': '0%', 'wd': '0.5 SMART'},
                                      {'prov': 'QTUM', 'dep': '0%', 'wd': '0.01 QTUM'},
                                      {'prov': 'HB', 'dep': '0%', 'wd': '10 HB'},
                                      {'prov': 'DAI', 'dep': '0%', 'wd': '1 DAI'},
                                      {'prov': 'MKR', 'dep': '0%', 'wd': '0.005 MKR'},
                                      {'prov': 'MNC', 'dep': '0%', 'wd': '15 MNC'},
                                      {'prov': 'PTI', 'dep': '0%', 'wd': '10 PTI'},
                                      {'prov': 'ATMCASH', 'dep': '0%', 'wd': '5 ATMCASH'},
                                      {'prov': 'ETZ', 'dep': '0%', 'wd': '1 ETZ'},
                                      {'prov': 'USDC', 'dep': '0%', 'wd': '0.5 USDC'},
                                      {'prov': 'ROOBEE', 'dep': '0%', 'wd': '200 ROOBEE'},
                                      {'prov': 'DCR', 'dep': '0%', 'wd': '0.01 DCR'},
                                      {'prov': 'ZAG', 'dep': '0%', 'wd': '0%'},
                                      {'prov': 'BTT', 'dep': '0%', 'wd': '100 BTT'},
                                      {'prov': 'VLX', 'dep': '0%', 'wd': '1 VLX'},
                                      {'prov': 'CRON', 'dep': '0%', 'wd': '5 CRON'},
                                      {'prov': 'ONT', 'dep': '0%', 'wd': '1 ONT'},
                                      {'prov': 'ONG', 'dep': '0%', 'wd': '5 ONG'},
                                  ],
                              },
                              {
                                  'group': 'usd',
                                  'title': 'USD',
                                  'items': [
                                      {'prov': 'EX-CODE', 'dep': '', 'wd': '0.2%'},
                                      {'prov': 'Payeer', 'dep': '3.95%', 'wd': '-'},
                                      {'prov': 'AdvCash', 'dep': '0%', 'wd': '3.99%'},
                                      {'prov': 'Visa/MasterCard(Simplex)', 'dep': '4.5% + 0.5 USD', 'wd': '-'},
                                      {'prov': 'Visa', 'dep': '3.45%', 'wd': '-'},
                                  ],
                              },
                              {
                                  'group': 'eur',
                                  'title': 'EUR',
                                  'items': [
                                      {'prov': 'EX-CODE', 'dep': '', 'wd': '0.2%'},
                                      {'prov': 'Visa/MasterCard(Simplex)', 'dep': '4.5% + 0.5 EUR', 'wd': '-'},
                                      {'prov': 'Visa', 'dep': '2.95%', 'wd': '-'},
                                      {'prov': 'SEPA', 'dep': '10 EUR', 'wd': '50 EUR'},
                                  ],
                              },
                              {
                                  'group': 'rub',
                                  'title': 'RUB',
                                  'items': [
                                      {'prov': 'Payeer', 'dep': '2.49%', 'wd': '-'},
                                      {'prov': 'EX-CODE', 'dep': '', 'wd': '0.2%'},
                                      {'prov': 'Qiwi', 'dep': '0.99%', 'wd': '2%'},
                                      {'prov': 'Yandex Money', 'dep': '1.95%', 'wd': '-'},
                                      {'prov': 'Enfins', 'dep': '0%', 'wd': '1.49%'},
                                      {'prov': 'AdvCash', 'dep': '0%', 'wd': '2.49%'},
                                      {'prov': 'Visa/MasterCard', 'dep': '1.99%', 'wd': '4.49% + 60 RUB'},
                                  ],
                              },
                              {
                                  'group': 'pln',
                                  'title': 'PLN',
                                  'items': [
                                      {'prov': 'EX-CODE', 'dep': '', 'wd': '0.2%'},
                                      {'prov': 'Visa/MasterCard(Simplex)', 'dep': '4.5% + 1 PLN', 'wd': '-'},
                                  ],
                              },
                              {
                                  'group': 'try',
                                  'title': 'TRY',
                                  'items': [
                                      {'prov': 'EX-CODE', 'dep': '', 'wd': '0.2%'},
                                      {'prov': 'Visa', 'dep': '3.05%', 'wd': '-'},
                                      {'prov': 'Visa/MasterCard(Simplex)', 'dep': '4.5% + 2 TRY', 'wd': '-'},
                                  ],
                              },
                              {
                                  'group': 'uah',
                                  'title': 'UAH',
                                  'items': [
                                      {'prov': 'EX-CODE', 'dep': '', 'wd': '0.2%'},
                                      {'prov': 'Terminal', 'dep': '2.6%', 'wd': '-'},
                                      {'prov': 'Enfins', 'dep': '0%', 'wd': '1.95%'},
                                      {'prov': 'Visa/MasterCard', 'dep': '1% + 5 UAH', 'wd': '2.99%'},
                                  ],
                              },
                              {
                                  'group': 'kzt',
                                  'title': 'KZT',
                                  'items': [
                                      {'prov': 'Visa/MasterCard RoyalPay', 'dep': '-', 'wd': '2.99% + 450 KZT'},
                                      {'prov': 'Visa/MasterCard', 'dep': '3.5%', 'wd': '-'},
                                      {'prov': 'AdvCash', 'dep': '0%', 'wd': '1.49%'},
                                  ],
                              },
                          ],
                      },
                  },
              },
              'exceptions': {
                  'exact': {
                      '40005': AuthenticationError,  # Authorization error, incorrect signature
                      '40009': InvalidNonce,  #
                      '40015': ExchangeError,  # API function do not exist
                      '40016': OnMaintenance,  # {"result":false,"error":"Error 40016: Maintenance work in progress"}
                      '40017': AuthenticationError,  # Wrong API Key
                      '50052': InsufficientFunds,
                      '50054': InsufficientFunds,
                      '50304': OrderNotFound,  # "Order was not found '123456789'"(fetching order trades for an order that does not have trades yet)
                      '50173': OrderNotFound,  # "Order with id X was not found."(cancelling non-existent, closed and cancelled order)
                      '50319': InvalidOrder,  # Price by order is less than permissible minimum for self pair
                      '50321': InvalidOrder,  # Price by order is more than permissible maximum for self pair
                  },
                  'broad': {
                      'API rate limit exceeded': RateLimitExceeded,  # {"result":false,"error":"API rate limit exceeded for 99.33.55.224. Retry after 60 sec.","history":[],"begin":1579392000,"end":1579478400}
                  },
              },
          })
  
      def fetch_trading_fees(self, params={}):
          if self.options['useWebapiForFetchingFees']:
              response = self.webGetEnDocsFees(params)
              parts = response.split('<td class="th_fees_2" colspan="2">')
              numParts = len(parts)
              if numParts != 2:
                  raise NotSupported(self.id + ' fetchTradingFees format has changed')
              rest = parts[1]
              parts = rest.split('</td>')
              numParts = len(parts)
              if numParts < 2:
                  raise NotSupported(self.id + ' fetchTradingFees format has changed')
              fee = float(parts[0].replace('%', '')) * 0.01
              taker = fee
              maker = fee
              return {
                  # 'info': response,
                  'maker': maker,
                  'taker': taker,
              }
          else:
              return {
                  'maker': self.fees['trading']['maker'],
                  'taker': self.fees['trading']['taker'],
              }
  
      def parse_fixed_float_value(self, input):
          if (input is None) or (input == '-'):
              return None
          isPercentage = (input.find('%') >= 0)
          parts = input.split(' ')
          value = parts[0].replace('%', '')
          result = float(value)
          if (result > 0) and isPercentage:
              raise ExchangeError(self.id + ' parseFixedFloatValue detected an unsupported non-zero percentage-based fee ' + input)
          return result
  
      def fetch_funding_fees(self, params={}):
          response = None
          if self.options['useWebapiForFetchingFees']:
              response = self.webGetCtrlFeesAndLimits(params)
          else:
              response = self.options['feesAndLimits']
          # the code below assumes all non-zero crypto fees are fixed(for now)
          withdraw = {}
          deposit = {}
          groups = self.safe_value(response['data'], 'fees')
          groupsByGroup = self.index_by(groups, 'group')
          items = groupsByGroup['crypto']['items']
          for i in range(0, len(items)):
              item = items[i]
              code = self.safe_currency_code(self.safe_string(item, 'prov'))
              withdrawalFee = self.safe_string(item, 'wd')
              depositFee = self.safe_string(item, 'dep')
              if withdrawalFee is not None:
                  if len(withdrawalFee) > 0:
                      withdraw[code] = self.parse_fixed_float_value(withdrawalFee)
              if depositFee is not None:
                  if len(depositFee) > 0:
                      deposit[code] = self.parse_fixed_float_value(depositFee)
          # sets fiat fees to None
          fiatGroups = self.to_array(self.omit(groupsByGroup, 'crypto'))
          for i in range(0, len(fiatGroups)):
              code = self.safe_currency_code(self.safe_string(fiatGroups[i], 'title'))
              withdraw[code] = None
              deposit[code] = None
          result = {
              'info': response,
              'withdraw': withdraw,
              'deposit': deposit,
          }
          # cache them for later use
          self.options['fundingFees'] = result
          return result
  
      def fetch_currencies(self, params={}):
          fees = self.fetch_funding_fees(params)
          # todo redesign the 'fee' property in currencies
          ids = list(fees['withdraw'].keys())
          limitsByMarketId = self.index_by(fees['info']['data']['limits'], 'pair')
          marketIds = list(limitsByMarketId.keys())
          minAmounts = {}
          minPrices = {}
          minCosts = {}
          maxAmounts = {}
          maxPrices = {}
          maxCosts = {}
          for i in range(0, len(marketIds)):
              marketId = marketIds[i]
              limit = limitsByMarketId[marketId]
              baseId, quoteId = marketId.split('/')
              base = self.safe_currency_code(baseId)
              quote = self.safe_currency_code(quoteId)
              maxAmount = self.safe_float(limit, 'max_q')
              maxPrice = self.safe_float(limit, 'max_p')
              maxCost = self.safe_float(limit, 'max_a')
              minAmount = self.safe_float(limit, 'min_q')
              minPrice = self.safe_float(limit, 'min_p')
              minCost = self.safe_float(limit, 'min_a')
              minAmounts[base] = min(self.safe_float(minAmounts, base, minAmount), minAmount)
              maxAmounts[base] = max(self.safe_float(maxAmounts, base, maxAmount), maxAmount)
              minPrices[quote] = min(self.safe_float(minPrices, quote, minPrice), minPrice)
              minCosts[quote] = min(self.safe_float(minCosts, quote, minCost), minCost)
              maxPrices[quote] = max(self.safe_float(maxPrices, quote, maxPrice), maxPrice)
              maxCosts[quote] = max(self.safe_float(maxCosts, quote, maxCost), maxCost)
          result = {}
          for i in range(0, len(ids)):
              id = ids[i]
              code = self.safe_currency_code(id)
              fee = self.safe_value(fees['withdraw'], code)
              active = True
              result[code] = {
                  'id': id,
                  'code': code,
                  'name': code,
                  'active': active,
                  'fee': fee,
                  'precision': 8,
                  'limits': {
                      'amount': {
                          'min': self.safe_float(minAmounts, code),
                          'max': self.safe_float(maxAmounts, code),
                      },
                      'price': {
                          'min': self.safe_float(minPrices, code),
                          'max': self.safe_float(maxPrices, code),
                      },
                      'cost': {
                          'min': self.safe_float(minCosts, code),
                          'max': self.safe_float(maxCosts, code),
                      },
                  },
                  'info': id,
              }
          return result
  
      def fetch_markets(self, params={}):
          fees = self.fetch_trading_fees()
          response = self.publicGetPairSettings(params)
          keys = list(response.keys())
          result = []
          for i in range(0, len(keys)):
              id = keys[i]
              market = response[id]
              symbol = id.replace('_', '/')
              baseId, quoteId = symbol.split('/')
              base = self.safe_currency_code(baseId)
              quote = self.safe_currency_code(quoteId)
              result.append({
                  'id': id,
                  'symbol': symbol,
                  'base': base,
                  'quote': quote,
                  'baseId': baseId,
                  'quoteId': quoteId,
                  'active': True,
                  'taker': fees['taker'],
                  'maker': fees['maker'],
                  'limits': {
                      'amount': {
                          'min': self.safe_float(market, 'min_quantity'),
                          'max': self.safe_float(market, 'max_quantity'),
                      },
                      'price': {
                          'min': self.safe_float(market, 'min_price'),
                          'max': self.safe_float(market, 'max_price'),
                      },
                      'cost': {
                          'min': self.safe_float(market, 'min_amount'),
                          'max': self.safe_float(market, 'max_amount'),
                      },
                  },
                  'precision': {
                      'amount': 8,
                      'price': 8,
                  },
                  'info': market,
              })
          return result
  
      def fetch_balance(self, params={}):
          self.load_markets()
          response = self.privatePostUserInfo(params)
          result = {'info': response}
          codes = list(self.currencies.keys())
          for i in range(0, len(codes)):
              code = codes[i]
              currencyId = self.currencyId(code)
              account = self.account()
              if currencyId in response['balances']:
                  account['free'] = self.safe_float(response['balances'], currencyId)
              if currencyId in response['reserved']:
                  account['used'] = self.safe_float(response['reserved'], currencyId)
              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 = {
              'pair': market['id'],
          }
          if limit is not None:
              request['limit'] = limit
          response = self.publicGetOrderBook(self.extend(request, params))
          result = self.safe_value(response, market['id'])
          return self.parse_order_book(result, None, 'bid', 'ask')
  
      def fetch_order_books(self, symbols=None, limit=None, params={}):
          self.load_markets()
          ids = None
          if symbols is None:
              ids = ','.join(self.ids)
              # max URL length is 2083 symbols, including http schema, hostname, tld, etc...
              if len(ids) > 2048:
                  numIds = len(self.ids)
                  raise ExchangeError(self.id + ' has ' + str(numIds) + ' symbols exceeding max URL length, you are required to specify a list of symbols in the first argument to fetchOrderBooks')
          else:
              ids = self.market_ids(symbols)
              ids = ','.join(ids)
          request = {
              'pair': ids,
          }
          if limit is not None:
              request['limit'] = limit
          response = self.publicGetOrderBook(self.extend(request, params))
          result = {}
          marketIds = list(response.keys())
          for i in range(0, len(marketIds)):
              marketId = marketIds[i]
              symbol = marketId
              if marketId in self.markets_by_id:
                  market = self.markets_by_id[marketId]
                  symbol = market['symbol']
              result[symbol] = self.parse_order_book(response[marketId], None, 'bid', 'ask')
          return result
  
      def parse_ticker(self, ticker, market=None):
          timestamp = self.safe_timestamp(ticker, 'updated')
          symbol = None
          if market is not None:
              symbol = market['symbol']
          last = self.safe_float(ticker, 'last_trade')
          return {
              'symbol': symbol,
              'timestamp': timestamp,
              'datetime': self.iso8601(timestamp),
              'high': self.safe_float(ticker, 'high'),
              'low': self.safe_float(ticker, 'low'),
              'bid': self.safe_float(ticker, 'buy_price'),
              'bidVolume': None,
              'ask': self.safe_float(ticker, 'sell_price'),
              'askVolume': None,
              'vwap': None,
              'open': None,
              'close': last,
              'last': last,
              'previousClose': None,
              'change': None,
              'percentage': None,
              'average': self.safe_float(ticker, 'avg'),
              'baseVolume': self.safe_float(ticker, 'vol'),
              'quoteVolume': self.safe_float(ticker, 'vol_curr'),
              'info': ticker,
          }
  
      def fetch_tickers(self, symbols=None, params={}):
          self.load_markets()
          response = self.publicGetTicker(params)
          result = {}
          ids = list(response.keys())
          for i in range(0, len(ids)):
              id = ids[i]
              market = self.markets_by_id[id]
              symbol = market['symbol']
              ticker = response[id]
              result[symbol] = self.parse_ticker(ticker, market)
          return result
  
      def fetch_ticker(self, symbol, params={}):
          self.load_markets()
          response = self.publicGetTicker(params)
          market = self.market(symbol)
          return self.parse_ticker(response[market['id']], market)
  
      def parse_trade(self, trade, market=None):
          timestamp = self.safe_timestamp(trade, 'date')
          fee = None
          symbol = None
          id = self.safe_string(trade, 'trade_id')
          orderId = self.safe_string(trade, 'order_id')
          price = self.safe_float(trade, 'price')
          amount = self.safe_float(trade, 'quantity')
          cost = self.safe_float(trade, 'amount')
          side = self.safe_string(trade, 'type')
          type = None
          if market is not None:
              symbol = market['symbol']
              if market['taker'] != market['maker']:
                  raise ExchangeError(self.id + ' parseTrade can not deduce proper fee costs, taker and maker fees now differ')
              if (side == 'buy') and (amount is not None):
                  fee = {
                      'currency': market['base'],
                      'cost': amount * market['taker'],
                      'rate': market['taker'],
                  }
              elif (side == 'sell') and (cost is not None):
                  fee = {
                      'currency': market['quote'],
                      'cost': cost * market['taker'],
                      'rate': market['taker'],
                  }
          return {
              'id': id,
              'info': trade,
              'timestamp': timestamp,
              'datetime': self.iso8601(timestamp),
              'symbol': symbol,
              'order': orderId,
              'type': type,
              'side': side,
              'takerOrMaker': None,
              '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 = {
              'pair': market['id'],
          }
          response = self.publicGetTrades(self.extend(request, params))
          data = self.safe_value(response, market['id'], [])
          return self.parse_trades(data, market, since, limit)
  
      def fetch_my_trades(self, symbol=None, since=None, limit=None, params={}):
          # a symbol is required but it can be a single string, or a non-empty array
          if symbol is None:
              raise ArgumentsRequired(self.id + ' fetchMyTrades() requires a symbol argument(a single symbol or an array)')
          self.load_markets()
          pair = None
          market = None
          if isinstance(symbol, list):
              numSymbols = len(symbol)
              if numSymbols < 1:
                  raise ArgumentsRequired(self.id + ' fetchMyTrades() requires a non-empty symbol array')
              marketIds = self.market_ids(symbol)
              pair = ','.join(marketIds)
          else:
              market = self.market(symbol)
              pair = market['id']
          request = {
              'pair': pair,
          }
          if limit is not None:
              request['limit'] = limit
          response = self.privatePostUserTrades(self.extend(request, params))
          result = []
          marketIds = list(response.keys())
          for i in range(0, len(marketIds)):
              marketId = marketIds[i]
              symbol = None
              if marketId in self.markets_by_id:
                  market = self.markets_by_id[marketId]
                  symbol = market['symbol']
              else:
                  baseId, quoteId = marketId.split('_')
                  base = self.safe_currency_code(baseId)
                  quote = self.safe_currency_code(quoteId)
                  symbol = base + '/' + quote
              items = response[marketId]
              trades = self.parse_trades(items, market, since, limit, {
                  'symbol': symbol,
              })
              result = self.array_concat(result, trades)
          return self.filter_by_since_limit(result, since, limit)
  
      def create_order(self, symbol, type, side, amount, price=None, params={}):
          self.load_markets()
          prefix = (type + '_') if (type == 'market') else ''
          market = self.market(symbol)
          if (type == 'market') and (price is None):
              price = 0
          request = {
              'pair': market['id'],
              'quantity': self.amount_to_precision(symbol, amount),
              'type': prefix + side,
              'price': self.price_to_precision(symbol, price),
          }
          response = self.privatePostOrderCreate(self.extend(request, params))
          id = self.safe_string(response, 'order_id')
          timestamp = self.milliseconds()
          amount = float(amount)
          price = float(price)
          status = 'open'
          order = {
              'id': id,
              'info': response,
              'timestamp': timestamp,
              'datetime': self.iso8601(timestamp),
              'lastTradeTimestamp': None,
              'status': status,
              'symbol': symbol,
              'type': type,
              'side': side,
              'price': price,
              'cost': price * amount,
              'amount': amount,
              'remaining': amount,
              'filled': 0.0,
              'fee': None,
              'trades': None,
          }
          self.orders[id] = order
          return order
  
      def cancel_order(self, id, symbol=None, params={}):
          self.load_markets()
          request = {'order_id': id}
          response = self.privatePostOrderCancel(self.extend(request, params))
          if id in self.orders:
              self.orders[id]['status'] = 'canceled'
          return response
  
      def fetch_order(self, id, symbol=None, params={}):
          self.load_markets()
          try:
              request = {
                  'order_id': str(id),
              }
              response = self.privatePostOrderTrades(self.extend(request, params))
              #
              #     {
              #         "type": "buy",
              #         "in_currency": "BTC",
              #         "in_amount": "1",
              #         "out_currency": "USD",
              #         "out_amount": "100",
              #         "trades": [
              #             {
              #                 "trade_id": 3,
              #                 "date": 1435488248,
              #                 "type": "buy",
              #                 "pair": "BTC_USD",
              #                 "order_id": 12345,
              #                 "quantity": 1,
              #                 "price": 100,
              #                 "amount": 100
              #             }
              #         ]
              #     }
              #
              order = self.parse_order(response)
              return self.extend(order, {
                  'id': str(id),
              })
          except Exception as e:
              if isinstance(e, OrderNotFound):
                  if id in self.orders:
                      return self.orders[id]
          raise OrderNotFound(self.id + ' fetchOrder order id ' + str(id) + ' not found in cache.')
  
      def fetch_order_trades(self, id, symbol=None, since=None, limit=None, params={}):
          market = None
          if symbol is not None:
              market = self.market(symbol)
          request = {
              'order_id': str(id),
          }
          response = self.privatePostOrderTrades(self.extend(request, params))
          trades = self.safe_value(response, 'trades')
          return self.parse_trades(trades, market, since, limit)
  
      def update_cached_orders(self, openOrders, symbol):
          # update local cache with open orders
          for j in range(0, len(openOrders)):
              id = openOrders[j]['id']
              self.orders[id] = openOrders[j]
          openOrdersIndexedById = self.index_by(openOrders, 'id')
          cachedOrderIds = list(self.orders.keys())
          for k in range(0, len(cachedOrderIds)):
              # match each cached order to an order in the open orders array
              # possible reasons why a cached order may be missing in the open orders array:
              # - order was closed or canceled -> update cache
              # - symbol mismatch(e.g. cached BTC/USDT, fetched ETH/USDT) -> skip
              id = cachedOrderIds[k]
              order = self.orders[id]
              if not (id in openOrdersIndexedById):
                  # cached order is not in open orders array
                  # if we fetched orders by symbol and it doesn't match the cached order -> won't update the cached order
                  if symbol is not None and symbol != order['symbol']:
                      continue
                  # order is cached but not present in the list of open orders -> mark the cached order as closed
                  if order['status'] == 'open':
                      order = self.extend(order, {
                          'status': 'closed',  # likewise it might have been canceled externally(unnoticed by "us")
                          'cost': None,
                          'filled': order['amount'],
                          'remaining': 0.0,
                      })
                      if order['cost'] is None:
                          if order['filled'] is not None:
                              order['cost'] = order['filled'] * order['price']
                      self.orders[id] = order
          return self.to_array(self.orders)
  
      def fetch_orders(self, symbol=None, since=None, limit=None, params={}):
          self.load_markets()
          response = self.privatePostUserOpenOrders(params)
          marketIds = list(response.keys())
          orders = []
          for i in range(0, len(marketIds)):
              marketId = marketIds[i]
              market = None
              if marketId in self.markets_by_id:
                  market = self.markets_by_id[marketId]
              parsedOrders = self.parse_orders(response[marketId], market)
              orders = self.array_concat(orders, parsedOrders)
          self.update_cached_orders(orders, symbol)
          return self.filter_by_symbol_since_limit(self.to_array(self.orders), symbol, since, limit)
  
      def fetch_open_orders(self, symbol=None, since=None, limit=None, params={}):
          self.fetch_orders(symbol, since, limit, params)
          orders = self.filter_by(self.orders, 'status', 'open')
          return self.filter_by_symbol_since_limit(orders, symbol, since, limit)
  
      def fetch_closed_orders(self, symbol=None, since=None, limit=None, params={}):
          self.fetch_orders(symbol, since, limit, params)
          orders = self.filter_by(self.orders, 'status', 'closed')
          return self.filter_by_symbol_since_limit(orders, symbol, since, limit)
  
      def parse_order(self, order, market=None):
          #
          # fetchOrders, fetchOpenOrders, fetchClosedOrders
          #
          #     {
          #         "order_id": "14",
          #         "created": "1435517311",
          #         "type": "buy",
          #         "pair": "BTC_USD",
          #         "price": "100",
          #         "quantity": "1",
          #         "amount": "100"
          #     }
          #
          # fetchOrder
          #
          #     {
          #         "type": "buy",
          #         "in_currency": "BTC",
          #         "in_amount": "1",
          #         "out_currency": "USD",
          #         "out_amount": "100",
          #         "trades": [
          #             {
          #                 "trade_id": 3,
          #                 "date": 1435488248,
          #                 "type": "buy",
          #                 "pair": "BTC_USD",
          #                 "order_id": 12345,
          #                 "quantity": 1,
          #                 "price": 100,
          #                 "amount": 100
          #             }
          #         ]
          #     }
          #
          id = self.safe_string(order, 'order_id')
          timestamp = self.safe_timestamp(order, 'created')
          symbol = None
          side = self.safe_string(order, 'type')
          if market is None:
              marketId = None
              if 'pair' in order:
                  marketId = order['pair']
              elif ('in_currency' in order) and ('out_currency' in order):
                  if side == 'buy':
                      marketId = order['in_currency'] + '_' + order['out_currency']
                  else:
                      marketId = order['out_currency'] + '_' + order['in_currency']
              if (marketId is not None) and (marketId in self.markets_by_id):
                  market = self.markets_by_id[marketId]
          amount = self.safe_float(order, 'quantity')
          if amount is None:
              amountField = 'in_amount' if (side == 'buy') else 'out_amount'
              amount = self.safe_float(order, amountField)
          price = self.safe_float(order, 'price')
          cost = self.safe_float(order, 'amount')
          filled = 0.0
          trades = []
          transactions = self.safe_value(order, 'trades', [])
          feeCost = None
          lastTradeTimestamp = None
          average = None
          numTransactions = len(transactions)
          if numTransactions > 0:
              feeCost = 0
              for i in range(0, numTransactions):
                  trade = self.parse_trade(transactions[i], market)
                  if id is None:
                      id = trade['order']
                  if timestamp is None:
                      timestamp = trade['timestamp']
                  if timestamp > trade['timestamp']:
                      timestamp = trade['timestamp']
                  filled = self.sum(filled, trade['amount'])
                  feeCost = self.sum(feeCost, trade['fee']['cost'])
                  trades.append(trade)
              lastTradeTimestamp = trades[numTransactions - 1]['timestamp']
          remaining = None
          if amount is not None:
              remaining = amount - filled
          status = self.safe_string(order, 'status')  # in case we need to redefine it for canceled orders
          if filled >= amount:
              status = 'closed'
          else:
              status = 'open'
          if market is None:
              market = self.get_market_from_trades(trades)
          feeCurrency = None
          if market is not None:
              symbol = market['symbol']
              feeCurrency = market['quote']
          if cost is None:
              if price is not None:
                  cost = price * filled
          else:
              if filled > 0:
                  if average is None:
                      average = cost / filled
                  if price is None:
                      price = cost / filled
          fee = {
              'cost': feeCost,
              'currency': feeCurrency,
          }
          return {
              'id': id,
              'datetime': self.iso8601(timestamp),
              'timestamp': timestamp,
              'lastTradeTimestamp': lastTradeTimestamp,
              'status': status,
              'symbol': symbol,
              'type': 'limit',
              'side': side,
              'price': price,
              'cost': cost,
              'amount': amount,
              'filled': filled,
              'remaining': remaining,
              'average': average,
              'trades': trades,
              'fee': fee,
              'info': order,
          }
  
      def fetch_deposit_address(self, code, params={}):
          self.load_markets()
          response = self.privatePostDepositAddress(params)
          depositAddress = self.safe_string(response, code)
          address = None
          tag = None
          if depositAddress:
              addressAndTag = depositAddress.split(',')
              address = addressAndTag[0]
              numParts = len(addressAndTag)
              if numParts > 1:
                  tag = addressAndTag[1]
          self.check_address(address)
          return {
              'currency': code,
              'address': address,
              'tag': tag,
              'info': response,
          }
  
      def get_market_from_trades(self, trades):
          tradesBySymbol = self.index_by(trades, 'pair')
          symbols = list(tradesBySymbol.keys())
          numSymbols = len(symbols)
          if numSymbols == 1:
              return self.markets[symbols[0]]
          return None
  
      def calculate_fee(self, symbol, type, side, amount, price, takerOrMaker='taker', params={}):
          market = self.markets[symbol]
          rate = market[takerOrMaker]
          cost = float(self.cost_to_precision(symbol, amount * rate))
          key = 'quote'
          if side == 'sell':
              cost *= price
          else:
              key = 'base'
          return {
              'type': takerOrMaker,
              'currency': market[key],
              'rate': rate,
              'cost': float(self.fee_to_precision(symbol, cost)),
          }
  
      def withdraw(self, code, amount, address, tag=None, params={}):
          self.load_markets()
          currency = self.currency(code)
          request = {
              'amount': amount,
              'currency': currency['id'],
              'address': address,
          }
          if tag is not None:
              request['invoice'] = tag
          response = self.privatePostWithdrawCrypt(self.extend(request, params))
          return {
              'info': response,
              'id': response['task_id'],
          }
  
      def parse_transaction_status(self, status):
          statuses = {
              'transferred': 'ok',
              'paid': 'ok',
              'pending': 'pending',
              'processing': 'pending',
          }
          return self.safe_string(statuses, status, status)
  
      def parse_transaction(self, transaction, currency=None):
          #
          # fetchTransactions
          #
          #          {
          #            "dt": 1461841192,
          #            "type": "deposit",
          #            "curr": "RUB",
          #            "status": "processing",
          #            "provider": "Qiwi(LA) [12345]",
          #            "amount": "1",
          #            "account": "",
          #            "txid": "ec46f784ad976fd7f7539089d1a129fe46...",
          #          }
          #
          timestamp = self.safe_timestamp(transaction, 'dt')
          amount = self.safe_float(transaction, 'amount')
          if amount is not None:
              amount = abs(amount)
          status = self.parse_transaction_status(self.safe_string(transaction, 'status'))
          txid = self.safe_string(transaction, 'txid')
          type = self.safe_string(transaction, 'type')
          currencyId = self.safe_string(transaction, 'curr')
          code = self.safe_currency_code(currencyId, currency)
          address = self.safe_string(transaction, 'account')
          if address is not None:
              parts = address.split(':')
              numParts = len(parts)
              if numParts == 2:
                  address = parts[1].replace(' ', '')
          fee = None
          # fixed funding fees only(for now)
          if not self.fees['funding']['percentage']:
              key = 'withdraw' if (type == 'withdrawal') else 'deposit'
              feeCost = self.safe_float(self.options['fundingFees'][key], code)
              # users don't pay for cashbacks, no fees for that
              provider = self.safe_string(transaction, 'provider')
              if provider == 'cashback':
                  feeCost = 0
              if feeCost is not None:
                  # withdrawal amount includes the fee
                  if type == 'withdrawal':
                      amount = amount - feeCost
                  fee = {
                      'cost': feeCost,
                      'currency': code,
                      'rate': None,
                  }
          return {
              'info': transaction,
              'id': None,
              'currency': code,
              'amount': amount,
              'address': address,
              'tag': None,  # refix it properly
              'status': status,
              'type': type,
              'updated': None,
              'txid': txid,
              'timestamp': timestamp,
              'datetime': self.iso8601(timestamp),
              'fee': fee,
          }
  
      def fetch_transactions(self, code=None, since=None, limit=None, params={}):
          self.load_markets()
          request = {}
          if since is not None:
              request['date'] = int(since / 1000)
          currency = None
          if code is not None:
              currency = self.currency(code)
          response = self.privatePostWalletHistory(self.extend(request, params))
          #
          #     {
          #       "result": True,
          #       "error": "",
          #       "begin": "1493942400",
          #       "end": "1494028800",
          #       "history": [
          #          {
          #            "dt": 1461841192,
          #            "type": "deposit",
          #            "curr": "RUB",
          #            "status": "processing",
          #            "provider": "Qiwi(LA) [12345]",
          #            "amount": "1",
          #            "account": "",
          #            "txid": "ec46f784ad976fd7f7539089d1a129fe46...",
          #          },
          #          {
          #            "dt": 1463414785,
          #            "type": "withdrawal",
          #            "curr": "USD",
          #            "status": "paid",
          #            "provider": "EXCODE",
          #            "amount": "-1",
          #            "account": "EX-CODE_19371_USDda...",
          #            "txid": "",
          #          },
          #       ],
          #     }
          #
          return self.parse_transactions(response['history'], currency, since, limit)
  
      def sign(self, path, api='public', method='GET', params={}, headers=None, body=None):
          url = self.urls['api'][api] + '/'
          if api != 'web':
              url += self.version + '/'
          url += path
          if (api == 'public') or (api == 'web'):
              if params:
                  url += '?' + self.urlencode(params)
          elif api == 'private':
              self.check_required_credentials()
              nonce = self.nonce()
              body = self.urlencode(self.extend({'nonce': nonce}, params))
              headers = {
                  'Content-Type': 'application/x-www-form-urlencoded',
                  'Key': self.apiKey,
                  'Sign': self.hmac(self.encode(body), self.encode(self.secret), hashlib.sha512),
              }
          return {'url': url, 'method': method, 'body': body, 'headers': headers}
  
      def nonce(self):
          return self.milliseconds()
  
      def handle_errors(self, httpCode, reason, url, method, headers, body, response, requestHeaders, requestBody):
          if response is None:
              return  # fallback to default error handler
          if 'result' in response:
              #
              #     {"result":false,"error":"Error 50052: Insufficient funds"}
              #
              success = self.safe_value(response, 'result', False)
              if isinstance(success, basestring):
                  if (success == 'true') or (success == '1'):
                      success = True
                  else:
                      success = False
              if not success:
                  code = None
                  message = self.safe_string(response, 'error')
                  errorParts = message.split(':')
                  numParts = len(errorParts)
                  if numParts > 1:
                      errorSubParts = errorParts[0].split(' ')
                      numSubParts = len(errorSubParts)
                      code = errorSubParts[1] if (numSubParts > 1) else errorSubParts[0]
                  feedback = self.id + ' ' + body
                  self.throw_exactly_matched_exception(self.exceptions['exact'], code, feedback)
                  self.throw_broadly_matched_exception(self.exceptions['broad'], message, feedback)
                  raise ExchangeError(feedback)
  