# -*- coding: utf-8 -*-

# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code

from ccxt.base.exchange import Exchange
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 BadRequest
from ccxt.base.errors import BadSymbol
from ccxt.base.errors import InsufficientFunds
from ccxt.base.errors import InvalidAddress
from ccxt.base.errors import InvalidOrder
from ccxt.base.errors import OrderNotFound
from ccxt.base.errors import InvalidNonce
from ccxt.base.decimal_to_precision import TRUNCATE


class aofex(Exchange):

    def describe(self):
        return self.deep_extend(super(aofex, self).describe(), {
            'id': 'aofex',
            'name': 'AOFEX',
            'countries': ['GB'],
            'rateLimit': 1000,
            'has': {
                'fetchMarkets': True,
                'fetchCurrencies': False,
                'fetchOrderBook': True,
                'fetchTrades': True,
                'fetchTicker': True,
                'fetchTickers': True,
                'fetchOHLCV': True,
                'fetchBalance': True,
                'createOrder': True,
                'cancelOrder': True,
                'cancelAllOrders': True,
                'fetchOpenOrders': True,
                'fetchClosedOrders': True,
                'fetchClosedOrder': True,
                'fetchOrderTrades': True,
                'fetchTradingFee': True,
            },
            'timeframes': {
                '1m': '1min',
                '5m': '5min',
                '15m': '15min',
                '30m': '30min',
                '1h': '1hour',
                '6h': '6hour',
                '12h': '12hour',
                '1d': '1day',
                '1w': '1week',
            },
            'urls': {
                'logo': 'https://user-images.githubusercontent.com/51840849/77670271-056d1080-6f97-11ea-9ac2-4268e9ed0c1f.jpg',
                'api': {
                    'public': 'https://openapi.aofex.com/openApi',
                    'private': 'https://openapi.aofex.com/openApi',
                },
                'www': 'https://aofex.com',
                'doc': 'https://aofex.zendesk.com/hc/en-us/sections/360005576574-API',
                'fees': 'https://aofex.zendesk.com/hc/en-us/articles/360025814934-Fees-on-AOFEX',
                'referral': 'https://aofex.com/#/register?key=9763840',
            },
            'api': {
                'public': {
                    'get': [
                        'market/symbols',
                        'market/trade',
                        'market/depth',
                        'market/kline',
                        'market/precision',
                        'market/24kline',
                        'market/gears_depth',
                        'market/detail',
                    ],
                },
                'private': {
                    'get': [
                        'entrust/currentList',
                        'entrust/historyList',
                        'entrust/rate',
                        'wallet/list',
                        'entrust/detail',
                    ],
                    'post': [
                        'entrust/add',
                        'entrust/cancel',
                    ],
                },
            },
            'fees': {
                'trading': {
                    'maker': 0.0019,
                    'taker': 0.002,
                },
            },
            'exceptions': {
                'exact': {
                    '20001': ExchangeError,  # request failure
                    '20401': PermissionDenied,  # no permission
                    '20500': ExchangeError,  # system error
                    '20501': BadSymbol,  # base symbol error
                    '20502': ExchangeError,  # base currency error
                    '20503': ExchangeError,  # base date error
                    '20504': InsufficientFunds,  # account frozen balance insufficient error
                    '20505': BadRequest,  # bad argument
                    '20506': AuthenticationError,  # api signature not valid
                    '20507': ExchangeError,  # gateway internal error
                    '20508': InvalidAddress,  # ad ethereum addresss
                    '20509': InsufficientFunds,  # order accountbalance error
                    '20510': InvalidOrder,  # order limitorder price error
                    '20511': InvalidOrder,  # order limitorder amount error
                    '20512': InvalidOrder,  # order orderprice precision error
                    '20513': InvalidOrder,  # order orderamount precision error
                    '20514': InvalidOrder,  # order marketorder amount error
                    '20515': InvalidOrder,  # order queryorder invalid
                    '20516': InvalidOrder,  # order orderstate error
                    '20517': InvalidOrder,  # order datelimit error
                    '50518': InvalidOrder,  # order update error
                    '20519': InvalidNonce,  # the nonce has been used
                    '20520': InvalidNonce,  # nonce expires, please verify server time
                    '20521': BadRequest,  # incomplete header parameters
                    '20522': ExchangeError,  # not getting the current user
                    '20523': AuthenticationError,  # please authenticate
                    '20524': PermissionDenied,  # btc account lockout
                    '20525': AuthenticationError,  # get API Key error
                    '20526': PermissionDenied,  # no query permission
                    '20527': PermissionDenied,  # no deal permission
                    '20528': PermissionDenied,  # no withdrawal permission
                    '20529': AuthenticationError,  # API Key expired
                    '20530': PermissionDenied,  # no permission
                },
                'broad': {
                },
            },
            'options': {
                'fetchBalance': {
                    'show_all': '0',  # '1' to show zero balances
                },
            },
        })

    def fetch_markets(self, params={}):
        markets = self.publicGetMarketSymbols(params)
        #
        #     {
        #         errno: 0,
        #         errmsg: 'success',
        #         result: [
        #             {
        #                 id: 2,
        #                 symbol: 'BTC-USDT',
        #                 base_currency: 'BTC',
        #                 quote_currency: 'USDT',
        #                 min_size: 0.00008,
        #                 max_size: 1300,
        #                 min_price: 1000,
        #                 max_price: 110000,
        #                 maker_fee: 1,
        #                 taker_fee: 1,
        #                 isHot: null,
        #                 isNew: null,
        #                 crown: null
        #             },
        #         ]
        #     }
        #
        precisions = self.publicGetMarketPrecision()
        #
        #     {
        #         errno: 0,
        #         errmsg: 'success',
        #         result: {
        #             'MANA-USDT': {
        #                 amount: '2',
        #                 minQuantity: '32',
        #                 maxQuantity: '46000000',
        #                 price: '4',
        #                 minPrice: '0.003',
        #                 maxPrice: '0.35'
        #             },
        #         }
        #     }
        #
        precisions = self.safe_value(precisions, 'result', {})
        markets = self.safe_value(markets, 'result', [])
        result = []
        for i in range(0, len(markets)):
            market = markets[i]
            id = self.safe_string(market, 'symbol')
            baseId = self.safe_string(market, 'base_currency')
            quoteId = self.safe_string(market, 'quote_currency')
            base = self.safe_currency_code(baseId)
            quote = self.safe_currency_code(quoteId)
            symbol = base + '/' + quote
            numericId = self.safe_integer(market, 'id')
            precision = self.safe_value(precisions, id, {})
            makerFee = self.safe_float(market, 'maker_fee')
            takerFee = self.safe_float(market, 'taker_fee')
            result.append({
                'id': id,
                'numericId': numericId,
                'symbol': symbol,
                'baseId': baseId,
                'quoteId': quoteId,
                'base': base,
                'quote': quote,
                'active': None,
                'maker': makerFee / 1000,
                'taker': takerFee / 1000,
                'precision': {
                    'amount': self.safe_integer(precision, 'amount'),
                    'price': self.safe_integer(precision, 'price'),
                },
                'limits': {
                    'amount': {
                        'min': self.safe_float(market, 'min_size'),
                        'max': self.safe_float(market, 'max_size'),
                    },
                    'price': {
                        'min': self.safe_float(market, 'min_price'),
                        'max': self.safe_float(market, 'max_price'),
                    },
                    'cost': {
                        'min': None,
                        'max': None,
                    },
                },
                'info': market,
            })
        return result

    def parse_ohlcv(self, ohlcv, market=None):
        #
        #     {
        #         id:  1584950100,
        #         amount: "329.196",
        #         count:  81,
        #         open: "0.021155",
        #         close: "0.021158",
        #         low: "0.021144",
        #         high: "0.021161",
        #         vol: "6.963557767"
        #     }
        #
        return [
            self.safe_timestamp(ohlcv, 'id'),
            self.safe_float(ohlcv, 'open'),
            self.safe_float(ohlcv, 'high'),
            self.safe_float(ohlcv, 'low'),
            self.safe_float(ohlcv, 'close'),
            self.safe_float(ohlcv, 'amount'),
        ]

    def fetch_ohlcv(self, symbol, timeframe='1m', since=None, limit=None, params={}):
        self.load_markets()
        market = self.market(symbol)
        if limit is None:
            limit = 150  # default 150, max 2000
        request = {
            'symbol': market['id'],
            'period': self.timeframes[timeframe],
            'size': limit,  # default 150, max 2000
        }
        response = self.publicGetMarketKline(self.extend(request, params))
        #
        #     {
        #         errno: 0,
        #         errmsg: "success",
        #         result: {
        #             ts:  1584950139003,
        #             symbol: "ETH-BTC",
        #             period: "1min",
        #             data: [
        #                 {
        #                     id:  1584950100,
        #                     amount: "329.196",
        #                     count:  81,
        #                     open: "0.021155",
        #                     close: "0.021158",
        #                     low: "0.021144",
        #                     high: "0.021161",
        #                     vol: "6.963557767"
        #                 },
        #                 {
        #                     id:  1584950040,
        #                     amount: "513.265",
        #                     count:  151,
        #                     open: "0.021165",
        #                     close: "0.021155",
        #                     low: "0.021151",
        #                     high: "0.02118",
        #                     vol: "10.862806573"
        #                 },
        #             ]
        #         }
        #     }
        #
        result = self.safe_value(response, 'result', {})
        data = self.safe_value(result, 'data', [])
        return self.parse_ohlcvs(data, market, since, limit)

    def fetch_balance(self, params={}):
        self.load_markets()
        options = self.safe_value(self.options, 'fetchBalance', {})
        showAll = self.safe_value(options, 'show_all', '0')
        request = {
            # 'currency': 'BTC',
            'show_all': showAll,  # required to show zero balances
        }
        response = self.privateGetWalletList(self.extend(request, params))
        #
        #     {
        #         "errno": 0,
        #         "errmsg": "success",
        #         "result": [
        #             {"available": "0", "frozen": "0", "currency": "BTC"}
        #         ]
        #     }
        #
        result = {'info': response}
        balances = self.safe_value(response, 'result', [])
        for i in range(0, len(balances)):
            balance = balances[i]
            currencyId = self.safe_string(balance, 'currency')
            code = self.safe_currency_code(currencyId)
            account = self.account()
            account['free'] = self.safe_float(balance, 'available')
            account['used'] = self.safe_float(balance, 'frozen')
            result[code] = account
        return self.parse_balance(result)

    def fetch_trading_fee(self, symbol, params={}):
        self.load_markets()
        market = self.market(symbol)
        request = {
            'symbol': market['id'],
        }
        response = self.privateGetEntrustRate(self.extend(request, params))
        #
        #     {
        #         "errno":0,
        #         "errmsg":"success",
        #         "result": {
        #             "toFee":"0.002","fromFee":"0.002"
        #         }
        #     }
        #
        result = self.safe_value(response, 'result', {})
        return {
            'info': response,
            'symbol': symbol,
            'maker': self.safe_float(result, 'fromFee'),
            'taker': self.safe_float(result, 'toFee'),
        }

    def fetch_order_book(self, symbol, limit=None, params={}):
        self.load_markets()
        request = {
            'symbol': self.market_id(symbol),
        }
        response = self.publicGetMarketDepth(self.extend(request, params))
        #
        #     {
        #         errno: 0,
        #         errmsg: "success",
        #         result: {
        #             buyType: 1,
        #             sellType: 1,
        #             ts: 1584950701050,
        #             symbol: "ETH-BTC",
        #             asks: [
        #                 ["0.021227", "0.182"],
        #                 ["0.021249", "0.035"],
        #                 ["0.021253", "0.058"],
        #             ],
        #             bids: [
        #                 ["0.021207", "0.039"],
        #                 ["0.021203", "0.051"],
        #                 ["0.02117", "2.326"],
        #             ]
        #         }
        #     }
        #
        result = self.safe_value(response, 'result', {})
        timestamp = self.safe_integer(result, 'ts')
        return self.parse_order_book(result, timestamp)

    def parse_ticker(self, ticker, market=None):
        #
        # fetchTicker
        #
        #     {
        #         id: 1584890087,
        #         amount: '150032.919',
        #         count: 134538,
        #         open: '0.021394',
        #         close: '0.021177',
        #         low: '0.021053',
        #         high: '0.021595',
        #         vol: '3201.72451442'
        #     }
        #
        timestamp = self.safe_timestamp(ticker, 'id')
        symbol = None
        if market:
            symbol = market['symbol']
        open = self.safe_float(ticker, 'open')
        last = self.safe_float(ticker, 'close')
        change = None
        if symbol is not None:
            change = float(self.price_to_precision(symbol, last - open))
        else:
            change = last - open
        average = self.sum(last, open) / 2
        percentage = change / open * 100
        baseVolume = self.safe_float(ticker, 'amount')
        quoteVolume = self.safe_float(ticker, 'vol')
        vwap = self.vwap(baseVolume, quoteVolume)
        if vwap is not None:
            vwap = float(self.price_to_precision(symbol, vwap))
        return {
            'symbol': symbol,
            'timestamp': timestamp,
            'datetime': self.iso8601(timestamp),
            'high': self.safe_float(ticker, 'high'),
            'low': self.safe_float(ticker, 'low'),
            'bid': None,
            'bidVolume': None,
            'ask': None,
            'askVolume': None,
            'vwap': vwap,
            'open': open,
            'close': last,
            'last': last,
            'previousClose': None,
            'change': change,
            'percentage': percentage,
            'average': average,
            'baseVolume': baseVolume,
            'quoteVolume': quoteVolume,
            'info': ticker,
        }

    def fetch_tickers(self, symbols=None, params={}):
        self.load_markets()
        request = {}
        if symbols is not None:
            ids = self.market_ids(symbols)
            request['symbol'] = ','.join(ids)
        response = self.publicGetMarket24kline(self.extend(request, params))
        #
        #     {
        #         errno: 0,
        #         errmsg: "success",
        #         result: [
        #             {
        #                 symbol: "HB-AQ",
        #                 data: {
        #                     id:  1584893403,
        #                     amount: "4753751.243400354852648809",
        #                     count:  4724,
        #                     open: "6.3497",
        #                     close: "6.3318",
        #                     low: "6.011",
        #                     high: "6.5",
        #                     vol: "29538384.7873528796542891343493"
        #                 }
        #             },
        #         ]
        #     }
        #
        tickers = self.safe_value(response, 'result', [])
        result = {}
        for i in range(0, len(tickers)):
            marketId = self.safe_string(tickers[i], 'symbol')
            market = self.safe_market(marketId, None, '-')
            symbol = market['symbol']
            data = self.safe_value(tickers[i], 'data', {})
            result[symbol] = self.parse_ticker(data, market)
        return self.filter_by_array(result, 'symbol', symbols)

    def fetch_ticker(self, symbol, params={}):
        self.load_markets()
        market = self.market(symbol)
        request = {
            'symbol': market['id'],
        }
        response = self.publicGetMarketDetail(self.extend(request, params))
        #
        #     {
        #         errno: 0,
        #         errmsg: 'success',
        #         result: {
        #             id: 1584890087,
        #             amount: '150032.919',
        #             count: 134538,
        #             open: '0.021394',
        #             close: '0.021177',
        #             low: '0.021053',
        #             high: '0.021595',
        #             vol: '3201.72451442'
        #         }
        #     }
        #
        result = self.safe_value(response, 'result', {})
        return self.parse_ticker(result, market)

    def parse_trade(self, trade, market=None):
        #
        # fetchTrades(public)
        #
        #     {
        #         id: 1584948803298490,
        #         amount: "2.737",
        #         price: "0.021209",
        #         direction: "sell",
        #         ts: 1584948803
        #     }
        #
        # fetchOrder trades
        #
        #     {
        #         "id":null,
        #         "ctime":"2020-03-23 20:07:17",
        #         "price":"123.9",
        #         "number":"0.010688626311541565",
        #         "total_price":"1.324320799999999903",
        #         "fee":"0.000021377252623083"
        #     }
        #
        id = self.safe_string(trade, 'id')
        ctime = self.parse8601(self.safe_string(trade, 'ctime'))
        timestamp = self.safe_timestamp(trade, 'ts', ctime) - 28800000  # 8 hours, adjust to UTC
        symbol = None
        if (symbol is None) and (market is not None):
            symbol = market['symbol']
        side = self.safe_string(trade, 'direction')
        price = self.safe_float(trade, 'price')
        amount = self.safe_float_2(trade, 'amount', 'number')
        cost = self.safe_float(trade, 'total_price')
        if (cost is None) and (price is not None) and (amount is not None):
            cost = price * amount
        feeCost = self.safe_float(trade, 'fee')
        fee = None
        if feeCost is not None:
            feeCurrencyCode = None
            if market is not None:
                if side == 'buy':
                    feeCurrencyCode = market['base']
                elif side == 'sell':
                    feeCurrencyCode = market['quote']
            fee = {
                'cost': feeCost,
                'currency': feeCurrencyCode,
            }
        return {
            'id': id,
            'info': trade,
            'timestamp': timestamp,
            'datetime': self.iso8601(timestamp),
            'symbol': symbol,
            'order': None,
            'type': None,
            'side': side,
            'takerOrMaker': None,
            'price': price,
            'amount': amount,
            'cost': cost,
            'fee': fee,
        }

    def fetch_trades(self, symbol, since=None, limit=None, params={}):
        self.load_markets()
        market = self.market(symbol)
        request = {
            'symbol': market['id'],
        }
        response = self.publicGetMarketTrade(self.extend(request, params))
        #
        #     {
        #         errno: 0,
        #         errmsg: "success",
        #         result: {
        #             symbol: "ETH-BTC",
        #             ts: 1584948805439,
        #             data: [
        #                 {
        #                     id: 1584948803300883,
        #                     amount: "0.583",
        #                     price: "0.021209",
        #                     direction: "buy",
        #                     ts: 1584948803
        #                 },
        #                 {
        #                     id: 1584948803298490,
        #                     amount: "2.737",
        #                     price: "0.021209",
        #                     direction: "sell",
        #                     ts: 1584948803
        #                 },
        #             ]
        #         }
        #     }
        #
        result = self.safe_value(response, 'result', {})
        data = self.safe_value(result, 'data', [])
        return self.parse_trades(data, market, since, limit)

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

    def parse_order(self, order, market=None):
        #
        # createOrder
        #
        #     {order_sn: 'BM7442641584965237751ZMAKJ5'}
        #
        # fetchOpenOrders, fetchClosedOrders
        #
        #     {
        #         "order_sn": "BL74426415849672087836G48N1",
        #         "symbol": "ETH-USDT",
        #         "ctime": "2020-03-23 20:40:08",
        #         "type": 2,
        #         "side": "buy",
        #         "price": "90",  # None for market orders
        #         "number": "0.1",
        #         "total_price": "9.0",  # 0 for market orders
        #         "deal_number": null,
        #         "deal_price": null,
        #         "status": 1,
        #     }
        #
        # fetchOrder
        #
        #     {
        #         order_sn: 'BM7442641584965237751ZMAKJ5',
        #         symbol: 'ETH-USDT',
        #         ctime: '2020-03-23 20:07:17',
        #         type: 1,
        #         side: 'buy',
        #         price: '0',
        #         number: '10',
        #         total_price: '0',
        #         deal_number: '0.080718626311541565',
        #         deal_price: '123.890000000000000000',
        #         status: 3,
        #         # the trades field is injected by fetchOrder
        #         trades: [
        #             {
        #                 id: null,
        #                 ctime: '2020-03-23 20:07:17',
        #                 price: '123.9',
        #                 number: '0.010688626311541565',
        #                 total_price: '1.324320799999999903',
        #                 fee: '0.000021377252623083'
        #             }
        #         ]
        #     }
        #
        id = self.safe_string(order, 'order_sn')
        orderStatus = self.safe_string(order, 'status')
        status = self.parse_order_status(orderStatus)
        marketId = self.safe_string(order, 'symbol')
        market = self.safe_market(marketId, market, '-')
        timestamp = self.parse8601(self.safe_string(order, 'ctime'))
        if timestamp is not None:
            timestamp -= 28800000  # 8 hours, adjust to UTC
        orderType = self.safe_string(order, 'type')
        type = 'limit' if (orderType == '2') else 'market'
        side = self.safe_string(order, 'side')
        # amount = self.safe_float(order, 'number')
        # price = self.safe_float(order, 'price')
        cost = None
        price = None
        amount = None
        average = None
        number = self.safe_float(order, 'number')
        totalPrice = self.safe_float(order, 'total_price')
        if type == 'limit':
            amount = number
            price = self.safe_float(order, 'price')
        else:
            average = self.safe_float(order, 'deal_price')
            if side == 'buy':
                amount = self.safe_float(order, 'deal_number')
            else:
                amount = number
        fee = None
        trades = None
        filled = None
        feeCost = None
        remaining = None
        lastTradeTimestamp = None
        # all orders except new orders and canceled orders
        if (orderStatus != '1') and (orderStatus != '6'):
            rawTrades = self.safe_value(order, 'trades')
            if rawTrades is not None:
                for i in range(0, len(rawTrades)):
                    rawTrades[i]['direction'] = side
                trades = self.parse_trades(rawTrades, market, None, None, {
                    'symbol': market['symbol'],
                    'order': id,
                    'side': side,
                    'type': type,
                })
                tradesLength = len(trades)
                if tradesLength > 0:
                    firstTrade = trades[0]
                    feeCost = firstTrade['fee']['cost']
                    lastTradeTimestamp = firstTrade['timestamp']
                    filled = firstTrade['amount']
                    cost = firstTrade['cost']
                    for i in range(1, len(trades)):
                        trade = trades[i]
                        feeCost = self.sum(feeCost, trade['fee']['cost'])
                        filled = self.sum(filled, trade['amount'])
                        cost = self.sum(cost, trade['cost'])
                        lastTradeTimestamp = max(lastTradeTimestamp, trade['timestamp'])
                    if amount is not None:
                        filled = min(amount, filled)
                    if filled > 0:
                        average = cost / filled
                if feeCost is not None:
                    feeCurrencyCode = market['base'] if (side == 'buy') else market['quote']
                    fee = {
                        'cost': feeCost,
                        'currency': feeCurrencyCode,
                    }
        else:
            filled = 0
            cost = 0
        if cost is None:
            if type == 'limit':
                cost = totalPrice
            elif side == 'buy':
                cost = number
        if filled is None:
            if (type == 'limit') and (orderStatus == '3'):
                filled = amount
        if filled is not None:
            if amount is not None:
                remaining = max(amount - filled, 0)
        return {
            'info': order,
            'id': id,
            'clientOrderId': None,
            'timestamp': timestamp,
            'datetime': self.iso8601(timestamp),
            'lastTradeTimestamp': lastTradeTimestamp,
            'status': status,
            'symbol': market['symbol'],
            'type': type,
            'timeInForce': None,
            'postOnly': None,
            'side': side,
            'price': price,
            'stopPrice': None,
            'cost': cost,
            'average': average,
            'amount': amount,
            'filled': filled,
            'remaining': remaining,
            'trades': trades,
            'fee': fee,
        }

    def fetch_closed_order(self, id, symbol=None, params={}):
        self.load_markets()
        request = {
            'order_sn': id,
        }
        response = self.privateGetEntrustDetail(self.extend(request, params))
        #
        #     {
        #         "errno": 0,
        #         "errmsg": "success",
        #         "result": {
        #             "trades": [
        #                 {
        #                     "id":null,
        #                     "ctime":"2020-03-23 20:07:17",
        #                     "price":"123.9",
        #                     "number":"0.010688626311541565",
        #                     "total_price":"1.324320799999999903",
        #                     "fee":"0.000021377252623083"
        #                 },
        #             ],
        #             "entrust":{
        #                 "order_sn":"BM7442641584965237751ZMAKJ5",
        #                 "symbol":"ETH-USDT",
        #                 "ctime":"2020-03-23 20:07:17",
        #                 "type":1,
        #                 "side":"buy",
        #                 "price":"0",
        #                 "number":"10",
        #                 "total_price":"0",
        #                 "deal_number":"0.080718626311541565",
        #                 "deal_price":"123.890000000000000000",
        #                 "status":3
        #             }
        #         }
        #     }
        #
        result = self.safe_value(response, 'result', {})
        trades = self.safe_value(result, 'trades', [])
        order = self.safe_value(result, 'entrust', {})
        order['trades'] = trades
        return self.parse_order(order)

    def fetch_order_trades(self, id, symbol=None, since=None, limit=None, params={}):
        response = self.fetch_closed_order(id, symbol, params)
        return self.safe_value(response, 'trades', [])

    def fetch_orders_with_method(self, method, symbol=None, since=None, limit=None, params={}):
        self.load_markets()
        request = {
            # 'from': 'BM7442641584965237751ZMAKJ5',  # query start order_sn
            'direct': 'prev',  # next
        }
        market = None
        if symbol is not None:
            market = self.market(symbol)
            request['symbol'] = market['id']
        if limit is not None:
            request['limit'] = limit  # default 20, max 100
        response = getattr(self, method)(self.extend(request, params))
        #
        #     {
        #         "errno": 0,
        #         "errmsg": "success",
        #         "result": [
        #             {
        #                 "order_sn": "BL74426415849672087836G48N1",
        #                 "symbol": "ETH-USDT",
        #                 "ctime": "2020-03-23 20:40:08",
        #                 "type": 2,
        #                 "side": "buy",
        #                 "price": "90",
        #                 "number": "0.1",
        #                 "total_price": "9.0",
        #                 "deal_number": null,
        #                 "deal_price": null,
        #                 "status": 1,
        #             }
        #         ]
        #     }
        #
        result = self.safe_value(response, 'result', [])
        return self.parse_orders(result, market, since, limit)

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

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

    def create_order(self, symbol, type, side, amount, price=None, params={}):
        self.load_markets()
        market = self.market(symbol)
        orderType = side + '-' + type
        request = {
            'symbol': market['id'],
            'type': orderType,
        }
        if type == 'limit':
            request['amount'] = self.amount_to_precision(symbol, amount)
            request['price'] = self.price_to_precision(symbol, price)
        elif type == 'market':
            # for market buy it requires the amount of quote currency to spend
            if side == 'buy':
                createMarketBuyOrderRequiresPrice = self.safe_value(self.options, 'createMarketBuyOrderRequiresPrice', True)
                cost = amount
                if createMarketBuyOrderRequiresPrice:
                    if price is not None:
                        cost = amount * price
                    else:
                        raise InvalidOrder(self.id + " createOrder() requires the price argument with market buy orders to calculate total order cost(amount to spend), where cost = amount * price. Supply a price argument to createOrder() call if you want the cost to be calculated for you from price and amount, or, alternatively, add .options['createMarketBuyOrderRequiresPrice'] = False and supply the total cost value in the 'amount' argument")
                precision = market['precision']['price']
                request['amount'] = self.decimal_to_precision(cost, TRUNCATE, precision, self.precisionMode)
            else:
                request['amount'] = self.amount_to_precision(symbol, amount)
        response = self.privatePostEntrustAdd(self.extend(request, params))
        #
        #     {
        #         errno: 0,
        #         errmsg: 'success',
        #         result: {order_sn: 'BM7442641584965237751ZMAKJ5'}
        #     }
        #
        result = self.safe_value(response, 'result', {})
        order = self.parse_order(result, market)
        timestamp = self.milliseconds()
        return self.extend(order, {
            'timestamp': timestamp,
            'datetime': self.iso8601(timestamp),
            'amount': amount,
            'price': price,
            'type': type,
            'side': side,
        })

    def cancel_order(self, id, symbol=None, params={}):
        self.load_markets()
        request = {
            'order_ids': id,
        }
        response = self.privatePostEntrustCancel(self.extend(request, params))
        #
        #     {
        #         "errno": 0,
        #         "errmsg": "success",
        #         "result": {
        #             "success": ["avl12121", "bl3123123"],
        #             "failed": ["sd24564", "sdf6564564"]
        #         }
        #     }
        #
        result = self.safe_value(response, 'result', {})
        success = self.safe_value(result, 'success', [])
        if not self.in_array(id, success):
            raise OrderNotFound(self.id + ' order id ' + id + ' not found in successfully canceled orders: ' + self.json(response))
        timestamp = None
        return {
            'info': response,
            'id': id,
            'timestamp': timestamp,
            'datetime': self.iso8601(timestamp),
            'lastTradeTimestamp': None,
            'status': 'canceled',
            'symbol': symbol,
            'type': None,
            'side': None,
            'price': None,
            'cost': None,
            'average': None,
            'amount': None,
            'filled': None,
            'remaining': None,
            'trades': None,
            'fee': None,
            'clientOrderId': None,
        }

    def cancel_all_orders(self, symbol=None, params={}):
        if symbol is None:
            raise ArgumentsRequired(self.id + ' cancelAllOrders() requires a symbol argument')
        self.load_markets()
        market = self.market(symbol)
        request = {
            'symbol': market['id'],
        }
        response = self.privatePostEntrustCancel(self.extend(request, params))
        #
        #     {
        #         "errno": 0,
        #         "errmsg": "success",
        #         "result": {
        #             "success": ["avl12121", "bl3123123"],
        #             "failed": ["sd24564", "sdf6564564"]
        #         }
        #     }
        #
        return response

    def nonce(self):
        return self.milliseconds()

    def sign(self, path, api='public', method='GET', params={}, headers=None, body=None):
        url = self.urls['api'][api] + '/' + path
        keys = list(params.keys())
        keysLength = len(keys)
        if api == 'public':
            if keysLength > 0:
                url += '?' + self.urlencode(params)
        else:
            nonce = str(self.nonce())
            uuid = self.uuid()
            randomString = uuid[0:5]
            nonceString = nonce + '_' + randomString
            auth = {}
            auth[self.apiKey] = self.apiKey
            auth[self.secret] = self.secret
            auth[nonceString] = nonceString
            for i in range(0, keysLength):
                key = keys[i]
                auth[key] = key + '=' + params[key]
            keysorted = self.keysort(auth)
            stringToSign = ''
            keys = list(keysorted.keys())
            for i in range(0, len(keys)):
                key = keys[i]
                stringToSign += keysorted[key]
            signature = self.hash(self.encode(stringToSign), 'sha1')
            headers = {
                'Nonce': nonceString,
                'Token': self.apiKey,
                'Signature': signature,
            }
            if method == 'POST':
                headers['Content-Type'] = 'application/x-www-form-urlencoded'
                if keysLength > 0:
                    body = self.urlencode(params)
            else:
                if keysLength > 0:
                    url += '?' + self.urlencode(params)
        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
        #
        #     {"errno":20501,"errmsg":"base symbol error"}
        #
        error = self.safe_string(response, 'errno')
        if (error is not None) and (error != '0'):
            message = self.safe_string(response, 'errmsg')
            feedback = self.id + ' ' + body
            self.throw_exactly_matched_exception(self.exceptions['exact'], error, feedback)
            self.throw_broadly_matched_exception(self.exceptions['broad'], message, feedback)
            raise ExchangeError(feedback)  # unknown message
