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.async_support.base.exchange import Exchange
  import hashlib
  from ccxt.base.errors import ExchangeError
  from ccxt.base.errors import AuthenticationError
  from ccxt.base.errors import PermissionDenied
  from ccxt.base.errors import BadRequest
  from ccxt.base.errors import BadSymbol
  from ccxt.base.errors import InsufficientFunds
  from ccxt.base.errors import AddressPending
  from ccxt.base.errors import InvalidOrder
  from ccxt.base.errors import OrderNotFound
  from ccxt.base.errors import RateLimitExceeded
  from ccxt.base.errors import RequestTimeout
  from ccxt.base.decimal_to_precision import ROUND
  from ccxt.base.precise import Precise
  
  
  class vcc(Exchange):
  
      def describe(self):
          return self.deep_extend(super(vcc, self).describe(), {
              'id': 'vcc',
              'name': 'VCC Exchange',
              'countries': ['VN'],  # Vietnam
              'rateLimit': 1000,
              'version': 'v3',
              'has': {
                  'cancelAllOrders': True,
                  'cancelOrder': True,
                  'createOrder': True,
                  'editOrder': False,
                  'fetchBalance': True,
                  'fetchClosedOrders': True,
                  'fetchCurrencies': True,
                  'fetchDepositAddress': True,
                  'fetchDeposits': True,
                  'fetchMarkets': True,
                  'fetchMyTrades': True,
                  'fetchOHLCV': True,
                  'fetchOpenOrders': True,
                  'fetchOrder': True,
                  'fetchOrderBook': True,
                  'fetchOrders': False,
                  'fetchTicker': 'emulated',
                  'fetchTickers': True,
                  'fetchTrades': True,
                  'fetchTradingFees': False,
                  'fetchTransactions': True,
                  'fetchWithdrawals': True,
              },
              'timeframes': {
                  '1m': '60000',
                  '5m': '300000',
                  '15m': '900000',
                  '30m': '1800000',
                  '1h': '3600000',
                  '2h': '7200000',
                  '4h': '14400000',
                  '6h': '21600000',
                  '12h': '43200000',
                  '1d': '86400000',
                  '1w': '604800000',
              },
              'urls': {
                  'logo': 'https://user-images.githubusercontent.com/1294454/100545356-8427f500-326c-11eb-9539-7d338242d61b.jpg',
                  'api': {
                      'public': 'https://api.vcc.exchange',
                      'private': 'https://api.vcc.exchange',
                  },
                  'www': 'https://vcc.exchange',
                  'doc': [
                      'https://vcc.exchange/api',
                  ],
                  'fees': 'https://support.vcc.exchange/hc/en-us/articles/360016401754',
                  'referral': 'https://vcc.exchange?ref=l4xhrH',
              },
              'api': {
                  'public': {
                      'get': [
                          'summary',
                          'exchange_info',
                          'assets',  # Available Currencies
                          'ticker',  # Ticker list for all symbols
                          'trades/{market_pair}',  # Recent trades
                          'orderbook/{market_pair}',  # Orderbook
                          'chart/bars',  # Candles
                          'tick_sizes',
                      ],
                  },
                  'private': {
                      'get': [
                          'user',
                          'balance',  # Get trading balance
                          'orders/{order_id}',  # Get a single order by order_id
                          'orders/open',  # Get open orders
                          'orders',  # Get closed orders
                          'orders/trades',  # Get trades history
                          'deposit-address',  # Generate or get deposit address
                          'transactions',  # Get deposit/withdrawal history
                      ],
                      'post': [
                          'orders',  # Create new order
                      ],
                      'put': [
                          'orders/{order_id}/cancel',  # Cancel order
                          'orders/cancel-by-type',
                          'orders/cancel-all',
                      ],
                  },
              },
              'fees': {
                  'trading': {
                      'tierBased': False,
                      'percentage': True,
                      'maker': 0.2 / 100,
                      'taker': 0.2 / 100,
                  },
              },
              'exceptions': {
                  'exact': {},
                  'broad': {
                      'limit may not be greater than': BadRequest,  # {"message":"The given data was invalid.","errors":{"limit":["The limit may not be greater than 1000."]}}
                      'Insufficient balance': InsufficientFunds,  # {"message":"Insufficient balance."}
                      'Unauthenticated': AuthenticationError,  # {"message":"Unauthenticated."}  # wrong api key
                      'signature is invalid': AuthenticationError,  # {"message":"The given data was invalid.","errors":{"signature":["HMAC signature is invalid"]}}
                      'Timeout': RequestTimeout,  # {"code":504,"message":"Gateway Timeout","description":""}
                      'Too many requests': RateLimitExceeded,  # {"code":429,"message":"Too many requests","description":"Too many requests"}
                      'quantity field is required': InvalidOrder,  # {"message":"The given data was invalid.","errors":{"quantity":["The quantity field is required when type is market."]}}
                      'price field is required': InvalidOrder,  # {"message":"The given data was invalid.","errors":{"price":["The price field is required when type is limit."]}}
                      'error_security_level': PermissionDenied,  # {"message":"error_security_level"}
                      'pair is invalid': BadSymbol,  # {"message":"The given data was invalid.","errors":{"coin":["Trading pair is invalid","Trading pair is offline"]}}
                      # {"message":"The given data was invalid.","errors":{"type":["The selected type is invalid."]}}
                      # {"message":"The given data was invalid.","errors":{"trade_type":["The selected trade type is invalid."]}}
                      'type is invalid': InvalidOrder,
                      'Data not found': OrderNotFound,  # {"message":"Data not found"}
                  },
              },
          })
  
      async def fetch_markets(self, params={}):
          response = await self.publicGetExchangeInfo(params)
          #
          #     {
          #         "message":null,
          #         "dataVersion":"4677e56a42f0c29872f3a6e75f5d39d2f07c748c",
          #         "data":{
          #             "timezone":"UTC",
          #             "serverTime":1605821914333,
          #             "symbols":[
          #                 {
          #                     "id":"btcvnd",
          #                     "symbol":"BTC\/VND",
          #                     "coin":"btc",
          #                     "currency":"vnd",
          #                     "baseId":1,
          #                     "quoteId":0,
          #                     "active":true,
          #                     "base_precision":"0.0000010000",
          #                     "quote_precision":"1.0000000000",
          #                     "minimum_quantity":"0.0000010000",
          #                     "minimum_amount":"250000.0000000000",
          #                     "precision":{"price":0,"amount":6,"cost":6},
          #                     "limits":{
          #                         "amount":{"min":"0.0000010000"},
          #                         "price":{"min":"1.0000000000"},
          #                         "cost":{"min":"250000.0000000000"},
          #                     },
          #                 },
          #             ],
          #         },
          #     }
          #
          data = self.safe_value(response, 'data')
          markets = self.safe_value(data, 'symbols')
          result = []
          for i in range(0, len(markets)):
              market = self.safe_value(markets, i)
              symbol = self.safe_string(market, 'symbol')
              id = symbol.replace('/', '_')
              baseId = self.safe_string(market, 'coin')
              quoteId = self.safe_string(market, 'currency')
              base = self.safe_currency_code(baseId)
              quote = self.safe_currency_code(quoteId)
              active = self.safe_value(market, 'active')
              precision = self.safe_value(market, 'precision', {})
              limits = self.safe_value(market, 'limits', {})
              amountLimits = self.safe_value(limits, 'amount', {})
              priceLimits = self.safe_value(limits, 'price', {})
              costLimits = self.safe_value(limits, 'cost', {})
              entry = {
                  'info': market,
                  'id': id,
                  'symbol': symbol,
                  'base': base,
                  'quote': quote,
                  'baseId': baseId,
                  'quoteId': quoteId,
                  'active': active,
                  'precision': {
                      'price': self.safe_integer(precision, 'price'),
                      'amount': self.safe_integer(precision, 'amount'),
                      'cost': self.safe_integer(precision, 'cost'),
                  },
                  'limits': {
                      'amount': {
                          'min': self.safe_number(amountLimits, 'min'),
                          'max': None,
                      },
                      'price': {
                          'min': self.safe_number(priceLimits, 'min'),
                          'max': None,
                      },
                      'cost': {
                          'min': self.safe_number(costLimits, 'min'),
                          'max': None,
                      },
                  },
              }
              result.append(entry)
          return result
  
      async def fetch_currencies(self, params={}):
          response = await self.publicGetAssets(params)
          #
          #     {
          #         "message":null,
          #         "dataVersion":"2514c8012d94ea375018fc13e0b5d4d896e435df",
          #         "data":{
          #             "BTC":{
          #                 "name":"Bitcoin",
          #                 "unified_cryptoasset_id":1,
          #                 "can_withdraw":1,
          #                 "can_deposit":1,
          #                 "min_withdraw":"0.0011250000",
          #                 "max_withdraw":"100.0000000000",
          #                 "maker_fee":"0.002",
          #                 "taker_fee":"0.002",
          #                 "decimal":8,
          #                 "withdrawal_fee":"0.0006250000",
          #             },
          #         },
          #     }
          #
          result = {}
          data = self.safe_value(response, 'data')
          ids = list(data.keys())
          for i in range(0, len(ids)):
              id = self.safe_string_lower(ids, i)
              currency = self.safe_value(data, ids[i])
              code = self.safe_currency_code(id)
              canDeposit = self.safe_value(currency, 'can_deposit')
              canWithdraw = self.safe_value(currency, 'can_withdraw')
              active = (canDeposit and canWithdraw)
              result[code] = {
                  'id': id,
                  'code': code,
                  'name': self.safe_string(currency, 'name'),
                  'active': active,
                  'fee': self.safe_number(currency, 'withdrawal_fee'),
                  'precision': self.safe_integer(currency, 'decimal'),
                  'limits': {
                      'withdraw': {
                          'min': self.safe_number(currency, 'min_withdraw'),
                          'max': self.safe_number(currency, 'max_withdraw'),
                      },
                  },
              }
          return result
  
      async def fetch_trading_fee(self, symbol, params={}):
          await self.load_markets()
          market = self.market(symbol)
          request = self.extend({
              'symbol': market['id'],
          }, self.omit(params, 'symbol'))
          response = await self.privateGetTradingFeeSymbol(request)
          #
          #     {
          #         takeLiquidityRate: '0.001',
          #         provideLiquidityRate: '-0.0001'
          #     }
          #
          return {
              'info': response,
              'maker': self.safe_number(response, 'provideLiquidityRate'),
              'taker': self.safe_number(response, 'takeLiquidityRate'),
          }
  
      async def fetch_balance(self, params={}):
          await self.load_markets()
          response = await self.privateGetBalance(params)
          #
          #     {
          #         "message":null,
          #         "dataVersion":"7168e6c99e90f60673070944d987988eef7d91fa",
          #         "data":{
          #             "vnd":{"balance":0,"available_balance":0},
          #             "btc":{"balance":0,"available_balance":0},
          #             "eth":{"balance":0,"available_balance":0},
          #         },
          #     }
          #
          data = self.safe_value(response, 'data')
          result = {
              'info': response,
              'timestamp': None,
              'datetime': None,
          }
          currencyIds = list(data.keys())
          for i in range(0, len(currencyIds)):
              currencyId = currencyIds[i]
              code = self.safe_currency_code(currencyId)
              balance = self.safe_value(data, currencyId)
              account = self.account()
              account['free'] = self.safe_string(balance, 'available_balance')
              account['total'] = self.safe_string(balance, 'balance')
              result[code] = account
          return self.parse_balance(result, False)
  
      def parse_ohlcv(self, ohlcv, market=None):
          #
          #     {
          #         "low":"415805323.0000000000",
          #         "high":"415805323.0000000000",
          #         "open":"415805323.0000000000",
          #         "close":"415805323.0000000000",
          #         "time":"1605845940000",
          #         "volume":"0.0065930000",
          #         "opening_time":1605845963263,
          #         "closing_time":1605845963263
          #     }
          #
          return [
              self.safe_integer(ohlcv, 'time'),
              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'),
          ]
  
      async def fetch_ohlcv(self, symbol, timeframe='1m', since=None, limit=None, params={}):
          await self.load_markets()
          market = self.market(symbol)
          request = {
              'coin': market['baseId'],
              'currency': market['quoteId'],
              'resolution': self.timeframes[timeframe],
          }
          limit = 100 if (limit is None) else limit
          limit = min(100, limit)
          duration = self.parse_timeframe(timeframe)
          if since is None:
              end = self.seconds()
              request['to'] = end
              request['from'] = end - limit * duration
          else:
              start = int(since / 1000)
              request['from'] = start
              request['to'] = self.sum(start, limit * duration)
          response = await self.publicGetChartBars(self.extend(request, params))
          #
          #     [
          #         {"low":"415805323.0000000000","high":"415805323.0000000000","open":"415805323.0000000000","close":"415805323.0000000000","time":"1605845940000","volume":"0.0065930000","opening_time":1605845963263,"closing_time":1605845963263},
          #         {"low":"416344148.0000000000","high":"416344148.0000000000","open":"415805323.0000000000","close":"416344148.0000000000","time":"1605846000000","volume":"0.0052810000","opening_time":1605846011490,"closing_time":1605846011490},
          #         {"low":"416299269.0000000000","high":"417278376.0000000000","open":"416344148.0000000000","close":"417278376.0000000000","time":"1605846060000","volume":"0.0136750000","opening_time":1605846070727,"closing_time":1605846102282},
          #     ]
          #
          return self.parse_ohlcvs(response, market, timeframe, since, limit)
  
      async def fetch_order_book(self, symbol, limit=None, params={}):
          await self.load_markets()
          market = self.market(symbol)
          request = {
              'market_pair': market['id'],
              # 'depth': 0,  # 0 = full orderbook, 5, 10, 20, 50, 100, 500
              'level': 2,  # 1 = best bidask, 2 = aggregated by price, 3 = no aggregation
          }
          if limit is not None:
              if (limit != 0) and (limit != 5) and (limit != 10) and (limit != 20) and (limit != 50) and (limit != 100) and (limit != 500):
                  raise BadRequest(self.id + ' fetchOrderBook limit must be 0, 5, 10, 20, 50, 100, 500 if specified')
              request['depth'] = limit
          response = await self.publicGetOrderbookMarketPair(self.extend(request, params))
          #
          #     {
          #         "message":null,
          #         "dataVersion":"376cee43af26deabcd3762ab11a876b6e7a71e82",
          #         "data":{
          #             "bids":[
          #                 ["413342637.0000000000","0.165089"],
          #                 ["413274576.0000000000","0.03"],
          #                 ["413274574.0000000000","0.03"],
          #             ],
          #             "asks":[
          #                 ["416979125.0000000000","0.122835"],
          #                 ["417248934.0000000000","0.030006"],
          #                 ["417458879.0000000000","0.1517"],
          #             ],
          #             "timestamp":"1605841619147"
          #         }
          #     }
          #
          data = self.safe_value(response, 'data')
          timestamp = self.safe_value(data, 'timestamp')
          return self.parse_order_book(data, symbol, timestamp, 'bids', 'asks', 0, 1)
  
      def parse_ticker(self, ticker, market=None):
          #
          #     {
          #         "base_id":1,
          #         "quote_id":0,
          #         "last_price":"411119457",
          #         "max_price":"419893173.0000000000",
          #         "min_price":"401292577.0000000000",
          #         "open_price":null,
          #         "base_volume":"10.5915050000",
          #         "quote_volume":"4367495977.4484430060",
          #         "isFrozen":0
          #     }
          #
          timestamp = self.milliseconds()
          baseVolume = self.safe_number(ticker, 'base_volume')
          quoteVolume = self.safe_number(ticker, 'quote_volume')
          open = self.safe_number(ticker, 'open_price')
          last = self.safe_number(ticker, 'last_price')
          change = None
          percentage = None
          average = None
          if last is not None and open is not None:
              change = last - open
              average = self.sum(last, open) / 2
              if open > 0:
                  percentage = change / open * 100
          vwap = self.vwap(baseVolume, quoteVolume)
          symbol = None if (market is None) else market['symbol']
          return {
              'symbol': symbol,
              'timestamp': timestamp,
              'datetime': self.iso8601(timestamp),
              'high': self.safe_number(ticker, 'max_price'),
              'low': self.safe_number(ticker, 'min_price'),
              'bid': self.safe_number(ticker, 'bid'),
              'bidVolume': None,
              'ask': self.safe_number(ticker, 'ask'),
              'askVolume': None,
              'vwap': vwap,
              'open': open,
              'close': last,
              'last': last,
              'previousClose': None,
              'change': change,
              'percentage': percentage,
              'average': average,
              'baseVolume': baseVolume,
              'quoteVolume': quoteVolume,
              'info': ticker,
          }
  
      async def fetch_tickers(self, symbols=None, params={}):
          await self.load_markets()
          response = await self.publicGetTicker(params)
          #
          #     {
          #         "message":null,
          #         "dataVersion":"fc521161aebe506178b8588cd2adb598eaf1018e",
          #         "data":{
          #             "BTC_VND":{
          #                 "base_id":1,
          #                 "quote_id":0,
          #                 "last_price":"411119457",
          #                 "max_price":"419893173.0000000000",
          #                 "min_price":"401292577.0000000000",
          #                 "open_price":null,
          #                 "base_volume":"10.5915050000",
          #                 "quote_volume":"4367495977.4484430060",
          #                 "isFrozen":0
          #             },
          #         }
          #     }
          #
          result = {}
          data = self.safe_value(response, 'data')
          marketIds = list(data.keys())
          for i in range(0, len(marketIds)):
              marketId = marketIds[i]
              market = self.safe_market(marketId, None, '_')
              symbol = market['symbol']
              result[symbol] = self.parse_ticker(data[marketId], market)
          return self.filter_by_array(result, 'symbol', symbols)
  
      def parse_trade(self, trade, market=None):
          #
          # public fetchTrades
          #
          #     {
          #         "trade_id":181509285,
          #         "price":"415933022.0000000000",
          #         "base_volume":"0.0022080000",
          #         "quote_volume":"918380.1125760000",
          #         "trade_timestamp":1605842150357,
          #         "type":"buy",
          #     }
          #
          # private fetchMyTrades
          #
          #     {
          #         "trade_type":"sell",
          #         "fee":"0.0610578086",
          #         "id":1483372,
          #         "created_at":1606581578368,
          #         "currency":"usdt",
          #         "coin":"btc",
          #         "price":"17667.1900000000",
          #         "quantity":"0.0017280000",
          #         "amount":"30.5289043200",
          #     }
          #
          timestamp = self.safe_integer_2(trade, 'trade_timestamp', 'created_at')
          baseId = self.safe_string_upper(trade, 'coin')
          quoteId = self.safe_string_upper(trade, 'currency')
          marketId = None
          if (baseId is not None) and (quoteId is not None):
              marketId = baseId + '_' + quoteId
          market = self.safe_market(marketId, market, '_')
          symbol = market['symbol']
          priceString = self.safe_string(trade, 'price')
          amountString = self.safe_string_2(trade, 'base_volume', 'quantity')
          price = self.parse_number(priceString)
          amount = self.parse_number(amountString)
          cost = self.safe_number_2(trade, 'quote_volume', 'amount')
          if cost is None:
              cost = self.parse_number(Precise.string_mul(priceString, amountString))
          side = self.safe_string_2(trade, 'type', 'trade_type')
          id = self.safe_string_2(trade, 'trade_id', 'id')
          feeCost = self.safe_number(trade, 'fee')
          fee = None
          if feeCost is not None:
              fee = {
                  'cost': feeCost,
                  'currency': market['quote'],
              }
          return {
              'info': trade,
              'id': id,
              'order': None,
              'timestamp': timestamp,
              'datetime': self.iso8601(timestamp),
              'symbol': symbol,
              'type': None,
              'side': side,
              'takerOrMaker': None,
              'price': price,
              'amount': amount,
              'cost': cost,
              'fee': fee,
          }
  
      async def fetch_trades(self, symbol, since=None, limit=None, params={}):
          await self.load_markets()
          market = self.market(symbol)
          request = {
              'market_pair': market['id'],
              # 'type': 'buy',  # 'sell'
              # 'count': limit,  # default 500, max 1000
          }
          if limit is not None:
              request['count'] = min(1000, limit)
          response = await self.publicGetTradesMarketPair(self.extend(request, params))
          #
          #     {
          #         "message":null,
          #         "dataVersion":"1f811b533143f739008a3e4ecaaab2ec82ea50d4",
          #         "data":[
          #             {
          #                 "trade_id":181509285,
          #                 "price":"415933022.0000000000",
          #                 "base_volume":"0.0022080000",
          #                 "quote_volume":"918380.1125760000",
          #                 "trade_timestamp":1605842150357,
          #                 "type":"buy",
          #             },
          #         ],
          #     }
          #
          data = self.safe_value(response, 'data')
          return self.parse_trades(data, market, since, limit)
  
      async def fetch_transactions(self, code=None, since=None, limit=None, params={}):
          await self.load_markets()
          request = {
              # 'type': type,  # 'deposit', 'withdraw'
              # 'start': int(since / 1000),
              # 'end': self.seconds(),
          }
          currency = None
          if code is not None:
              currency = self.currency(code)
              request['currency'] = currency['id']
          if limit is not None:
              request['limit'] = min(1000, limit)
          if since is not None:
              request['start'] = since
          response = await self.privateGetTransactions(self.extend(request, params))
          #
          #     {
          #         "message":null,
          #         "dataVersion":"1fdfb0ec85b666871d62fe59d098d01839b05e97",
          #         "data":{
          #             "current_page":1,
          #             "data":[
          #                 {
          #                     "id":85391,
          #                     "user_id":253063,
          #                     "transaction_id":"0x885719cee5910ca509a223d208797510e80eb27a2f1d51a71bb4ccb82d538131",
          #                     "internal_transaction_id":null,
          #                     "temp_transaction_id":"2367",
          #                     "currency":"usdt",
          #                     "amount":"30.0000000000",
          #                     "btc_amount":"0.0000000000",
          #                     "usdt_amount":"0.0000000000",
          #                     "fee":"0.0000000000",
          #                     "tx_cost":"0.0000000000",
          #                     "confirmation":0,
          #                     "deposit_code":null,
          #                     "status":"success",
          #                     "bank_name":null,
          #                     "foreign_bank_account":null,
          #                     "foreign_bank_account_holder":null,
          #                     "blockchain_address":"0xd54b84AD27E4c4a8C9E0b2b53701DeFc728f6E44",
          #                     "destination_tag":null,
          #                     "error_detail":null,
          #                     "refunded":"0.0000000000",
          #                     "transaction_date":"2020-11-28",
          #                     "transaction_timestamp":"1606563143.959",
          #                     "created_at":1606563143959,
          #                     "updated_at":1606563143959,
          #                     "transaction_email_timestamp":0,
          #                     "network":null,
          #                     "collect_tx_id":null,
          #                     "collect_id":null
          #                 }
          #             ],
          #             "first_page_url":"http:\/\/api.vcc.exchange\/v3\/transactions?page=1",
          #             "from":1,
          #             "last_page":1,
          #             "last_page_url":"http:\/\/api.vcc.exchange\/v3\/transactions?page=1",
          #             "next_page_url":null,
          #             "path":"http:\/\/api.vcc.exchange\/v3\/transactions",
          #             "per_page":10,
          #             "prev_page_url":null,
          #             "to":1,
          #             "total":1
          #         }
          #     }
          #
          data = self.safe_value(response, 'data', {})
          data = self.safe_value(data, 'data', [])
          return self.parse_transactions(data, currency, since, limit)
  
      async def fetch_deposits(self, code=None, since=None, limit=None, params={}):
          request = {'type': 'deposit'}
          return await self.fetch_transactions(code, since, limit, self.extend(request, params))
  
      async def fetch_withdrawals(self, code=None, since=None, limit=None, params={}):
          request = {'type': 'withdraw'}
          return await self.fetch_transactions(code, since, limit, self.extend(request, params))
  
      def parse_transaction(self, transaction, currency=None):
          #
          # fetchTransactions, fetchDeposits, fetchWithdrawals
          #
          #     {
          #         "id":85391,
          #         "user_id":253063,
          #         "transaction_id":"0x885719cee5910ca509a223d208797510e80eb27a2f1d51a71bb4ccb82d538131",
          #         "internal_transaction_id":null,
          #         "temp_transaction_id":"2367",
          #         "currency":"usdt",
          #         "amount":"30.0000000000",
          #         "btc_amount":"0.0000000000",
          #         "usdt_amount":"0.0000000000",
          #         "fee":"0.0000000000",
          #         "tx_cost":"0.0000000000",
          #         "confirmation":0,
          #         "deposit_code":null,
          #         "status":"success",
          #         "bank_name":null,
          #         "foreign_bank_account":null,
          #         "foreign_bank_account_holder":null,
          #         "blockchain_address":"0xd54b84AD27E4c4a8C9E0b2b53701DeFc728f6E44",
          #         "destination_tag":null,
          #         "error_detail":null,
          #         "refunded":"0.0000000000",
          #         "transaction_date":"2020-11-28",
          #         "transaction_timestamp":"1606563143.959",
          #         "created_at":1606563143959,
          #         "updated_at":1606563143959,
          #         "transaction_email_timestamp":0,
          #         "network":null,
          #         "collect_tx_id":null,
          #         "collect_id":null
          #     }
          #
          id = self.safe_string(transaction, 'id')
          timestamp = self.safe_integer(transaction, 'created_at')
          updated = self.safe_integer(transaction, 'updated_at')
          currencyId = self.safe_string(transaction, 'currency')
          code = self.safe_currency_code(currencyId, currency)
          status = self.parse_transaction_status(self.safe_string(transaction, 'status'))
          amount = self.safe_number(transaction, 'amount')
          if amount is not None:
              amount = abs(amount)
          address = self.safe_string(transaction, 'blockchain_address')
          txid = self.safe_string(transaction, 'transaction_id')
          tag = self.safe_string(transaction, 'destination_tag')
          fee = None
          feeCost = self.safe_number(transaction, 'fee')
          if feeCost is not None:
              fee = {
                  'cost': feeCost,
                  'currency': code,
              }
          type = amount > 'deposit' if 0 else 'withdrawal'
          return {
              'info': transaction,
              'id': id,
              'txid': txid,
              'timestamp': timestamp,
              'datetime': self.iso8601(timestamp),
              'address': address,
              'addressTo': address,
              'addressFrom': None,
              'tag': tag,
              'tagTo': tag,
              'tagFrom': None,
              'type': type,
              'amount': amount,
              'currency': code,
              'status': status,
              'updated': updated,
              'fee': fee,
          }
  
      def parse_transaction_status(self, status):
          statuses = {
              'pending': 'pending',
              'error': 'failed',
              'success': 'ok',
              'cancel': 'canceled',
          }
          return self.safe_string(statuses, status, status)
  
      def parse_transaction_type(self, type):
          types = {
              'deposit': 'deposit',
              'withdraw': 'withdrawal',
          }
          return self.safe_string(types, type, type)
  
      def cost_to_precision(self, symbol, cost):
          return self.decimal_to_precision(cost, ROUND, self.markets[symbol]['precision']['cost'], self.precisionMode, self.paddingMode)
  
      async def create_order(self, symbol, type, side, amount, price=None, params={}):
          await self.load_markets()
          market = self.market(symbol)
          request = {
              'coin': market['baseId'],
              'currency': market['quoteId'],
              'trade_type': side,
              'type': type,
          }
          if type == 'ceiling_market':
              ceiling = self.safe_value(params, 'ceiling')
              if ceiling is not None:
                  request['ceiling'] = self.cost_to_precision(symbol, ceiling)
              elif price is not None:
                  request['ceiling'] = self.cost_to_precision(symbol, amount * price)
              else:
                  raise InvalidOrder(self.id + ' createOrder() requires a price argument or a ceiling parameter for ' + type + ' orders')
          else:
              request['quantity'] = self.amount_to_precision(symbol, amount)
          if type == 'limit':
              request['price'] = self.price_to_precision(symbol, price)
          stopPrice = self.safe_value_2(params, 'stop_price', 'stopPrice')
          if stopPrice is not None:
              request['is_stop'] = 1
              request['stop_condition'] = 'le' if (side == 'buy') else 'ge'  # ge = greater than or equal, le = less than or equal
              request['stop_price'] = self.price_to_precision(symbol, price)
          params = self.omit(params, ['stop_price', 'stopPrice'])
          response = await self.privatePostOrders(self.extend(request, params))
          #
          # ceiling_market order
          #
          #     {
          #         "message":null,
          #         "dataVersion":"213fc0d433f38307f736cae1cbda4cc310469b7a",
          #         "data":{
          #             "coin":"btc",
          #             "currency":"usdt",
          #             "trade_type":"buy",
          #             "type":"ceiling_market",
          #             "ceiling":"30",
          #             "user_id":253063,
          #             "email":"igor.kroitor@gmail.com",
          #             "side":"buy",
          #             "quantity":"0.00172800",
          #             "status":"pending",
          #             "fee":0,
          #             "created_at":1606571333035,
          #             "updated_at":1606571333035,
          #             "instrument_symbol":"BTCUSDT",
          #             "remaining":"0.00172800",
          #             "fee_rate":"0.002",
          #             "id":88214435
          #         }
          #     }
          #
          # limit order
          #
          #     {
          #         "message":null,
          #         "dataVersion":"d9b1159d2bcefa2388be156e32ddc7cc324400ee",
          #         "data":{
          #             "id":41230,
          #             "trade_type":"sell",
          #             "type":"limit",
          #             "quantity":"1",
          #             "price":"14.99",
          #             "currency":"usdt",
          #             "coin":"neo",
          #             "status":"pending",
          #             "is_stop": "1",
          #             "stop_price": "13",
          #             "stop_condition": "ge",
          #             "fee":0,
          #             "created_at":1560244052168,
          #             "updated_at":1560244052168
          #         }
          #     }
          #
          data = self.safe_value(response, 'data')
          return self.parse_order(data, market)
  
      async def cancel_order(self, id, symbol=None, params={}):
          await self.load_markets()
          request = {
              'order_id': id,
          }
          response = await self.privatePutOrdersOrderIdCancel(self.extend(request, params))
          return self.parse_order(response)
  
      async def cancel_all_orders(self, symbol=None, params={}):
          type = self.safe_string(params, 'type')
          method = 'privatePutOrdersCancelAll' if (type is None) else 'privatePutOrdersCancelByType'
          request = {}
          if type is not None:
              request['type'] = type
          await self.load_markets()
          response = await getattr(self, method)(self.extend(request, params))
          #
          #     {
          #         "dataVersion":"6d72fb82a9c613c8166581a887e1723ce5a937ff",
          #         "data":{
          #             "data":[
          #                 {
          #                     "id":410,
          #                     "trade_type":"sell",
          #                     "currency":"usdt",
          #                     "coin":"neo",
          #                     "type":"limit",
          #                     "quantity":"1.0000000000",
          #                     "price":"14.9900000000",
          #                     "executed_quantity":"0.0000000000",
          #                     "executed_price":"0.0000000000",
          #                     "fee":"0.0000000000",
          #                     "status":"canceled",
          #                     "created_at":1560244052168,
          #                     "updated_at":1560244052168,
          #                 },
          #             ],
          #         },
          #     }
          #
          data = self.safe_value(response, 'data', {})
          data = self.safe_value(response, 'data', [])
          return self.parse_orders(data)
  
      def parse_order_status(self, status):
          statuses = {
              'pending': 'open',
              'stopping': 'open',
              'executing': 'open',
              'executed': 'closed',
              'canceled': 'canceled',
          }
          return self.safe_string(statuses, status, status)
  
      def parse_order(self, order, market=None):
          #
          # ceiling_market
          #
          #     {
          #         "coin":"btc",
          #         "currency":"usdt",
          #         "trade_type":"buy",
          #         "type":"ceiling_market",
          #         "ceiling":"30",
          #         "user_id":253063,
          #         "email":"igor.kroitor@gmail.com",
          #         "side":"buy",
          #         "quantity":"0.00172800",
          #         "status":"pending",
          #         "fee":0,
          #         "created_at":1606571333035,
          #         "updated_at":1606571333035,
          #         "instrument_symbol":"BTCUSDT",
          #         "remaining":"0.00172800",
          #         "fee_rate":"0.002",
          #         "id":88214435
          #     }
          #
          # limit order
          #
          #     {
          #         "id":41230,
          #         "trade_type":"sell",
          #         "type":"limit",
          #         "quantity":"1",
          #         "price":"14.99",
          #         "currency":"usdt",
          #         "coin":"neo",
          #         "status":"pending",
          #         "is_stop": "1",
          #         "stop_price": "13",
          #         "stop_condition": "ge",
          #         "fee":0,
          #         "created_at":1560244052168,
          #         "updated_at":1560244052168
          #     }
          #
          created = self.safe_value(order, 'created_at')
          updated = self.safe_value(order, 'updated_at')
          baseId = self.safe_string_upper(order, 'coin')
          quoteId = self.safe_string_upper(order, 'currency')
          marketId = baseId + '_' + quoteId
          market = self.safe_market(marketId, market, '_')
          symbol = market['symbol']
          amount = self.safe_number(order, 'quantity')
          filled = self.safe_number(order, 'executed_quantity')
          status = self.parse_order_status(self.safe_string(order, 'status'))
          cost = self.safe_number(order, 'ceiling')
          id = self.safe_string(order, 'id')
          price = self.safe_number(order, 'price')
          average = self.safe_number(order, 'executed_price')
          remaining = self.safe_number(order, 'remaining')
          type = self.safe_string(order, 'type')
          side = self.safe_string(order, 'trade_type')
          fee = {
              'currency': market['quote'],
              'cost': self.safe_number(order, 'fee'),
              'rate': self.safe_number(order, 'fee_rate'),
          }
          lastTradeTimestamp = None
          if updated != created:
              lastTradeTimestamp = updated
          stopPrice = self.safe_number(order, 'stopPrice')
          return self.safe_order({
              'id': id,
              'clientOrderId': id,
              'timestamp': created,
              'datetime': self.iso8601(created),
              'lastTradeTimestamp': lastTradeTimestamp,
              'status': status,
              'symbol': symbol,
              'type': type,
              'timeInForce': None,
              'postOnly': None,
              'side': side,
              'price': price,
              'stopPrice': stopPrice,
              'average': average,
              'amount': amount,
              'cost': cost,
              'filled': filled,
              'remaining': remaining,
              'fee': fee,
              'trades': None,
              'info': order,
          })
  
      async def fetch_order(self, id, symbol=None, params={}):
          await self.load_markets()
          request = {
              'order_id': id,
          }
          response = await self.privateGetOrdersOrderId(self.extend(request, params))
          #
          #     {
          #         "message":null,
          #         "dataVersion":"57448aa1fb8f227254e8e2e925b3ade8e1e5bbef",
          #         "data":{
          #             "id":88265741,
          #             "user_id":253063,
          #             "email":"igor.kroitor@gmail.com",
          #             "updated_at":1606581578141,
          #             "created_at":1606581578141,
          #             "coin":"btc",
          #             "currency":"usdt",
          #             "type":"market",
          #             "trade_type":"sell",
          #             "executed_price":"17667.1900000000",
          #             "price":null,
          #             "executed_quantity":"0.0017280000",
          #             "quantity":"0.0017280000",
          #             "fee":"0.0610578086",
          #             "status":"executed",
          #             "is_stop":0,
          #             "stop_condition":null,
          #             "stop_price":null,
          #             "ceiling":null
          #         }
          #     }
          #
          data = self.safe_value(response, 'data')
          return self.parse_order(data)
  
      async def fetch_orders_with_method(self, method, symbol=None, since=None, limit=None, params={}):
          await self.load_markets()
          request = {
              # 'page': 1,
              # 'limit': limit,  # max 1000
              # 'start_date': since,
              # 'end_date': self.milliseconds(),
              # 'currency': market['quoteId'],
              # 'coin': market['baseId'],
              # 'trade_type': 'buy',  # or 'sell'
              # 'hide_canceled': 0,  # 1 to exclude canceled orders
          }
          market = None
          if symbol is not None:
              market = self.market(symbol)
              request['coin'] = market['baseId']
              request['currency'] = market['quoteId']
          if since is not None:
              request['start_date'] = since
          if limit is not None:
              request['limit'] = min(1000, limit)  # max 1000
          response = await getattr(self, method)(self.extend(request, params))
          #
          #     {
          #         "message":null,
          #         "dataVersion":"89aa11497f23fdd34cf9de9c55acfad863c78780",
          #         "data":{
          #             "current_page":1,
          #             "data":[
          #                 {
          #                     "id":88489678,
          #                     "email":"igor.kroitor@gmail.com",
          #                     "updated_at":1606628593567,
          #                     "created_at":1606628593567,
          #                     "coin":"btc",
          #                     "currency":"usdt",
          #                     "type":"limit",
          #                     "trade_type":"buy",
          #                     "executed_price":"0.0000000000",
          #                     "price":"10000.0000000000",
          #                     "executed_quantity":"0.0000000000",
          #                     "quantity":"0.0010000000",
          #                     "fee":"0.0000000000",
          #                     "status":"pending",
          #                     "is_stop":0,
          #                     "stop_condition":null,
          #                     "stop_price":null,
          #                     "ceiling":null,
          #                 },
          #             ],
          #             "first_page_url":"http:\/\/api.vcc.exchange\/v3\/orders\/open?page=1",
          #             "from":1,
          #             "last_page":1,
          #             "last_page_url":"http:\/\/api.vcc.exchange\/v3\/orders\/open?page=1",
          #             "next_page_url":null,
          #             "path":"http:\/\/api.vcc.exchange\/v3\/orders\/open",
          #             "per_page":10,
          #             "prev_page_url":null,
          #             "to":1,
          #             "total":1,
          #         },
          #     }
          #
          data = self.safe_value(response, 'data', {})
          data = self.safe_value(data, 'data', [])
          return self.parse_orders(data, market, since, limit)
  
      async def fetch_open_orders(self, symbol=None, since=None, limit=None, params={}):
          return await self.fetch_orders_with_method('privateGetOrdersOpen', symbol, since, limit, params)
  
      async def fetch_closed_orders(self, symbol=None, since=None, limit=None, params={}):
          return await self.fetch_orders_with_method('privateGetOrders', symbol, since, limit, params)
  
      async def fetch_my_trades(self, symbol=None, since=None, limit=None, params={}):
          await self.load_markets()
          request = {
              # 'page': 1,
              # 'limit': limit,  # max 1000
              # 'start_date': since,
              # 'end_date': self.milliseconds(),
              # 'currency': market['quoteId'],
              # 'coin': market['baseId'],
              # 'trade_type': 'buy',  # or 'sell'
          }
          market = None
          if symbol is not None:
              market = self.market(symbol)
              request['coin'] = market['baseId']
              request['currency'] = market['quoteId']
          if since is not None:
              request['start_date'] = since
          if limit is not None:
              request['limit'] = min(1000, limit)  # max 1000
          response = await self.privateGetOrdersTrades(self.extend(request, params))
          #
          #     {
          #         "message":null,
          #         "dataVersion":"eb890af684cf84e20044e9a9771b96302e7b8dec",
          #         "data":{
          #             "current_page":1,
          #             "data":[
          #                 {
          #                     "trade_type":"sell",
          #                     "fee":"0.0610578086",
          #                     "id":1483372,
          #                     "created_at":1606581578368,
          #                     "currency":"usdt",
          #                     "coin":"btc",
          #                     "price":"17667.1900000000",
          #                     "quantity":"0.0017280000",
          #                     "amount":"30.5289043200",
          #                 },
          #             ],
          #             "first_page_url":"http:\/\/api.vcc.exchange\/v3\/orders\/trades?page=1",
          #             "from":1,
          #             "last_page":1,
          #             "last_page_url":"http:\/\/api.vcc.exchange\/v3\/orders\/trades?page=1",
          #             "next_page_url":null,
          #             "path":"http:\/\/api.vcc.exchange\/v3\/orders\/trades",
          #             "per_page":10,
          #             "prev_page_url":null,
          #             "to":2,
          #             "total":2,
          #         },
          #     }
          #
          data = self.safe_value(response, 'data', {})
          data = self.safe_value(data, 'data', [])
          return self.parse_trades(data, market, since, limit)
  
      async def fetch_deposit_address(self, code, params={}):
          await self.load_markets()
          currency = self.currency(code)
          request = {
              'currency': currency['id'],
          }
          response = await self.privateGetDepositAddress(self.extend(request, params))
          #
          #     {
          #         "dataVersion":"6d72fb82a9c613c8166581a887e1723ce5a937ff",
          #         "data":{
          #             "status": "REQUESTED",
          #             "blockchain_address": "",
          #             "currency": "btc"
          #         }
          #     }
          #
          #     {
          #         "dataVersion":"6d72fb82a9c613c8166581a887e1723ce5a937ff",
          #         "data":{
          #             "status": "PROVISIONED",
          #             "blockchain_address": "rPVMhWBsfF9iMXYj3aAzJVkPDTFNSyWdKy",
          #             "blockchain_tag": "920396135",
          #             "currency": "xrp"
          #         }
          #     }
          #
          data = self.safe_value(response, 'data')
          status = self.safe_string(data, 'status')
          if status == 'REQUESTED':
              raise AddressPending(self.id + ' is generating ' + code + ' deposit address, call fetchDepositAddress one more time later to retrieve the generated address')
          address = self.safe_string(data, 'blockchain_address')
          self.check_address(address)
          tag = self.safe_string(data, 'blockchain_tag')
          currencyId = self.safe_string(data, 'currency')
          return {
              'currency': self.safe_currency_code(currencyId),
              'address': address,
              'tag': tag,
              'info': data,
          }
  
      def sign(self, path, api='public', method='GET', params={}, headers=None, body=None):
          url = self.version + '/' + self.implode_params(path, params)
          query = self.omit(params, self.extract_params(path))
          if query:
              url += '?' + self.urlencode(query)
          if api == 'private':
              self.check_required_credentials()
              timestamp = str(self.milliseconds())
              if method != 'GET':
                  body = self.json(query)
              auth = method + ' ' + url
              signature = self.hmac(self.encode(auth), self.encode(self.secret), hashlib.sha256)
              headers = {
                  'Authorization': 'Bearer ' + self.apiKey,
                  'Content-Type': 'application/json',
                  'timestamp': timestamp,
                  'signature': signature,
              }
          url = self.urls['api'][api] + '/' + url
          return {'url': url, 'method': method, 'body': body, 'headers': headers}
  
      def handle_errors(self, code, reason, url, method, headers, body, response, requestHeaders, requestBody):
          if response is None:
              return
          #
          #     {"message":"Insufficient balance."}
          #     {"message":"Unauthenticated."}  # wrong api key
          #     {"message":"The given data was invalid.","errors":{"signature":["HMAC signature is invalid"]}}
          #     {"code":504,"message":"Gateway Timeout","description":""}
          #     {"code":429,"message":"Too many requests","description":"Too many requests"}
          #
          message = self.safe_string(response, 'message')
          if message is not None:
              feedback = self.id + ' ' + body
              self.throw_exactly_matched_exception(self.exceptions['exact'], message, feedback)
              self.throw_broadly_matched_exception(self.exceptions['broad'], body, feedback)
              raise ExchangeError(feedback)
  