# -*- 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 math
from ccxt.base.errors import ExchangeError
from ccxt.base.errors import AuthenticationError
from ccxt.base.errors import PermissionDenied
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 DDoSProtection
from ccxt.base.errors import RateLimitExceeded
from ccxt.base.errors import ExchangeNotAvailable
from ccxt.base.errors import OnMaintenance


class bitz(Exchange):

    def describe(self):
        return self.deep_extend(super(bitz, self).describe(), {
            'id': 'bitz',
            'name': 'Bit-Z',
            'countries': ['HK'],
            'rateLimit': 2000,
            'version': 'v2',
            'userAgent': self.userAgents['chrome'],
            'has': {
                'cancelOrder': True,
                'cancelOrders': True,
                'createOrder': True,
                'createMarketOrder': False,
                'fetchBalance': True,
                'fetchDeposits': True,
                'fetchClosedOrders': True,
                'fetchMarkets': True,
                'fetchOHLCV': True,
                'fetchOpenOrders': True,
                'fetchOrder': True,
                'fetchOrderBook': True,
                'fetchOrders': True,
                'fetchTicker': True,
                'fetchTickers': True,
                'fetchTime': True,
                'fetchTrades': True,
                'fetchTransactions': False,
                'fetchWithdrawals': True,
                'withdraw': True,
            },
            'timeframes': {
                '1m': '1min',
                '5m': '5min',
                '15m': '15min',
                '30m': '30min',
                '1h': '60min',
                '4h': '4hour',
                '1d': '1day',
                '5d': '5day',
                '1w': '1week',
                '1M': '1mon',
            },
            'hostname': 'apiv2.bitz.com',
            'urls': {
                'logo': 'https://user-images.githubusercontent.com/51840849/87443304-fec5e000-c5fd-11ea-98f8-ba8e67f7eaff.jpg',
                'api': {
                    'market': 'https://{hostname}',
                    'trade': 'https://{hostname}',
                    'assets': 'https://{hostname}',
                },
                'www': 'https://www.bitz.com',
                'doc': 'https://apidoc.bitz.com/en/',
                'fees': 'https://www.bitz.com/fee?type=1',
                'referral': 'https://u.bitz.com/register?invite_code=1429193',
            },
            'api': {
                'market': {
                    'get': [
                        'ticker',
                        'depth',
                        'order',  # trades
                        'tickerall',
                        'kline',
                        'symbolList',
                        'getServerTime',
                        'currencyRate',
                        'currencyCoinRate',
                        'coinRate',
                    ],
                },
                'trade': {
                    'post': [
                        'addEntrustSheet',
                        'cancelEntrustSheet',
                        'cancelAllEntrustSheet',
                        'coinOut',  # withdraw
                        'getUserHistoryEntrustSheet',  # closed orders
                        'getUserNowEntrustSheet',  # open orders
                        'getEntrustSheetInfo',  # order
                        'depositOrWithdraw',  # transactions
                    ],
                },
                'assets': {
                    'post': [
                        'getUserAssets',
                    ],
                },
            },
            'fees': {
                'trading': {
                    'maker': 0.002,
                    'taker': 0.002,
                },
                'funding': {
                    'withdraw': {
                        'BTC': '0.5%',
                        'DKKT': '0.5%',
                        'ETH': 0.01,
                        'USDT': '0.5%',
                        'LTC': '0.5%',
                        'FCT': '0.5%',
                        'LSK': '0.5%',
                        'HXI': '0.8%',
                        'ZEC': '0.5%',
                        'DOGE': '0.5%',
                        'MZC': '0.5%',
                        'ETC': '0.5%',
                        'GXS': '0.5%',
                        'XPM': '0.5%',
                        'PPC': '0.5%',
                        'BLK': '0.5%',
                        'XAS': '0.5%',
                        'HSR': '0.5%',
                        'NULS': 5.0,
                        'VOISE': 350.0,
                        'PAY': 1.5,
                        'EOS': 0.6,
                        'YBCT': 35.0,
                        'OMG': 0.3,
                        'OTN': 0.4,
                        'BTX': '0.5%',
                        'QTUM': '0.5%',
                        'DASH': '0.5%',
                        'GAME': '0.5%',
                        'BCH': '0.5%',
                        'GNT': 9.0,
                        'SSS': 1500.0,
                        'ARK': '0.5%',
                        'PART': '0.5%',
                        'LEO': '0.5%',
                        'DGB': '0.5%',
                        'ZSC': 130.0,
                        'VIU': 350.0,
                        'BTG': '0.5%',
                        'ARN': 10.0,
                        'VTC': '0.5%',
                        'BCD': '0.5%',
                        'TRX': 200.0,
                        'HWC': '0.5%',
                        'UNIT': '0.5%',
                        'OXY': '0.5%',
                        'MCO': 0.3500,
                        'SBTC': '0.5%',
                        'BCX': '0.5%',
                        'ETF': '0.5%',
                        'PYLNT': 0.4000,
                        'XRB': '0.5%',
                        'ETP': '0.5%',
                    },
                },
            },
            'precision': {
                'amount': 8,
                'price': 8,
            },
            'options': {
                'fetchOHLCVVolume': True,
                'fetchOHLCVWarning': True,
                'lastNonceTimestamp': 0,
            },
            'commonCurrencies': {
                # https://github.com/ccxt/ccxt/issues/3881
                # https://support.bit-z.pro/hc/en-us/articles/360007500654-BOX-BOX-Token-
                'BOX': 'BOX Token',
                'LEO': 'LeoCoin',
                'XRB': 'NANO',
                'PXC': 'Pixiecoin',
                'VTC': 'VoteCoin',
                'TTC': 'TimesChain',
            },
            'exceptions': {
                # '200': Success
                '-102': ExchangeError,  # Invalid parameter
                '-103': AuthenticationError,  # Verification failed
                '-104': ExchangeNotAvailable,  # Network Error-1
                '-105': AuthenticationError,  # Invalid api signature
                '-106': ExchangeNotAvailable,  # Network Error-2
                '-109': AuthenticationError,  # Invalid scretKey
                '-110': DDoSProtection,  # The number of access requests exceeded
                '-111': PermissionDenied,  # Current IP is not in the range of trusted IP
                '-112': OnMaintenance,  # Service is under maintenance
                '-114': RateLimitExceeded,  # The number of daily requests has reached the limit
                '-117': AuthenticationError,  # The apikey expires
                '-100015': AuthenticationError,  # Trade password error
                '-100044': ExchangeError,  # Fail to request data
                '-100101': ExchangeError,  # Invalid symbol
                '-100201': ExchangeError,  # Invalid symbol
                '-100301': ExchangeError,  # Invalid symbol
                '-100401': ExchangeError,  # Invalid symbol
                '-100302': ExchangeError,  # Type of K-line error
                '-100303': ExchangeError,  # Size of K-line error
                '-200003': AuthenticationError,  # Please set trade password
                '-200005': PermissionDenied,  # This account can not trade
                '-200025': ExchangeNotAvailable,  # Temporary trading halt
                '-200027': InvalidOrder,  # Price Error
                '-200028': InvalidOrder,  # Amount must be greater than 0
                '-200029': InvalidOrder,  # Number must be between %s and %d
                '-200030': InvalidOrder,  # Over price range
                '-200031': InsufficientFunds,  # Insufficient assets
                '-200032': ExchangeError,  # System error. Please contact customer service
                '-200033': ExchangeError,  # Fail to trade
                '-200034': OrderNotFound,  # The order does not exist
                '-200035': OrderNotFound,  # Cancellation error, order filled
                '-200037': InvalidOrder,  # Trade direction error
                '-200038': ExchangeError,  # Trading Market Error
                '-200055': OrderNotFound,  # Order record does not exist
                '-300069': AuthenticationError,  # api_key is illegal
                '-300101': ExchangeError,  # Transaction type error
                '-300102': InvalidOrder,  # Price or number cannot be less than 0
                '-300103': AuthenticationError,  # Trade password error
                '-301001': ExchangeNotAvailable,  # Network Error-3
            },
        })

    async def fetch_markets(self, params={}):
        response = await self.marketGetSymbolList(params)
        #
        #     {   status:    200,
        #             msg:   "",
        #            data: {  ltc_btc: {         id: "1",
        #                                        name: "ltc_btc",
        #                                    coinFrom: "ltc",
        #                                      coinTo: "btc",
        #                                 numberFloat: "4",
        #                                  priceFloat: "8",
        #                                      status: "1",
        #                                    minTrade: "0.010",
        #                                    maxTrade: "500000000.000"},
        #                    qtum_usdt: {         id: "196",
        #                                        name: "qtum_usdt",
        #                                    coinFrom: "qtum",
        #                                      coinTo: "usdt",
        #                                 numberFloat: "4",
        #                                  priceFloat: "2",
        #                                      status: "1",
        #                                    minTrade: "0.100",
        #                                    maxTrade: "500000000.000"},  },
        #            time:    1535969146,
        #       microtime:   "0.66955600 1535969146",
        #          source:   "api"                                           }
        #
        markets = self.safe_value(response, 'data')
        ids = list(markets.keys())
        result = []
        for i in range(0, len(ids)):
            id = ids[i]
            market = markets[id]
            numericId = self.safe_string(market, 'id')
            baseId = self.safe_string(market, 'coinFrom')
            quoteId = self.safe_string(market, 'coinTo')
            base = baseId.upper()
            quote = quoteId.upper()
            base = self.safe_currency_code(base)
            quote = self.safe_currency_code(quote)
            symbol = base + '/' + quote
            precision = {
                'amount': self.safe_integer(market, 'numberFloat'),
                'price': self.safe_integer(market, 'priceFloat'),
            }
            result.append({
                'info': market,
                'id': id,
                'numericId': numericId,
                'symbol': symbol,
                'base': base,
                'quote': quote,
                'baseId': baseId,
                'quoteId': quoteId,
                'active': True,
                'precision': precision,
                'limits': {
                    'amount': {
                        'min': self.safe_float(market, 'minTrade'),
                        'max': self.safe_float(market, 'maxTrade'),
                    },
                    'price': {
                        'min': math.pow(10, -precision['price']),
                        'max': None,
                    },
                    'cost': {
                        'min': None,
                        'max': None,
                    },
                },
            })
        return result

    async def fetch_balance(self, params={}):
        await self.load_markets()
        response = await self.assetsPostGetUserAssets(params)
        #
        #     {
        #         status: 200,
        #         msg: "",
        #         data: {
        #             cny: 0,
        #             usd: 0,
        #             btc_total: 0,
        #             info: [{
        #                 "name": "zpr",
        #                 "num": "37.49067275",
        #                 "over": "37.49067275",
        #                 "lock": "0.00000000",
        #                 "btc": "0.00000000",
        #                 "usd": "0.00000000",
        #                 "cny": "0.00000000",
        #             }],
        #         },
        #         time: 1535983966,
        #         microtime: "0.70400500 1535983966",
        #         source: "api",
        #     }
        #
        balances = self.safe_value(response['data'], 'info')
        result = {'info': response}
        for i in range(0, len(balances)):
            balance = balances[i]
            currencyId = self.safe_string(balance, 'name')
            code = self.safe_currency_code(currencyId)
            account = self.account()
            account['used'] = self.safe_float(balance, 'lock')
            account['total'] = self.safe_float(balance, 'num')
            account['free'] = self.safe_float(balance, 'over')
            result[code] = account
        return self.parse_balance(result)

    def parse_ticker(self, ticker, market=None):
        #
        #      {         symbol: "eth_btc",
        #            quoteVolume: "3905.72",
        #                 volume: "97058.21",
        #            priceChange: "-1.72",
        #         priceChange24h: "-1.65",
        #               askPrice: "0.03971272",
        #                 askQty: "0.0663",
        #               bidPrice: "0.03961469",
        #                 bidQty: "19.5451",
        #                   open: "0.04036769",
        #                   high: "0.04062988",
        #                    low: "0.03956123",
        #                    now: "0.03970100",
        #                firstId:  115567767,
        #                 lastId:  115795316,
        #              dealCount:  14078,
        #        numberPrecision:  4,
        #         pricePrecision:  8,
        #                    cny: "1959.05",
        #                    usd: "287.10",
        #                    krw: "318655.82"   }
        #
        timestamp = None
        marketId = self.safe_string(ticker, 'symbol')
        symbol = self.safe_symbol(marketId, market, '_')
        last = self.safe_float(ticker, 'now')
        open = self.safe_float(ticker, 'open')
        change = None
        average = None
        if last is not None and open is not None:
            change = last - open
            average = self.sum(last, open) / 2
        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, 'bidPrice'),
            'bidVolume': self.safe_float(ticker, 'bidQty'),
            'ask': self.safe_float(ticker, 'askPrice'),
            'askVolume': self.safe_float(ticker, 'askQty'),
            'vwap': None,
            'open': open,
            'close': last,
            'last': last,
            'previousClose': None,
            'change': change,
            'percentage': self.safe_float(ticker, 'priceChange24h'),
            'average': average,
            'baseVolume': self.safe_float(ticker, 'volume'),
            'quoteVolume': self.safe_float(ticker, 'quoteVolume'),
            'info': ticker,
        }

    def parse_microtime(self, microtime):
        if microtime is None:
            return microtime
        parts = microtime.split(' ')
        milliseconds = float(parts[0])
        seconds = int(parts[1])
        total = self.sum(seconds, milliseconds)
        return int(total * 1000)

    async def fetch_ticker(self, symbol, params={}):
        await self.load_markets()
        market = self.market(symbol)
        request = {
            'symbol': market['id'],
        }
        response = await self.marketGetTicker(self.extend(request, params))
        #
        #     {   status:    200,
        #             msg:   "",
        #            data: {         symbol: "eth_btc",
        #                        quoteVolume: "3905.72",
        #                             volume: "97058.21",
        #                        priceChange: "-1.72",
        #                     priceChange24h: "-1.65",
        #                           askPrice: "0.03971272",
        #                             askQty: "0.0663",
        #                           bidPrice: "0.03961469",
        #                             bidQty: "19.5451",
        #                               open: "0.04036769",
        #                               high: "0.04062988",
        #                                low: "0.03956123",
        #                                now: "0.03970100",
        #                            firstId:  115567767,
        #                             lastId:  115795316,
        #                          dealCount:  14078,
        #                    numberPrecision:  4,
        #                     pricePrecision:  8,
        #                                cny: "1959.05",
        #                                usd: "287.10",
        #                                krw: "318655.82"   },
        #            time:    1535970397,
        #       microtime:   "0.76341900 1535970397",
        #          source:   "api"                             }
        #
        ticker = self.parse_ticker(response['data'], market)
        timestamp = self.parse_microtime(self.safe_string(response, 'microtime'))
        return self.extend(ticker, {
            'timestamp': timestamp,
            'datetime': self.iso8601(timestamp),
        })

    async def fetch_tickers(self, symbols=None, params={}):
        await self.load_markets()
        request = {}
        if symbols is not None:
            ids = self.market_ids(symbols)
            request['symbols'] = ','.join(ids)
        response = await self.marketGetTickerall(self.extend(request, params))
        #
        #     {   status:    200,
        #             msg:   "",
        #            data: {  ela_btc: {         symbol: "ela_btc",
        #                                     quoteVolume: "0.00",
        #                                          volume: "3.28",
        #                                     priceChange: "0.00",
        #                                  priceChange24h: "0.00",
        #                                        askPrice: "0.00147984",
        #                                          askQty: "5.4580",
        #                                        bidPrice: "0.00120230",
        #                                          bidQty: "12.5384",
        #                                            open: "0.00149078",
        #                                            high: "0.00149078",
        #                                             low: "0.00149078",
        #                                             now: "0.00149078",
        #                                         firstId:  115581219,
        #                                          lastId:  115581219,
        #                                       dealCount:  1,
        #                                 numberPrecision:  4,
        #                                  pricePrecision:  8,
        #                                             cny: "73.66",
        #                                             usd: "10.79",
        #                                             krw: "11995.03"    }     },
        #            time:    1535971578,
        #       microtime:   "0.39854200 1535971578",
        #          source:   "api"                                                }
        #
        tickers = self.safe_value(response, 'data')
        timestamp = self.parse_microtime(self.safe_string(response, 'microtime'))
        result = {}
        ids = list(tickers.keys())
        for i in range(0, len(ids)):
            id = ids[i]
            ticker = tickers[id]
            market = None
            if id in self.markets_by_id:
                market = self.markets_by_id[id]
            ticker = self.parse_ticker(tickers[id], market)
            symbol = ticker['symbol']
            if symbol is None:
                if market is not None:
                    symbol = market['symbol']
                else:
                    baseId, quoteId = id.split('_')
                    base = self.safe_currency_code(baseId)
                    quote = self.safe_currency_code(quoteId)
                    symbol = base + '/' + quote
            if symbol is not None:
                result[symbol] = self.extend(ticker, {
                    'timestamp': timestamp,
                    'datetime': self.iso8601(timestamp),
                })
        return self.filter_by_array(result, 'symbol', symbols)

    async def fetch_time(self, params={}):
        response = await self.marketGetGetServerTime(params)
        #
        #     {
        #         "status":200,
        #         "msg":"",
        #         "data":[],
        #         "time":1555490875,
        #         "microtime":"0.35994200 1555490875",
        #         "source":"api"
        #     }
        #
        return self.safe_timestamp(response, 'time')

    async def fetch_order_book(self, symbol, limit=None, params={}):
        await self.load_markets()
        request = {
            'symbol': self.market_id(symbol),
        }
        response = await self.marketGetDepth(self.extend(request, params))
        #
        #     {   status:    200,
        #             msg:   "",
        #            data: {    asks: [["10.00000000", "0.4426", "4.4260"],
        #                                ["1.00000000", "0.8339", "0.8339"],
        #                                ["0.91700000", "0.0500", "0.0458"],
        #                                ["0.20000000", "0.1000", "0.0200"],
        #                                ["0.03987120", "16.1262", "0.6429"],
        #                                ["0.03986120", "9.7523", "0.3887"]   ],
        #                        bids: [["0.03976145", "0.0359", "0.0014"],
        #                                ["0.03973401", "20.9493", "0.8323"],
        #                                ["0.03967970", "0.0328", "0.0013"],
        #                                ["0.00000002", "10000.0000", "0.0002"],
        #                                ["0.00000001", "231840.7500", "0.0023"]],
        #                    coinPair:   "eth_btc"                                  },
        #            time:    1535974778,
        #       microtime:   "0.04017400 1535974778",
        #          source:   "api"                                                     }
        #
        orderbook = self.safe_value(response, 'data')
        timestamp = self.parse_microtime(self.safe_string(response, 'microtime'))
        return self.parse_order_book(orderbook, timestamp)

    def parse_trade(self, trade, market=None):
        #
        # fetchTrades(public)
        #
        #    {id:  115807453,
        #       t: "19:36:24",
        #       T:  1535974584,
        #       p: "0.03983296",
        #       n: "0.1000",
        #       s: "buy"         },
        #
        id = self.safe_string(trade, 'id')
        timestamp = self.safe_timestamp(trade, 'T')
        symbol = None
        if market is not None:
            symbol = market['symbol']
        price = self.safe_float(trade, 'p')
        amount = self.safe_float(trade, 'n')
        cost = None
        if price is not None:
            if amount is not None:
                cost = self.price_to_precision(symbol, amount * price)
        side = self.safe_string(trade, 's')
        return {
            'timestamp': timestamp,
            'datetime': self.iso8601(timestamp),
            'symbol': symbol,
            'id': id,
            'order': None,
            'type': 'limit',
            'side': side,
            'takerOrMaker': None,
            'price': price,
            'amount': amount,
            'cost': cost,
            'fee': None,
            'info': trade,
        }

    async def fetch_trades(self, symbol, since=None, limit=None, params={}):
        await self.load_markets()
        market = self.market(symbol)
        request = {
            'symbol': market['id'],
        }
        response = await self.marketGetOrder(self.extend(request, params))
        #
        #     {   status:    200,
        #             msg:   "",
        #            data: [{id:  115807453,
        #                       t: "19:36:24",
        #                       T:  1535974584,
        #                       p: "0.03983296",
        #                       n: "0.1000",
        #                       s: "buy"         },
        #                    {id:  115806811,
        #                       t: "19:33:19",
        #                       T:  1535974399,
        #                       p: "0.03981135",
        #                       n: "9.4612",
        #                       s: "sell"        }  ],
        #            time:    1535974583,
        #       microtime:   "0.57118100 1535974583",
        #          source:   "api"                     }
        #
        return self.parse_trades(response['data'], market, since, limit)

    def parse_ohlcv(self, ohlcv, market=None):
        #
        #     {
        #         time: "1535973420000",
        #         open: "0.03975084",
        #         high: "0.03975084",
        #         low: "0.03967700",
        #         close: "0.03967700",
        #         volume: "12.4733",
        #         datetime: "2018-09-03 19:17:00"
        #     }
        #
        return [
            self.safe_integer(ohlcv, 'time'),
            self.safe_float(ohlcv, 'open'),
            self.safe_float(ohlcv, 'high'),
            self.safe_float(ohlcv, 'low'),
            self.safe_float(ohlcv, 'close'),
            self.safe_float(ohlcv, 'volume'),
        ]

    async def fetch_ohlcv(self, symbol, timeframe='1m', since=None, limit=None, params={}):
        await self.load_markets()
        duration = self.parse_timeframe(timeframe) * 1000
        market = self.market(symbol)
        request = {
            'symbol': market['id'],
            'resolution': self.timeframes[timeframe],
        }
        if limit is not None:
            request['size'] = min(limit, 300)  # 1-300
            if since is not None:
                request['to'] = self.sum(since, limit * duration * 1000)
        else:
            if since is not None:
                raise ArgumentsRequired(self.id + ' fetchOHLCV() requires a limit argument if the since argument is specified')
        response = await self.marketGetKline(self.extend(request, params))
        #
        #     {
        #         status: 200,
        #         msg: "",
        #         data: {
        #             bars: [
        #                 {time: "1535973420000", open: "0.03975084", high: "0.03975084", low: "0.03967700", close: "0.03967700", volume: "12.4733", datetime: "2018-09-03 19:17:00"},
        #                 {time: "1535955480000", open: "0.04009900", high: "0.04016745", low: "0.04009900", close: "0.04012074", volume: "74.4803", datetime: "2018-09-03 14:18:00"},
        #             ],
        #             resolution: "1min",
        #             symbol: "eth_btc",
        #             from: "1535973420000",
        #             to: "1535955480000",
        #             size: 300
        #         },
        #         time: 1535973435,
        #         microtime: "0.56462100 1535973435",
        #         source: "api"
        #     }
        #
        data = self.safe_value(response, 'data', {})
        bars = self.safe_value(data, 'bars', [])
        return self.parse_ohlcvs(bars, market, timeframe, since, limit)

    def parse_order_status(self, status):
        statuses = {
            '0': 'open',
            '1': 'open',  # partially filled
            '2': 'closed',  # filled
            '3': 'canceled',
        }
        return self.safe_string(statuses, status, status)

    def parse_order(self, order, market=None):
        #
        # createOrder
        #
        #    {
        #         "id": "693248739",   # order id
        #         "uId": "2074056",    # uid
        #         "price": "100",      # price
        #         "number": "10",      # number
        #         "numberOver": "10",  # undealed
        #         "flag": "sale",      # flag
        #         "status": "0",       # unfilled
        #         "coinFrom": "vtc",
        #         "coinTo": "dkkt",
        #         "numberDeal": "0"    # dealed
        #     }
        #
        id = self.safe_string(order, 'id')
        symbol = None
        if market is None:
            baseId = self.safe_string(order, 'coinFrom')
            quoteId = self.safe_string(order, 'coinTo')
            if (baseId is not None) and (quoteId is not None):
                marketId = baseId + '_' + quoteId
                if marketId in self.markets_by_id:
                    market = self.safe_value(self.markets_by_id, marketId)
                else:
                    base = self.safe_currency_code(baseId)
                    quote = self.safe_currency_code(quoteId)
                    symbol = base + '/' + quote
        if market is not None:
            symbol = market['symbol']
        side = self.safe_string(order, 'flag')
        if side is not None:
            side = 'sell' if (side == 'sale') else 'buy'
        price = self.safe_float(order, 'price')
        amount = self.safe_float(order, 'number')
        remaining = self.safe_float(order, 'numberOver')
        filled = self.safe_float(order, 'numberDeal')
        timestamp = self.safe_integer(order, 'timestamp')
        if timestamp is None:
            timestamp = self.safe_timestamp(order, 'created')
        cost = self.safe_float(order, 'orderTotalPrice')
        if price is not None:
            if filled is not None:
                cost = filled * price
        status = self.parse_order_status(self.safe_string(order, 'status'))
        return {
            'id': id,
            'clientOrderId': None,
            'datetime': self.iso8601(timestamp),
            'timestamp': timestamp,
            'lastTradeTimestamp': None,
            'status': status,
            'symbol': symbol,
            'type': 'limit',
            'timeInForce': None,
            'postOnly': None,
            'side': side,
            'price': price,
            'stopPrice': None,
            'cost': cost,
            'amount': amount,
            'filled': filled,
            'remaining': remaining,
            'trades': None,
            'fee': None,
            'info': order,
            'average': None,
        }

    async def create_order(self, symbol, type, side, amount, price=None, params={}):
        await self.load_markets()
        if type != 'limit':
            raise ExchangeError(self.id + ' createOrder allows limit orders only')
        market = self.market(symbol)
        orderType = '1' if (side == 'buy') else '2'
        if not self.password:
            raise ExchangeError(self.id + ' createOrder() requires you to set exchange.password = "YOUR_TRADING_PASSWORD"(a trade password is NOT THE SAME as your login password)')
        request = {
            'symbol': market['id'],
            'type': orderType,
            'price': self.price_to_precision(symbol, price),
            'number': self.amount_to_precision(symbol, amount),
            'tradePwd': self.password,
        }
        response = await self.tradePostAddEntrustSheet(self.extend(request, params))
        #
        #     {
        #         "status": 200,
        #         "msg": "",
        #         "data": {
        #             "id": "693248739",   # order id
        #             "uId": "2074056",    # uid
        #             "price": "100",      # price
        #             "number": "10",      # number
        #             "numberOver": "10",  # undealed
        #             "flag": "sale",      # flag
        #             "status": "0",       # unfilled
        #             "coinFrom": "vtc",
        #             "coinTo": "dkkt",
        #             "numberDeal": "0"    # dealed
        #         },
        #         "time": "1533035297",
        #         "microtime": "0.41892000 1533035297",
        #         "source": "api",
        #     }
        #
        timestamp = self.parse_microtime(self.safe_string(response, 'microtime'))
        order = self.extend({
            'timestamp': timestamp,
        }, response['data'])
        return self.parse_order(order, market)

    async def cancel_order(self, id, symbol=None, params={}):
        await self.load_markets()
        request = {
            'entrustSheetId': id,
        }
        response = await self.tradePostCancelEntrustSheet(self.extend(request, params))
        #
        #     {
        #         "status":200,
        #         "msg":"",
        #         "data":{
        #             "updateAssetsData":{
        #                 "coin":"bz",
        #                 "over":"1000.00000000",
        #                 "lock":"-1000.00000000"
        #             },
        #             "assetsInfo":{
        #                 "coin":"bz",
        #                 "over":"9999.99999999",
        #                 "lock":"9999.99999999"
        #             }
        #         },
        #         "time":"1535464383",
        #         "microtime":"0.91558000 1535464383",
        #         "source":"api"
        #     }
        #
        return response

    async def cancel_orders(self, ids, symbol=None, params={}):
        await self.load_markets()
        request = {
            'ids': ','.join(ids),
        }
        response = await self.tradePostCancelEntrustSheet(self.extend(request, params))
        #
        #     {
        #         "status":200,
        #         "msg":"",
        #         "data":{
        #             "744173808":{
        #                 "updateAssetsData":{
        #                     "coin":"bz",
        #                     "over":"100.00000000",
        #                     "lock":"-100.00000000"
        #                 },
        #                 "assetsInfo":{
        #                     "coin":"bz",
        #                     "over":"899.99999999",
        #                     "lock":"19099.99999999"
        #                 }
        #             },
        #             "744173809":{
        #                 "updateAssetsData":{
        #                     "coin":"bz",
        #                     "over":"100.00000000",
        #                     "lock":"-100.00000000"
        #                 },
        #                 "assetsInfo":{
        #                     "coin":"bz",
        #                     "over":"999.99999999",
        #                     "lock":"18999.99999999"
        #                 }
        #             }
        #         },
        #         "time":"1535525649",
        #         "microtime":"0.05009400 1535525649",
        #         "source":"api"
        #     }
        #
        return response

    async def fetch_order(self, id, symbol=None, params={}):
        await self.load_markets()
        request = {
            'entrustSheetId': id,
        }
        response = await self.tradePostGetEntrustSheetInfo(self.extend(request, params))
        #
        #     {
        #         "status":200,
        #         "msg":"",
        #         "data":{
        #             "id":"708279852",
        #             "uId":"2074056",
        #             "price":"100.00000000",
        #             "number":"10.0000",
        #             "total":"0.00000000",
        #             "numberOver":"10.0000",
        #             "numberDeal":"0.0000",
        #             "flag":"sale",
        #             "status":"0",  #0:unfilled, 1:partial deal, 2:all transactions, 3:already cancelled
        #             "coinFrom":"bz",
        #             "coinTo":"usdt",
        #             "orderTotalPrice":"0",
        #             "created":"1533279876"
        #         },
        #         "time":"1533280294",
        #         "microtime":"0.36859200 1533280294",
        #         "source":"api"
        #     }
        #
        return self.parse_order(response['data'])

    async def fetch_orders_with_method(self, method, symbol=None, since=None, limit=None, params={}):
        if symbol is None:
            raise ArgumentsRequired(self.id + ' fetchOpenOrders() requires a symbol argument')
        await self.load_markets()
        market = self.market(symbol)
        request = {
            'coinFrom': market['baseId'],
            'coinTo': market['quoteId'],
            # 'type': 1,  # optional integer, 1 = buy, 2 = sell
            # 'page': 1,  # optional integer
            # 'pageSize': 100,  # optional integer, max 100
            # 'startTime': 1510235730,  # optional integer timestamp in seconds
            # 'endTime': 1510235730,  # optional integer timestamp in seconds
        }
        if limit is not None:
            request['page'] = 1
            request['pageSize'] = limit
        if since is not None:
            request['startTime'] = int(since / 1000)
            # request['endTime'] = int(since / 1000)
        response = await getattr(self, method)(self.extend(request, params))
        #
        #     {
        #         "status": 200,
        #         "msg": "",
        #         "data": {
        #             "data": [
        #                 {
        #                     "id": "693248739",
        #                     "uid": "2074056",
        #                     "price": "100.00000000",
        #                     "number": "10.0000",
        #                     "total": "0.00000000",
        #                     "numberOver": "0.0000",
        #                     "numberDeal": "0.0000",
        #                     "flag": "sale",
        #                     "status": "3",  # 0:unfilled, 1:partial deal, 2:all transactions, 3:already cancelled
        #                     "isNew": "N",
        #                     "coinFrom": "vtc",
        #                     "coinTo": "dkkt",
        #                     "created": "1533035300",
        #                 },
        #                 {
        #                     "id": "723086996",
        #                     "uid": "2074056",
        #                     "price": "100.00000000",
        #                     "number": "10.0000",
        #                     "total": "0.00000000",
        #                     "numberOver": "0.0000",
        #                     "numberDeal": "0.0000",
        #                     "flag": "sale",
        #                     "status": "3",
        #                     "isNew": "N",
        #                     "coinFrom": "bz",
        #                     "coinTo": "usdt",
        #                     "created": "1533523568",
        #                 },
        #             ],
        #             "pageInfo": {
        #                 "limit": "10",
        #                 "offest": "0",
        #                 "current_page": "1",
        #                 "page_size": "10",
        #                 "total_count": "17",
        #                 "page_count": "2",
        #             }
        #         },
        #         "time": "1533279329",
        #         "microtime": "0.15305300 1533279329",
        #         "source": "api"
        #     }
        #
        orders = self.safe_value(response['data'], 'data', [])
        return self.parse_orders(orders, None, since, limit)

    async def fetch_orders(self, symbol=None, since=None, limit=None, params={}):
        return await self.fetch_orders_with_method('tradePostGetUserHistoryEntrustSheet', symbol, since, limit, params)

    async def fetch_open_orders(self, symbol=None, since=None, limit=None, params={}):
        return await self.fetch_orders_with_method('tradePostGetUserNowEntrustSheet', symbol, since, limit, params)

    async def fetch_closed_orders(self, symbol=None, since=None, limit=None, params={}):
        return await self.fetch_orders_with_method('tradePostGetUserHistoryEntrustSheet', symbol, since, limit, params)

    def parse_transaction_status(self, status):
        statuses = {
            '1': 'pending',
            '2': 'pending',
            '3': 'pending',
            '4': 'ok',
            '5': 'canceled',
        }
        return self.safe_string(statuses, status, status)

    def parse_transaction(self, transaction, currency=None):
        #
        #     {
        #         "id": '96275',
        #         "uid": '2109073',
        #         "wallet": '0xf4c4141c0127bc37b1d0c409a091920eba13ada7',
        #         "txid": '0xb7adfa52aa566f9ac112e3c01f77bd91179b19eab12092a9a5a8b33d5086e31d',
        #         "confirm": '12',
        #         "number": '0.50000000',
        #         "status": 4,
        #         "updated": '1534944168605',
        #         "addressUrl": 'https://etherscan.io/address/',
        #         "txidUrl": 'https://etherscan.io/tx/',
        #         "description": 'Ethereum',
        #         "coin": 'eth',
        #         "memo": ''
        #     }
        #
        #     {
        #         "id":"397574",
        #         "uid":"2033056",
        #         "wallet":"1AG1gZvQAYu3WBvgg7p4BMMghQD2gE693k",
        #         "txid":"",
        #         "confirm":"0",
        #         "number":"1000.00000000",
        #         "status":1,
        #         "updated":"0",
        #         "addressUrl":"http://omniexplorer.info/lookupadd.aspx?address=",
        #         "txidUrl":"http://omniexplorer.info/lookuptx.aspx?txid=",
        #         "description":"Tether",
        #         "coin":"usdt",
        #         "memo":""
        #     }
        #
        #     {
        #         "id":"153606",
        #         "uid":"2033056",
        #         "wallet":"1AG1gZvQAYu3WBvgg7p4BMMghQD2gE693k",
        #         "txid":"aa2b179f84cd6dedafd41845e0fbf7f01e14c0d71ea3140d03d6f5a9ccd93199",
        #         "confirm":"0",
        #         "number":"761.11110000",
        #         "status":4,
        #         "updated":"1536726133579",
        #         "addressUrl":"http://omniexplorer.info/lookupadd.aspx?address=",
        #         "txidUrl":"http://omniexplorer.info/lookuptx.aspx?txid=",
        #         "description":"Tether",
        #         "coin":"usdt",
        #         "memo":""
        #     }
        #
        # withdraw
        #
        #     {
        #         "id":397574,
        #         "email":"***@email.com",
        #         "coin":"usdt",
        #         "network_fee":"",
        #         "eid":23112
        #     }
        #
        timestamp = self.safe_integer(transaction, 'updated')
        if timestamp == 0:
            timestamp = None
        currencyId = self.safe_string(transaction, 'coin')
        code = self.safe_currency_code(currencyId, currency)
        type = self.safe_string_lower(transaction, 'type')
        status = self.parse_transaction_status(self.safe_string(transaction, 'status'))
        fee = None
        feeCost = self.safe_float(transaction, 'network_fee')
        if feeCost is not None:
            fee = {
                'cost': feeCost,
                'code': code,
            }
        return {
            'id': self.safe_string(transaction, 'id'),
            'txid': self.safe_string(transaction, 'txid'),
            'timestamp': timestamp,
            'datetime': self.iso8601(timestamp),
            'address': self.safe_string(transaction, 'wallet'),
            'tag': self.safe_string(transaction, 'memo'),
            'type': type,
            'amount': self.safe_float(transaction, 'number'),
            'currency': code,
            'status': status,
            'updated': timestamp,
            'fee': fee,
            'info': transaction,
        }

    def parse_transactions_by_type(self, type, transactions, code=None, since=None, limit=None):
        result = []
        for i in range(0, len(transactions)):
            transaction = self.parse_transaction(self.extend({
                'type': type,
            }, transactions[i]))
            result.append(transaction)
        return self.filter_by_currency_since_limit(result, code, since, limit)

    def parse_transaction_type(self, type):
        types = {
            'deposit': 1,
            'withdrawal': 2,
        }
        return self.safe_integer(types, type, type)

    async def fetch_deposits(self, code=None, since=None, limit=None, params={}):
        return await self.fetch_transactions_for_type('deposit', code, since, limit, params)

    async def fetch_withdrawals(self, code=None, since=None, limit=None, params={}):
        return await self.fetch_transactions_for_type('withdrawal', code, since, limit, params)

    async def fetch_transactions_for_type(self, type, code=None, since=None, limit=None, params={}):
        if code is None:
            raise ArgumentsRequired(self.id + ' fetchTransactions() requires a currency `code` argument')
        await self.load_markets()
        currency = self.currency(code)
        request = {
            'coin': currency['id'],
            'type': self.parse_transaction_type(type),
        }
        if since is not None:
            request['startTime'] = int(since / str(1000))
        if limit is not None:
            request['page'] = 1
            request['pageSize'] = limit
        response = await self.tradePostDepositOrWithdraw(self.extend(request, params))
        transactions = self.safe_value(response['data'], 'data', [])
        return self.parse_transactions_by_type(type, transactions, code, since, limit)

    async def withdraw(self, code, amount, address, tag=None, params={}):
        self.check_address(address)
        await self.load_markets()
        currency = self.currency(code)
        request = {
            'coin': currency['id'],
            'number': self.currency_to_precision(code, amount),
            'address': address,
            # 'type': 'erc20',  # omni, trc20, optional
        }
        if tag is not None:
            request['memo'] = tag
        response = await self.tradePostCoinOut(self.extend(request, params))
        #
        #     {
        #         "status":200,
        #         "msg":"",
        #         "data":{
        #             "id":397574,
        #             "email":"***@email.com",
        #             "coin":"usdt",
        #             "network_fee":"",
        #             "eid":23112
        #         },
        #         "time":1552641646,
        #         "microtime":"0.70304500 1552641646",
        #         "source":"api"
        #     }
        #
        data = self.safe_value(response, 'data', {})
        return self.parse_transaction(data, currency)

    def nonce(self):
        currentTimestamp = self.seconds()
        if currentTimestamp > self.options['lastNonceTimestamp']:
            self.options['lastNonceTimestamp'] = currentTimestamp
            self.options['lastNonce'] = 100000
        self.options['lastNonce'] = self.sum(self.options['lastNonce'], 1)
        return self.options['lastNonce']

    def sign(self, path, api='market', method='GET', params={}, headers=None, body=None):
        baseUrl = self.implode_params(self.urls['api'][api], {'hostname': self.hostname})
        url = baseUrl + '/' + self.capitalize(api) + '/' + path
        query = None
        if api == 'market':
            query = self.urlencode(params)
            if len(query):
                url += '?' + query
        else:
            self.check_required_credentials()
            body = self.rawencode(self.keysort(self.extend({
                'apiKey': self.apiKey,
                'timeStamp': self.seconds(),
                'nonce': self.nonce(),
            }, params)))
            body += '&sign=' + self.hash(self.encode(body + self.secret))
            headers = {'Content-type': 'application/x-www-form-urlencoded'}
        return {'url': url, 'method': method, 'body': body, 'headers': headers}

    def handle_errors(self, httpCode, reason, url, method, headers, body, response, requestHeaders, requestBody):
        if response is None:
            return  # fallback to default error handler
        status = self.safe_string(response, 'status')
        if status is not None:
            feedback = self.id + ' ' + body
            #
            #     {"status":-107,"msg":"","data":"","time":1535968848,"microtime":"0.89092200 1535968848","source":"api"}
            #
            if status == '200':
                #
                #     {"status":200,"msg":"","data":-200031,"time":1535999806,"microtime":"0.85476800 1535999806","source":"api"}
                #
                code = self.safe_integer(response, 'data')
                if code is not None:
                    self.throw_exactly_matched_exception(self.exceptions, code, feedback)
                    raise ExchangeError(feedback)
                else:
                    return  # no error
            self.throw_exactly_matched_exception(self.exceptions, status, feedback)
            raise ExchangeError(feedback)
