# -*- 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 ArgumentsRequired


class coss(Exchange):

    def describe(self):
        return self.deep_extend(super(coss, self).describe(), {
            'id': 'coss',
            'name': 'COSS',
            'countries': ['SG', 'NL'],
            'rateLimit': 1000,
            'version': 'v1',
            'certified': False,
            'urls': {
                'logo': 'https://user-images.githubusercontent.com/51840849/87443313-008fa380-c5fe-11ea-8400-34d4749c7da5.jpg',
                'api': {
                    'trade': 'https://trade.coss.io/c/api/v1',
                    'engine': 'https://engine.coss.io/api/v1',
                    'public': 'https://trade.coss.io/c/api/v1',
                    'web': 'https://trade.coss.io/c',  # undocumented
                    'exchange': 'https://exchange.coss.io/api',
                },
                'www': 'https://www.coss.io',
                'doc': 'https://api.coss.io/v1/spec',
                'referral': 'https://www.coss.io/c/reg?r=OWCMHQVW2Q',
            },
            'has': {
                'fetchTrades': True,
                'fetchTicker': True,
                'fetchTickers': True,
                'fetchMarkets': True,
                'fetchCurrencies': True,
                'fetchBalance': True,
                'fetchOrderBook': True,
                'fetchOrder': True,
                'fetchOrders': True,
                'fetchOrderTrades': True,
                'fetchClosedOrders': True,
                'fetchOpenOrders': True,
                'fetchOHLCV': True,
                'createOrder': True,
                'cancelOrder': True,
            },
            'timeframes': {
                '1m': '1m',
                '5m': '5m',
                '15m': '15m',
                '30m': '30m',
                '1h': '1h',
                '2h': '2h',
                '4h': '4h',
                '6h': '6h',
                '12h': '12h',
                '1d': '1d',
                '1w': '1w',
            },
            'api': {
                'exchange': {
                    'get': [
                        'getmarketsummaries',
                    ],
                },
                'public': {
                    'get': [
                        'market-price',
                        'exchange-info',
                    ],
                },
                'web': {
                    'get': [
                        'coins/getinfo/all',  # undocumented
                        'order/symbols',  # undocumented
                        'coins/get_base_list',  # undocumented
                    ],
                },
                'engine': {
                    'get': [
                        'dp',
                        'ht',
                        'cs',
                    ],
                },
                'trade': {
                    'get': [
                        'ping',
                        'time',
                        'account/balances',
                        'account/details',
                    ],
                    'post': [
                        'order/add',
                        'order/details',
                        'order/list/open',
                        'order/list/completed',
                        'order/list/all',
                        'order/trade-detail',
                    ],
                    'delete': [
                        'order/cancel',
                    ],
                },
            },
            'fees': {
                'trading': {
                    'tierBased': True,
                    'percentage': True,
                    'taker': 0.0025,
                    'maker': 0.0,
                },
                'funding': {
                    'tierBased': False,
                    'percentage': False,
                    'withdraw': {},
                    'deposit': {},
                },
            },
            'commonCurrencies': {
                'COS': 'COSS',
                'COSS': 'COSS.io',
            },
        })

    async def fetch_markets(self, params={}):
        response = await self.publicGetExchangeInfo(params)
        #
        #     {       timezone:   "UTC",
        #           server_time:    1545171487108,
        #           rate_limits: [{    type: "REQUESTS",
        #                            interval: "MINUTE",
        #                               limit:  1000       }],
        #       base_currencies: [{currency_code: "BTC", minimum_total_order: "0.0001"},
        #                          {currency_code: "USDT", minimum_total_order: "1"},
        #                          {currency_code: "EUR", minimum_total_order: "1"}],
        #                 coins: [{       currency_code: "ADI",
        #                                            name: "Aditus",
        #                            minimum_order_amount: "0.00000001"},
        #                          ...
        #                          {       currency_code: "NPXSXEM",
        #                                            name: "PundiX-XEM",
        #                            minimum_order_amount: "0.00000001"  }                ],
        #               symbols: [{              symbol: "ADI_BTC",
        #                            amount_limit_decimal:  0,
        #                             price_limit_decimal:  8,
        #                                   allow_trading:  True      },
        #                          ...
        #                          {              symbol: "ETH_GUSD",
        #                            amount_limit_decimal:  5,
        #                             price_limit_decimal:  3,
        #                                   allow_trading:  True       }     ]               }
        #
        result = []
        markets = self.safe_value(response, 'symbols', [])
        baseCurrencies = self.safe_value(response, 'base_currencies', [])
        baseCurrenciesByIds = self.index_by(baseCurrencies, 'currency_code')
        currencies = self.safe_value(response, 'coins', [])
        currenciesByIds = self.index_by(currencies, 'currency_code')
        for i in range(0, len(markets)):
            market = markets[i]
            marketId = market['symbol']
            baseId, quoteId = marketId.split('_')
            base = self.safe_currency_code(baseId)
            quote = self.safe_currency_code(quoteId)
            symbol = base + '/' + quote
            precision = {
                'amount': self.safe_integer(market, 'amount_limit_decimal'),
                'price': self.safe_integer(market, 'price_limit_decimal'),
            }
            active = self.safe_value(market, 'allow_trading', False)
            baseCurrency = self.safe_value(baseCurrenciesByIds, baseId, {})
            minCost = self.safe_float(baseCurrency, 'minimum_total_order')
            currency = self.safe_value(currenciesByIds, baseId, {})
            defaultMinAmount = math.pow(10, -precision['amount'])
            minAmount = self.safe_float(currency, 'minimum_order_amount', defaultMinAmount)
            result.append({
                'symbol': symbol,
                'id': marketId,
                'baseId': baseId,
                'quoteId': quoteId,
                'base': base,
                'quote': quote,
                'active': active,
                'precision': precision,
                'limits': {
                    'amount': {
                        'min': minAmount,
                        'max': None,
                    },
                    'price': {
                        'min': None,
                        'max': None,
                    },
                    'cost': {
                        'min': minCost,
                        'max': None,
                    },
                },
                'info': market,
            })
        return result

    async def fetch_currencies(self, params={}):
        response = await self.webGetCoinsGetinfoAll(params)
        #
        #     [{                currency_code: "VET",
        #                                  name: "VeChain",
        #                             buy_limit:  0,
        #                            sell_limit:  0,
        #                                  usdt:  0,
        #                transaction_time_limit:  5,
        #                                status: "trade",
        #                         withdrawn_fee: "0.6",
        #              minimum_withdrawn_amount: "1.2",
        #                minimum_deposit_amount: "0.6",
        #                  minimum_order_amount: "0.00000001",
        #                        decimal_format: "0.########",
        #                            token_type:  null,  # "erc", "eos", "stellar", "tron", "ripple"...
        #                                buy_at:  0,
        #                               sell_at:  0,
        #                              min_rate:  0,
        #                              max_rate:  0,
        #                       allow_withdrawn:  False,
        #                         allow_deposit:  False,
        #         explorer_website_mainnet_link:  null,
        #         explorer_website_testnet_link:  null,
        #            deposit_block_confirmation: "6",
        #           withdraw_block_confirmation: "0",
        #                              icon_url: "https://s2.coinmarketcap.com/static/img/coins/32x32/3077.png",
        #                               is_fiat:  False,
        #                            allow_sell:  True,
        #                             allow_buy:  True                                                           }]
        #
        result = {}
        for i in range(0, len(response)):
            currency = response[i]
            currencyId = self.safe_string(currency, 'currency_code')
            code = self.safe_currency_code(currencyId)
            name = self.safe_string(currency, 'name')
            allowBuy = self.safe_value(currency, 'allow_buy')
            allowSell = self.safe_value(currency, 'allow_sell')
            allowWithdrawals = self.safe_value(currency, 'allow_withdrawn')
            allowDeposits = self.safe_value(currency, 'allow_deposit')
            active = allowBuy and allowSell and allowWithdrawals and allowDeposits
            fee = self.safe_float(currency, 'withdrawn_fee')
            type = self.safe_string(currency, 'token_type')
            #
            # decimal_format can be anything...
            #
            #     0.########
            #     #.########
            #     0.##
            #     ''(empty string)
            #     0.000000
            #     null(None)
            #     0.0000
            #     0.###
            #
            decimalFormat = self.safe_string(currency, 'decimal_format')
            precision = 8
            if decimalFormat is not None:
                parts = decimalFormat.split('.')
                numParts = len(parts)  # transpiler workaround for array lengths
                if numParts > 1:
                    if len(parts[1]) > 1:
                        precision = len(parts[1])
            result[code] = {
                'id': currencyId,
                'code': code,
                'info': currency,
                'name': name,
                'active': active,
                'fee': fee,
                'precision': precision,
                'type': type,
                'limits': {
                    'amount': {
                        'min': self.safe_float(currency, 'minimum_order_amount'),
                        'max': None,
                    },
                    'withdraw': {
                        'min': self.safe_float(currency, 'minimum_withdrawn_amount'),
                        'max': None,
                    },
                },
            }
        return result

    async def fetch_balance(self, params={}):
        await self.load_markets()
        response = await self.tradeGetAccountBalances(params)
        #
        #     [{currency_code: "ETH",
        #               address: "0x6820511d43111a941d3e187b9e36ec64af763bde",  # deposit address
        #                 total: "0.20399125",
        #             available: "0.20399125",
        #              in_order: "0",
        #                  memo:  null                                         },  # tag, if any
        #       {currency_code: "ICX",
        #               address: "",
        #                 total: "0",
        #             available: "0",
        #              in_order: "0",
        #                  memo:  null  }                                         ]
        #
        result = {}
        for i in range(0, len(response)):
            balance = response[i]
            currencyId = self.safe_string(balance, 'currency_code')
            code = self.safe_currency_code(currencyId)
            total = self.safe_float(balance, 'total')
            used = self.safe_float(balance, 'in_order')
            free = self.safe_float(balance, 'available')
            result[code] = {
                'total': total,
                'used': used,
                'free': free,
            }
        return self.parse_balance(result)

    def parse_ohlcv(self, ohlcv, market=None):
        #
        #     [
        #         1545138960000,
        #         "0.02705000",
        #         "0.02705000",
        #         "0.02705000",
        #         "0.02705000",
        #         "0.00000000"
        #     ]
        #
        return [
            self.safe_integer(ohlcv, 0),   # timestamp
            self.safe_float(ohlcv, 1),  # Open
            self.safe_float(ohlcv, 2),  # High
            self.safe_float(ohlcv, 3),  # Low
            self.safe_float(ohlcv, 4),  # Close
            self.safe_float(ohlcv, 5),  # base Volume
        ]

    async def fetch_ohlcv(self, symbol, timeframe='1m', since=None, limit=None, params={}):
        await self.load_markets()
        market = self.market(symbol)
        request = {
            'symbol': market['id'],
            'tt': self.timeframes[timeframe],
        }
        response = await self.engineGetCs(self.extend(request, params))
        #
        #     {
        #         tt: "1m",
        #         symbol: "ETH_BTC",
        #         nextTime: 1545138960000,
        #         series: [
        #             [
        #                 1545138960000,
        #                 "0.02705000",
        #                 "0.02705000",
        #                 "0.02705000",
        #                 "0.02705000",
        #                 "0.00000000"
        #             ],
        #         ],
        #         limit: 500
        #     }
        #
        series = self.safe_value(response, 'series', [])
        return self.parse_ohlcvs(series, market, timeframe, since, limit)

    async def fetch_order_book(self, symbol, limit=None, params={}):
        await self.load_markets()
        marketId = self.market_id(symbol)
        request = {'symbol': marketId}
        # limit argument is not supported on COSS's end
        response = await self.engineGetDp(self.extend(request, params))
        #
        #     {symbol:   "COSS_ETH",
        #         asks: [["0.00065200", "214.15000000"],
        #                 ["0.00065300", "645.45000000"],
        #                 ...
        #                 ["0.00076400", "380.00000000"],
        #                 ["0.00076900", "25.00000000"]     ],
        #        limit:    100,
        #         bids: [["0.00065100", "666.99000000"],
        #                 ["0.00065000", "1171.93000000"],
        #                 ...
        #                 ["0.00037700", "3300.00000000"],
        #                 ["0.00037600", "2010.82000000"]   ],
        #         time:    1545180569354                       }
        #
        timestamp = self.safe_integer(response, 'time')
        return self.parse_order_book(response, timestamp)

    def parse_ticker(self, ticker, market=None):
        #
        #      {MarketName: "COSS-ETH",
        #              High:  0.00066,
        #               Low:  0.000628,
        #        BaseVolume:  131.09652674,
        #              Last:  0.000636,
        #         TimeStamp: "2018-12-19T05:16:41.369Z",
        #            Volume:  206126.6143710692,
        #               Ask: "0.00063600",
        #               Bid: "0.00063400",
        #           PrevDay:  0.000636                   }
        #
        timestamp = self.parse8601(self.safe_string(ticker, 'TimeStamp'))
        marketId = self.safe_string(ticker, 'MarketName')
        if marketId is not None:
            marketId = marketId.replace('-', '_')
        symbol = self.safe_symbol(marketId, market, '_')
        previous = self.safe_float(ticker, 'PrevDay')
        last = self.safe_float(ticker, 'Last')
        change = None
        percentage = None
        if last is not None:
            if previous is not None:
                change = last - previous
                if previous > 0:
                    percentage = (change / previous) * 100
        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, 'Bid'),
            'bidVolume': None,
            'ask': self.safe_float(ticker, 'Ask'),
            'askVolume': None,
            'vwap': None,
            'open': previous,
            'close': last,
            'last': last,
            'previousClose': None,
            'change': change,
            'percentage': percentage,
            'average': None,
            'baseVolume': self.safe_float(ticker, 'Volume'),
            'quoteVolume': self.safe_float(ticker, 'BaseVolume'),
            'info': ticker,
        }

    async def fetch_tickers(self, symbols=None, params={}):
        await self.load_markets()
        response = await self.exchangeGetGetmarketsummaries(params)
        #
        #     {success:    True,
        #       message:   "",
        #        result: [{MarketName: "COSS-ETH",
        #                          High:  0.00066,
        #                           Low:  0.000628,
        #                    BaseVolume:  131.09652674,
        #                          Last:  0.000636,
        #                     TimeStamp: "2018-12-19T05:16:41.369Z",
        #                        Volume:  206126.6143710692,
        #                           Ask: "0.00063600",
        #                           Bid: "0.00063400",
        #                       PrevDay:  0.000636                   },
        #                  ...
        #                  {MarketName: "XLM-BTC",
        #                          High:  0.0000309,
        #                           Low:  0.0000309,
        #                    BaseVolume:  0,
        #                          Last:  0.0000309,
        #                     TimeStamp: "2018-12-19T02:00:02.145Z",
        #                        Volume:  0,
        #                           Ask: "0.00003300",
        #                           Bid: "0.00003090",
        #                       PrevDay:  0.0000309                  }  ],
        #       volumes: [{CoinName: "ETH", Volume: 668.1928095999999},  # these are overall exchange volumes
        #                  {CoinName: "USD", Volume: 9942.58480324},
        #                  {CoinName: "BTC", Volume: 43.749184570000004},
        #                  {CoinName: "COSS", Volume: 909909.26644574},
        #                  {CoinName: "EUR", Volume: 0},
        #                  {CoinName: "TUSD", Volume: 2613.3395026999997},
        #                  {CoinName: "USDT", Volume: 1017152.07416519},
        #                  {CoinName: "GUSD", Volume: 1.80438},
        #                  {CoinName: "XRP", Volume: 15.95508},
        #                  {CoinName: "GBP", Volume: 0},
        #                  {CoinName: "USDC", Volume: 0}                   ],
        #             t:    1545196604371                                       }
        #
        tickers = self.safe_value(response, 'result', [])
        result = {}
        for i in range(0, len(tickers)):
            ticker = self.parse_ticker(tickers[i])
            symbol = ticker['symbol']
            result[symbol] = ticker
        return self.filter_by_array(result, 'symbol', symbols)

    async def fetch_ticker(self, symbol, params={}):
        tickers = await self.fetch_tickers([symbol], params)
        return tickers[symbol]

    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.engineGetHt(self.extend(request, params))
        #
        #     { symbol:   "COSS_ETH",
        #         limit:    100,
        #       history: [{          id:  481321,
        #                           price: "0.00065100",
        #                             qty: "272.92000000",
        #                    isBuyerMaker:  False,
        #                            time:  1545180845019  },
        #                  {          id:  481322,
        #                           price: "0.00065200",
        #                             qty: "1.90000000",
        #                    isBuyerMaker:  True,
        #                            time:  1545180847535},
        #                  ...
        #                  {          id:  481420,
        #                           price: "0.00065300",
        #                             qty: "2.00000000",
        #                    isBuyerMaker:  True,
        #                            time:  1545181167702}   ],
        #          time:    1545181171274                        }
        #
        return self.parse_trades(response['history'], market, since, limit)

    def parse_trade_fee(self, fee):
        if fee is None:
            return fee
        parts = fee.split(' ')
        numParts = len(parts)
        cost = parts[0]
        code = None
        if numParts > 1:
            code = self.safe_currency_code(parts[1])
        return {
            'cost': cost,
            'currency': code,
        }

    def parse_trade(self, trade, market=None):
        #
        # fetchTrades(public)
        #
        #      {          id:  481322,
        #               price: "0.00065200",
        #                 qty: "1.90000000",
        #        isBuyerMaker:  True,
        #                time:  1545180847535}
        #
        # fetchOrderTrades(private)
        #
        #     [{        hex_id:  null,
        #                 symbol: "COSS_ETH",
        #               order_id: "ad6f6b47-3def-4add-a5d5-2549a9df1593",
        #             order_side: "BUY",
        #                  price: "0.00065900",
        #               quantity: "10",
        #                    fee: "0.00700000 COSS",
        #         additional_fee: "0.00000461 ETH",
        #                  total: "0.00659000 ETH",
        #              timestamp:  1545152356075                          }]
        #
        id = self.safe_string(trade, 'id')
        timestamp = self.safe_integer(trade, 'time')
        orderId = self.safe_string(trade, 'order_id')
        side = self.safe_string_lower(trade, 'order_side')
        marketId = self.safe_string(trade, 'symbol')
        symbol = self.safe_symbol(marketId, market, '_')
        cost = None
        price = self.safe_float(trade, 'price')
        amount = self.safe_float_2(trade, 'qty', 'quantity')
        if amount is not None:
            if price is not None:
                cost = price * amount
        result = {
            'id': id,
            'info': trade,
            'timestamp': timestamp,
            'datetime': self.iso8601(timestamp),
            'symbol': symbol,
            'order': orderId,
            'type': None,
            'side': side,
            'takerOrMaker': None,
            'price': price,
            'amount': amount,
            'cost': cost,
            'fee': None,
        }
        fee = self.parse_trade_fee(self.safe_string(trade, 'fee'))
        if fee is not None:
            additionalFee = self.parse_trade_fee(self.safe_string(trade, 'additional_fee'))
            if additionalFee is None:
                result['fee'] = fee
            else:
                result['fees'] = [
                    fee,
                    additionalFee,
                ]
        return result

    async def fetch_orders_by_type(self, type, symbol=None, since=None, limit=None, params={}):
        if symbol is None:
            raise ArgumentsRequired(self.id + ' fetchOrders requires a symbol argument')
        await self.load_markets()
        market = self.market(symbol)
        request = {
            # 'from_id': 'b2a2d379-f9b6-418b-9414-cbf8330b20d1',  # string(uuid), fetchOrders(all orders) only
            # 'page': 0,  # different pagination in fetchOpenOrders and fetchClosedOrders
            # 'limit': 50,  # optional, max = default = 50
            'symbol': market['id'],  # required
        }
        if limit is not None:
            request['limit'] = limit  # max = default = 50
        method = 'tradePostOrderList' + type
        response = await getattr(self, method)(self.extend(request, params))
        #
        # fetchOrders, fetchClosedOrders
        #
        #     [{      hex_id: "5c192784330fe51149f556bb",
        #             order_id: "5e46e1b1-93d5-4656-9b43-a5635b08eae9",
        #           account_id: "a0c20128-b9e0-484e-9bc8-b8bb86340e5b",
        #         order_symbol: "COSS_ETH",
        #           order_side: "BUY",
        #               status: "filled",
        #           createTime:  1545152388019,
        #                 type: "limit",
        #         timeMatching:  0,
        #          order_price: "0.00065900",
        #           order_size: "10",
        #             executed: "10",
        #           stop_price: "0.00000000",
        #                  avg: "0.00065900",
        #                total: "0.00659000 ETH"                        }  ]
        #
        # fetchOpenOrders
        #
        #     {
        #         "total": 2,
        #         "list": [
        #             {
        #                 "order_id": "9e5ae4dd-3369-401d-81f5-dff985e1c4ty",
        #                 "account_id": "9e5ae4dd-3369-401d-81f5-dff985e1c4a6",
        #                 "order_symbol": "eth-btc",
        #                 "order_side": "BUY",
        #                 "status": "OPEN",
        #                 "createTime": 1538114348750,
        #                 "type": "limit",
        #                 "order_price": "0.12345678",
        #                 "order_size": "10.12345678",
        #                 "executed": "0",
        #                 "stop_price": "02.12345678",
        #                 "avg": "1.12345678",
        #                 "total": "2.12345678"
        #             }
        #         ]
        #     }
        #
        # the following code is to handle the above difference in response formats
        orders = None
        if isinstance(response, list):
            orders = response
        else:
            orders = self.safe_value(response, 'list', [])
        return self.parse_orders(orders, market, since, limit)

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

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

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

    async def fetch_order(self, id, symbol=None, params={}):
        await self.load_markets()
        request = {
            'order_id': id,
        }
        response = await self.tradePostOrderDetails(self.extend(request, params))
        return self.parse_order(response)

    async def fetch_order_trades(self, id, symbol=None, since=None, limit=None, params={}):
        await self.load_markets()
        market = None
        if symbol is not None:
            market = self.market(symbol)
        request = {
            'order_id': id,
        }
        response = await self.tradePostOrderTradeDetail(self.extend(request, params))
        #
        #     [{        hex_id:  null,
        #                 symbol: "COSS_ETH",
        #               order_id: "ad6f6b47-3def-4add-a5d5-2549a9df1593",
        #             order_side: "BUY",
        #                  price: "0.00065900",
        #               quantity: "10",
        #                    fee: "0.00700000 COSS",
        #         additional_fee: "0.00000461 ETH",
        #                  total: "0.00659000 ETH",
        #              timestamp:  1545152356075                          }]
        #
        return self.parse_trades(response, market, since, limit)

    def parse_order_status(self, status):
        if status is None:
            return status
        statuses = {
            'OPEN': 'open',
            'CANCELLED': 'canceled',
            'FILLED': 'closed',
            'PARTIAL_FILL': 'closed',
            'CANCELLING': 'open',
        }
        return self.safe_string(statuses, status.upper(), status)

    def parse_order(self, order, market=None):
        #
        #       {      hex_id: "5c192784330fe51149f556bb",  # missing in fetchOpenOrders
        #             order_id: "5e46e1b1-93d5-4656-9b43-a5635b08eae9",
        #           account_id: "a0c20128-b9e0-484e-9bc8-b8bb86340e5b",
        #         order_symbol: "COSS_ETH",  # coss-eth in docs
        #           order_side: "BUY",
        #               status: "filled",
        #           createTime:  1545152388019,
        #                 type: "limit",
        #         timeMatching:  0,  # missing in fetchOpenOrders
        #          order_price: "0.00065900",
        #           order_size: "10",
        #             executed: "10",
        #           stop_price: "0.00000000",
        #                  avg: "0.00065900",
        #                total: "0.00659000 ETH"                        }
        #
        id = self.safe_string(order, 'order_id')
        marketId = self.safe_string(order, 'order_symbol')
        if marketId is not None:
            marketId = marketId.replace('-', '_')
        symbol = self.safe_symbol(marketId, market, '_')
        timestamp = self.safe_integer(order, 'createTime')
        status = self.parse_order_status(self.safe_string(order, 'status'))
        price = self.safe_float(order, 'order_price')
        filled = self.safe_float(order, 'executed')
        type = self.safe_string(order, 'type')
        amount = self.safe_float(order, 'order_size')
        remaining = None
        if amount is not None:
            if filled is not None:
                remaining = amount - filled
        average = self.safe_float(order, 'avg')
        side = self.safe_string_lower(order, 'order_side')
        cost = self.safe_float(order, 'total')
        fee = None
        trades = None
        return {
            'info': order,
            'id': id,
            'clientOrderId': None,
            'timestamp': timestamp,
            'datetime': self.iso8601(timestamp),
            'lastTradeTimestamp': None,
            'symbol': symbol,
            'type': type,
            'side': side,
            'price': price,
            'amount': amount,
            'cost': cost,
            'average': average,
            'filled': filled,
            'remaining': remaining,
            'status': status,
            'fee': fee,
            'trades': trades,
        }

    async def create_order(self, symbol, type, side, amount, price=None, params={}):
        await self.load_markets()
        market = self.market(symbol)
        request = {
            'order_symbol': market['id'],
            'order_size': self.amount_to_precision(symbol, amount),
            'order_side': side.upper(),
            'type': type,
        }
        if price is not None:
            request['order_price'] = self.price_to_precision(symbol, price)
        response = await self.tradePostOrderAdd(self.extend(request, params))
        #
        #     {
        #         "order_id": "9e5ae4dd-3369-401d-81f5-dff985e1c4ty",
        #         "account_id": "9e5ae4dd-3369-401d-81f5-dff985e1c4a6",
        #         "order_symbol": "eth-btc",
        #         "order_side": "BUY",
        #         "status": "OPEN",
        #         "createTime": 1538114348750,
        #         "type": "limit",
        #         "order_price": "0.12345678",
        #         "order_size": "10.12345678",
        #         "executed": "0",
        #         "stop_price": "02.12345678",
        #         "avg": "1.12345678",
        #         "total": "2.12345678"
        #     }
        #
        return self.parse_order(response, market)

    async def cancel_order(self, id, symbol=None, params={}):
        if symbol is None:
            raise ArgumentsRequired(self.id + ' cancelOrder requires a symbol argument')
        await self.load_markets()
        market = self.market(symbol)
        request = {
            'order_id': id,
            'order_symbol': market['id'],
        }
        response = await self.tradeDeleteOrderCancel(self.extend(request, params))
        #
        #     {order_symbol: "COSS_ETH",
        #           order_id: "30f2d698-39a0-4b9f-a3a6-a179542373bd",
        #         order_size:  0,
        #         account_id: "a0c20128-b9e0-484e-9bc8-b8bb86340e5b",
        #          timestamp:  1545202728814,
        #         recvWindow:  null                                   }
        #
        return self.parse_order(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
        if api == 'trade':
            self.check_required_credentials()
            timestamp = self.nonce()
            query = self.extend({
                'timestamp': timestamp,  # required(int64)
                # 'recvWindow': 10000,  # optional(int32)
            }, params)
            request = None
            if method == 'GET':
                request = self.urlencode(query)
                url += '?' + request
            else:
                request = self.json(query)
                body = request
            headers = {
                'Signature': self.hmac(self.encode(request), self.encode(self.secret)),
                'Authorization': self.apiKey,
                'X-Requested-With': 'XMLHttpRequest',
            }
        else:
            if params:
                url += '?' + self.urlencode(params)
        return {'url': url, 'method': method, 'body': body, 'headers': headers}
