# -*- 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
from ccxt.base.errors import ExchangeError
from ccxt.base.errors import BadRequest
from ccxt.base.errors import InsufficientFunds
from ccxt.base.errors import InvalidOrder
from ccxt.base.errors import DuplicateOrderId
from ccxt.base.errors import NotSupported
from ccxt.base.decimal_to_precision import TICK_SIZE
from ccxt.base.precise import Precise


class lykke(Exchange):

    def describe(self):
        return self.deep_extend(super(lykke, self).describe(), {
            'id': 'lykke',
            'name': 'Lykke',
            'countries': ['UK'],
            'version': '2',
            # 300 requests per minute per method => 60000ms / 300 = 200(/api/orders/*)
            # 120 requests per minute per method =>( 60000ms / rateLimit ) / 120 = cost = 2.5(/api/*)
            'rateLimit': 200,  # TODO: optim\ize https://lykkecity.github.io/Trading-API/#request-rate-limits
            'has': {
                'CORS': None,
                'spot': True,
                'margin': False,
                'swap': False,
                'future': False,
                'option': False,
                'cancelAllOrders': True,
                'cancelOrder': True,
                'createOrder': True,
                'createStopLimitOrder': False,
                'createStopMarketOrder': False,
                'createStopOrder': False,
                'editOrder': False,
                'fetchBalance': True,
                'fetchBorrowRate': False,
                'fetchBorrowRateHistories': False,
                'fetchBorrowRateHistory': False,
                'fetchBorrowRates': False,
                'fetchClosedOrders': True,
                'fetchCurrencies': True,
                'fetchDepositAddress': True,
                'fetchDeposits': False,
                'fetchFundingHistory': False,
                'fetchFundingRate': False,
                'fetchFundingRateHistory': False,
                'fetchFundingRates': False,
                'fetchIndexOHLCV': False,
                'fetchMarginMode': False,
                'fetchMarkets': True,
                'fetchMarkOHLCV': False,
                'fetchMyTrades': True,
                'fetchOHLCV': 'emulated',
                'fetchOpenInterestHistory': False,
                'fetchOpenOrders': True,
                'fetchOrder': True,
                'fetchOrderBook': True,
                'fetchOrders': False,
                'fetchOrderTrades': False,
                'fetchPositionMode': False,
                'fetchPositions': False,
                'fetchPremiumIndexOHLCV': False,
                'fetchTicker': True,
                'fetchTickers': True,
                'fetchTime': False,
                'fetchTrades': True,
                'fetchTradingFee': False,
                'fetchTradingFees': False,
                'fetchTransactionFees': False,
                'fetchTransactions': True,
                'fetchWithdrawals': False,
                'setLeverage': False,
                'setMarginMode': False,
                'withdraw': True,
            },
            'requiredCredentials': {
                'apiKey': True,
                'secret': False,
            },
            'urls': {
                'logo': 'https://user-images.githubusercontent.com/1294454/155840500-1ea4fdf0-47c0-4daa-9597-c6c1cd51b9ec.jpg',
                'api': {
                    'public': 'https://hft-apiv2.lykke.com/api',
                    'private': 'https://hft-apiv2.lykke.com/api',
                },
                'www': 'https://www.lykke.com',
                'doc': [
                    'https://hft-apiv2.lykke.com/swagger/ui/index.html',
                    'https://lykkecity.github.io/Trading-API',
                ],
                'fees': 'https://support.lykke.com/hc/en-us/articles/115002141125-What-are-the-fees-and-charges-',  # zero fee
            },
            'api': {
                'public': {
                    'get': {
                        'assetpairs': 2.5,
                        'assetpairs/{id}': 2.5,
                        'assets': 2.5,
                        'assets/{id}': 2.5,
                        'isalive': 2.5,
                        'orderbooks': 2.5,
                        'tickers': 2.5,
                        'prices': 2.5,
                        'trades/public/{assetPairId}': 2.5,
                    },
                },
                'private': {
                    'get': {
                        'balance': 2.5,
                        'trades': 2.5,
                        'trades/order/{orderId}': 2.5,
                        'orders/active': 1,
                        'orders/closed': 1,
                        'orders/{orderId}': 1,
                        'operations': 2.5,
                        'operations/deposits/addresses': 2.5,
                        'operations/deposits/addresses/{assetId}': 2.5,
                    },
                    'post': {
                        'orders/limit': 1,
                        'orders/market': 1,
                        'orders/bulk': 1,
                        'operations/withdrawals': 2.5,
                        'operations/deposits/addresses': 2.5,
                    },
                    'delete': {
                        'orders': 1,
                        'orders/{orderId}': 1,
                    },
                },
            },
            'fees': {
                'trading': {
                    'tierBased': False,
                    'percentage': True,
                    'maker': 0,  # https://support.lykke.com/hc/en-us/articles/115002141125-What-are-the-fees-and-min-amounts-
                    'taker': 0,
                },
            },
            'precisionMode': TICK_SIZE,
            'exceptions': {
                'exact': {
                    '1001': ExchangeError,
                    '1100': ExchangeError,
                    '1101': ExchangeError,
                    '2000': BadRequest,
                    '2001': InsufficientFunds,
                    '2202': DuplicateOrderId,
                    '2003': ExchangeError,
                    '2004': NotSupported,
                    '2005': ExchangeError,
                    '2006': InsufficientFunds,
                    '2007': InsufficientFunds,
                    '2008': InsufficientFunds,
                    '2009': ExchangeError,
                    '2010': InsufficientFunds,
                    '2011': InvalidOrder,
                    '2012': InvalidOrder,
                    '2013': InvalidOrder,
                    '2014': InvalidOrder,
                    '2015': InvalidOrder,
                    '2016': InvalidOrder,
                    '2017': InvalidOrder,
                    '2018': InvalidOrder,
                    '2019': InvalidOrder,
                    '2020': InvalidOrder,
                    '2021': InvalidOrder,
                    '2022': InvalidOrder,
                    '2023': ExchangeError,
                },
                'broad': {},
            },
            'commonCurrencies': {
            },
        })

    async def fetch_currencies(self, params={}):
        """
        fetches all available currencies on an exchange
        :param dict params: extra parameters specific to the lykke api endpoint
        :returns dict: an associative dictionary of currencies
        """
        response = await self.publicGetAssets(params)
        currencies = self.safe_value(response, 'payload', [])
        #
        #     {
        #         "payload":[
        #             {
        #                 "assetId":"115a60c2-0da1-40f9-a7f2-41da723b9074",
        #                 "name":"Monaco Token",
        #                 "symbol":"MCO",
        #                 "accuracy":6,
        #                 "multiplierPower":8,
        #                 "assetAddress":"",
        #                 "blockchainIntegrationLayerId":"",
        #                 "blockchain":"ethereum",
        #                 "type":"erc20Token",
        #                 "isTradable":true,
        #                 "isTrusted":true,
        #                 "kycNeeded":false,
        #                 "blockchainWithdrawal":true,
        #                 "cashoutMinimalAmount":0.1,
        #                 "lowVolumeAmount":null,
        #                 "lykkeEntityId":"LYKKE NL",
        #                 "siriusAssetId":0,
        #                 "siriusBlockchainId":null,
        #                 "blockchainIntegrationType":"none",
        #                 "blockchainDepositEnabled":false,
        #                 "isDisabled":false
        #             }
        #         ],
        #         "error":null
        #     }
        #
        result = {}
        for i in range(0, len(currencies)):
            currency = currencies[i]
            id = self.safe_string(currency, 'assetId')
            code = self.safe_string(currency, 'symbol')
            name = self.safe_string(currency, 'name')
            type = self.safe_string(currency, 'type')
            deposit = self.safe_value(currency, 'blockchainDepositEnabled')
            withdraw = self.safe_value(currency, 'blockchainWithdrawal')
            isDisabled = self.safe_value(currency, 'isDisabled')
            active = not isDisabled
            result[code] = {
                'id': id,
                'code': code,
                'info': currency,
                'type': type,
                'name': name,
                'active': active,
                'deposit': deposit,
                'withdraw': withdraw,
                'fee': None,
                'precision': self.parse_number(self.parse_precision(self.safe_string(currency, 'accuracy'))),
                'limits': {
                    'withdraw': {
                        'min': self.safe_value(currency, 'cashoutMinimalAmount'),
                        'max': None,
                    },
                    'amount': {
                        'min': self.safe_value(currency, 'lowVolumeAmount'),
                        'max': None,
                    },
                },
            }
        return result

    async def fetch_markets(self, params={}):
        """
        retrieves data on all markets for lykke
        :param dict params: extra parameters specific to the exchange api endpoint
        :returns [dict]: an array of objects representing market data
        """
        response = await self.publicGetAssetpairs(params)
        markets = self.safe_value(response, 'payload', [])
        #
        #     {
        #         "payload":[
        #             {
        #                 "assetPairId":"AAVEBTC",
        #                 "baseAssetId":"c9e55548-dae5-44fc-bebd-e72249cb19f3",
        #                 "quoteAssetId":"BTC",
        #                 "name":"AAVE/BTC",
        #                 "priceAccuracy":6,
        #                 "baseAssetAccuracy":6,
        #                 "quoteAssetAccuracy":8,
        #                 "minVolume":0.001,
        #                 "minOppositeVolume":0.0001
        #             }
        #         ],
        #         "error":null
        #     }
        #
        result = []
        for i in range(0, len(markets)):
            market = markets[i]
            id = self.safe_string(market, 'assetPairId')
            name = self.safe_string(market, 'name')
            baseAssetId = self.safe_string(market, 'baseAssetId')
            quoteAssetId = self.safe_string(market, 'quoteAssetId')
            baseId, quoteId = name.split('/')
            base = self.safe_currency_code(baseId)
            quote = self.safe_currency_code(quoteId)
            symbol = base + '/' + quote
            result.append({
                'id': id,
                'symbol': symbol,
                'base': base,
                'quote': quote,
                'baseId': baseAssetId,
                'quoteId': quoteAssetId,
                'settle': None,
                'settleId': None,
                'type': 'spot',
                'spot': True,
                'margin': False,
                'swap': False,
                'future': False,
                'option': False,
                'contract': False,
                'active': True,
                'info': market,
                'linear': None,
                'inverse': None,
                'contractSize': None,
                'expiry': None,
                'expiryDatetime': None,
                'strike': None,
                'optionType': None,
                'precision': {
                    'amount': self.parse_number(self.parse_precision(self.safe_string(market, 'baseAssetAccuracy'))),
                    'price': self.parse_number(self.parse_precision(self.safe_string(market, 'priceAccuracy'))),
                },
                'limits': {
                    'amount': {
                        'min': self.safe_number(market, 'minVolume'),
                        'max': None,
                    },
                    'price': {
                        'min': None,
                        'max': None,
                    },
                    'cost': {
                        'min': self.safe_number(market, 'minOppositeVolume'),
                        'max': None,
                    },
                    'leverage': {
                        'min': None,
                        'max': None,
                    },
                },
            })
        return result

    def parse_ticker(self, ticker, market=None):
        #
        # fetchTickers
        #
        #     publicGetTickers
        #
        #     {
        #         "assetPairId":"BTCUSD",
        #         "volumeBase":2.56905016,
        #         "volumeQuote":95653.8730,
        #         "priceChange":-0.0367945778541765034194707584,
        #         "lastPrice":36840.0,
        #         "high":38371.645,
        #         "low":35903.356,
        #         "timestamp":1643295740729
        #     }
        #
        # fetchTicker
        #
        #     publicGetTickers
        #
        #     {
        #         "assetPairId":"BTCUSD",
        #         "volumeBase":2.56905016,
        #         "volumeQuote":95653.8730,
        #         "priceChange":-0.0367945778541765034194707584,
        #         "lastPrice":36840.0,
        #         "high":38371.645,
        #         "low":35903.356,
        #         "timestamp":1643295740729
        #     }
        #
        #     publicGetPrices
        #
        #     {
        #         "assetPairId":"BTCUSD",
        #         "bid":36181.521,
        #         "ask":36244.492,
        #         "timestamp":1643305510990
        #     }
        #
        timestamp = None  # temporary bug in lykke api, returns unrealistic numbers
        marketId = self.safe_string(ticker, 'assetPairId')
        market = self.safe_market(marketId, market)
        close = self.safe_string(ticker, 'lastPrice')
        return self.safe_ticker({
            'symbol': self.safe_string(market, 'symbol'),
            'timestamp': timestamp,
            'datetime': self.iso8601(timestamp),
            'high': self.safe_string(ticker, 'high'),
            'low': self.safe_string(ticker, 'low'),
            'bid': self.safe_string(ticker, 'bid'),
            'bidVolume': None,
            'ask': self.safe_string(ticker, 'ask'),
            'askVolume': None,
            'vwap': None,
            'open': None,
            'close': close,
            'last': close,
            'previousClose': None,
            'change': self.safe_string(ticker, 'priceChange'),
            'percentage': None,
            'average': None,
            'baseVolume': self.safe_string(ticker, 'volumeBase'),
            'quoteVolume': self.safe_string(ticker, 'volumeQuote'),
            'info': ticker,
        }, market)

    async def fetch_ticker(self, symbol, params={}):
        """
        fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
        :param str symbol: unified symbol of the market to fetch the ticker for
        :param dict params: extra parameters specific to the lykke api endpoint
        :returns dict: a `ticker structure <https://docs.ccxt.com/en/latest/manual.html#ticker-structure>`
        """
        await self.load_markets()
        market = self.market(symbol)
        request = {
            'assetPairIds': market['id'],
        }
        # publicGetTickers or publicGetPrices
        method = self.safe_string(self.options, 'fetchTickerMethod', 'publicGetTickers')
        response = await getattr(self, method)(self.extend(request, params))
        ticker = self.safe_value(response, 'payload', [])
        #
        # publicGetTickers
        #
        #     {
        #         "payload":[
        #             {
        #                 "assetPairId":"BTCUSD",
        #                 "volumeBase":0.78056880,
        #                 "volumeQuote":29782.5169,
        #                 "priceChange":0.0436602362590968619931324699,
        #                 "lastPrice":38626.885,
        #                 "high":38742.896,
        #                 "low":36872.498,
        #                 "timestamp":1643687822840
        #             }
        #         ],
        #         "error":null
        #     }
        #
        # publicGetPrices
        #
        #     {
        #         "payload":[
        #             {
        #                 "assetPairId":"BTCUSD",
        #                 "bid":38597.936,
        #                 "ask":38640.311,
        #                 "timestamp":1643688350847
        #             }
        #         ],
        #         "error":null
        #     }
        #
        return self.parse_ticker(self.safe_value(ticker, 0, {}), market)

    async def fetch_tickers(self, symbols=None, params={}):
        """
        fetches price tickers for multiple markets, statistical calculations with the information calculated over the past 24 hours each market
        :param [str]|None symbols: unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
        :param dict params: extra parameters specific to the lykke api endpoint
        :returns dict: a dictionary of `ticker structures <https://docs.ccxt.com/en/latest/manual.html#ticker-structure>`
        """
        await self.load_markets()
        response = await self.publicGetTickers(params)
        tickers = self.safe_value(response, 'payload', [])
        #
        #     {
        #         "payload":[
        #             {
        #                 "assetPairId":"BTCUSD",
        #                 "volumeBase":0.78056880,
        #                 "volumeQuote":29782.5169,
        #                 "priceChange":0.0436602362590968619931324699,
        #                 "lastPrice":38626.885,
        #                 "high":38742.896,
        #                 "low":36872.498,
        #                 "timestamp":1643687822840
        #             }
        #         ],
        #         "error":null
        #     }
        #
        return self.parse_tickers(tickers, symbols)

    async def fetch_order_book(self, symbol, limit=None, params={}):
        """
        fetches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
        :param str symbol: unified symbol of the market to fetch the order book for
        :param int|None limit: the maximum amount of order book entries to return
        :param dict params: extra parameters specific to the lykke api endpoint
        :returns dict: A dictionary of `order book structures <https://docs.ccxt.com/en/latest/manual.html#order-book-structure>` indexed by market symbols
        """
        await self.load_markets()
        market = self.market(symbol)
        request = {
            'assetPairId': market['id'],
        }
        if limit is not None:
            request['depth'] = limit  # default 0
        response = await self.publicGetOrderbooks(self.extend(request, params))
        payload = self.safe_value(response, 'payload', [])
        #
        #     {
        #         "payload":[
        #             {
        #                 assetPairId: 'BTCUSD',
        #                 timestamp: '1643298038203',
        #                 bids: [
        #                     {
        #                         "v":0.59034382,
        #                         "p":36665.329
        #                     }
        #                 ],
        #                 asks: [
        #                     {
        #                         "v":-0.003,
        #                         "p":36729.686
        #                     }
        #                 ]
        #             }
        #         ],
        #         "error":null
        #     }
        #
        orderbook = self.safe_value(payload, 0, {})
        timestamp = self.safe_integer(orderbook, 'timestamp')
        return self.parse_order_book(orderbook, market['symbol'], timestamp, 'bids', 'asks', 'p', 'v')

    def parse_trade(self, trade, market):
        #
        #  public fetchTrades
        #
        #     {
        #         "id":"71df1f0c-be4e-4d45-b809-c108fad5f2a8",
        #         "assetPairId":"BTCUSD",
        #         "timestamp":1643345958414,
        #         "volume":0.00010996,
        #         "price":37205.723,
        #         "side":"buy"
        #      }
        #
        #  private fetchMyTrades
        #         {
        #             "id":"813a3ffa-1c4b-45cb-b13f-1c077ea2748b",
        #             "timestamp":1644155923357,
        #             "assetPairId":"BCHEUR",
        #             "orderId":"1b367978-7e4f-454b-b870-64040d484443",
        #             "role":"Taker",
        #             "side":"sell",
        #             "price":280.569,
        #             "baseVolume":0.01,
        #             "quoteVolume":2.8056,
        #             "baseAssetId":"2a34d6a6-5839-40e5-836f-c1178fa09b89",
        #             "quoteAssetId":"EUR",
        #             "fee":null
        #         }
        #
        marketId = self.safe_string(trade, 'assetPairId')
        market = self.safe_market(marketId, market)
        symbol = market['symbol']
        id = self.safe_string_2(trade, 'id', 'id')
        orderId = self.safe_string(trade, 'orderId')
        timestamp = self.safe_integer(trade, 'timestamp')
        price = self.safe_string_2(trade, 'price', 'price')
        amount = self.safe_string_2(trade, 'volume', 'amount')
        if amount is None:
            amount = self.safe_string_2(trade, 'baseVolume', 'amount')
        side = self.safe_string_lower(trade, 'side')
        return self.safe_trade({
            'id': id,
            'info': trade,
            'timestamp': timestamp,
            'datetime': self.iso8601(timestamp),
            'symbol': symbol,
            'type': None,
            'order': orderId,
            'side': side,
            'takerOrMaker': None,
            'price': price,
            'amount': amount,
            'cost': None,
            'fee': None,
        }, market)

    async def fetch_trades(self, symbol, since=None, limit=None, params={}):
        """
        get the list of most recent trades for a particular symbol
        :param str symbol: unified symbol of the market to fetch trades for
        :param int|None since: timestamp in ms of the earliest trade to fetch
        :param int|None limit: the maximum amount of trades to fetch
        :param dict params: extra parameters specific to the lykke api endpoint
        :returns [dict]: a list of `trade structures <https://docs.ccxt.com/en/latest/manual.html?#public-trades>`
        """
        await self.load_markets()
        market = self.market(symbol)
        request = {
            'assetPairId': market['id'],
            # 'offset': 0,
        }
        if limit is not None:
            request['take'] = limit
        response = await self.publicGetTradesPublicAssetPairId(self.extend(request, params))
        result = self.safe_value(response, 'payload', [])
        #
        #     {
        #         "payload":[
        #             {
        #                 "id":"71df1f0c-be4e-4d45-b809-c108fad5f2a8",
        #                 "assetPairId":"BTCUSD",
        #                 "timestamp":1643345958414,
        #                 "volume":0.00010996,
        #                 "price":37205.723,
        #                 "side":"buy"
        #             }
        #         ],
        #         "error":null
        #     }
        #
        return self.parse_trades(result, market, since, limit)

    def parse_balance(self, response):
        #
        #     [
        #         {
        #             "assetId":"2a34d6a6-5839-40e5-836f-c1178fa09b89",
        #             "available":0.1,
        #             "reserved":0.0,
        #             "timestamp":1644146723620
        #         }
        #     ]
        #
        result = {'info': response}
        for i in range(0, len(response)):
            balance = response[i]
            currencyId = self.safe_string(balance, 'assetId')
            code = self.safe_currency_code(currencyId)
            account = self.account()
            free = self.safe_string(balance, 'available')
            used = self.safe_string(balance, 'reserved')
            account['free'] = free
            account['used'] = used
            result[code] = account
        return self.safe_balance(result)

    async def fetch_balance(self, params={}):
        """
        query for balance and get the amount of funds available for trading or funds locked in orders
        :param dict params: extra parameters specific to the lykke api endpoint
        :returns dict: a `balance structure <https://docs.ccxt.com/en/latest/manual.html?#balance-structure>`
        """
        await self.load_markets()
        response = await self.privateGetBalance(params)
        payload = self.safe_value(response, 'payload', [])
        #
        #     {
        #         "payload":[
        #             {
        #                 "assetId":"2a34d6a6-5839-40e5-836f-c1178fa09b89",
        #                 "available":0.1,
        #                 "reserved":0.0,
        #                 "timestamp":1644146723620
        #             }
        #         ],
        #         "error":null
        #     }
        #
        return self.parse_balance(payload)

    def parse_order_status(self, status):
        statuses = {
            'Open': 'open',
            'Pending': 'open',
            'InOrderBook': 'open',
            'Processing': 'open',
            'Matched': 'closed',
            'Cancelled': 'canceled',
            'Rejected': 'rejected',
            'Replaced': 'canceled',
            'Placed': 'open',
        }
        return self.safe_string(statuses, status, status)

    def parse_order(self, order, market=None):
        #
        #     {
        #         "id":"1b367978-7e4f-454b-b870-64040d484443",
        #         "timestamp":1644155923357,
        #         "lastTradeTimestamp":1644155923357,
        #         "status":"Matched",
        #         "assetPairId":"BCHEUR",
        #         "type":"Market",
        #         "side":"Sell",
        #         "price":280.569,
        #         "volume":0.01,
        #         "filledVolume":0.01,
        #         "remainingVolume":0.0,
        #         "cost":2.80569
        #     }
        #
        id = self.safe_string(order, 'id')
        status = self.parse_order_status(self.safe_string(order, 'status'))
        marketId = self.safe_string(order, 'assetPairId')
        symbol = self.safe_symbol(marketId, market)
        type = self.safe_string_lower(order, 'type')
        lastTradeTimestamp = self.safe_integer(order, 'lastTradeTimestamp')
        timestamp = self.safe_integer(order, 'timestamp')
        price = self.safe_string(order, 'price')
        side = self.safe_string_lower(order, 'side')
        amount = self.safe_string(order, 'volume')
        remaining = self.safe_string(order, 'remainingVolume')
        filled = self.safe_string(order, 'filledVolume')
        cost = self.safe_string(order, 'cost')
        return self.safe_order({
            'info': order,
            'id': id,
            'clientOrderId': None,
            'timestamp': timestamp,
            'datetime': self.iso8601(timestamp),
            'lastTradeTimestamp': lastTradeTimestamp,
            'symbol': symbol,
            'type': type,
            'timeInForce': None,
            'postOnly': None,
            'side': side,
            'price': price,
            'stopPrice': None,
            'triggerPrice': None,
            'amount': amount,
            'cost': cost,
            'average': None,
            'filled': filled,
            'remaining': remaining,
            'status': status,
            'fee': None,
            'trades': None,
        }, market)

    async def create_order(self, symbol, type, side, amount, price=None, params={}):
        """
        create a trade order
        :param str symbol: unified symbol of the market to create an order in
        :param str type: 'market' or 'limit'
        :param str side: 'buy' or 'sell'
        :param float amount: how much of currency you want to trade in units of base currency
        :param float|None price: the price at which the order is to be fullfilled, in units of the quote currency, ignored in market orders
        :param dict params: extra parameters specific to the lykke api endpoint
        :returns dict: an `order structure <https://docs.ccxt.com/en/latest/manual.html#order-structure>`
        """
        await self.load_markets()
        market = self.market(symbol)
        query = {
            'assetPairId': market['id'],
            'side': self.capitalize(side),
            'volume': float(self.amount_to_precision(market['symbol'], amount)),
        }
        if type == 'limit':
            query['price'] = float(self.price_to_precision(market['symbol'], price))
        method = 'privatePostOrders' + self.capitalize(type)
        result = await getattr(self, method)(self.extend(query, params))
        #
        # market
        #
        #         {
        #             "payload":{
        #                 "orderId":"2b98ec26-8410-49b6-9f37-1fb2150e2299",
        #                 "price":280.699
        #             },
        #             "error":null
        #         }
        #
        # limit
        #
        #         {
        #             "payload":{
        #                 "orderId":"27be8802-30be-40ca-bf40-ec886b309c5b"
        #             },
        #             "error":null
        #         }
        #
        payload = self.safe_value(result, 'payload')
        id = self.safe_string(payload, 'orderId')
        if type == 'market':
            price = self.safe_number(payload, 'price')
        return {
            'id': id,
            'info': result,
            'clientOrderId': None,
            'timestamp': None,
            'datetime': None,
            'lastTradeTimestamp': None,
            'symbol': market['symbol'],
            'type': type,
            'side': side,
            'price': price,
            'amount': amount,
            'cost': None,
            'average': None,
            'filled': None,
            'remaining': None,
            'status': None,
            'fee': None,
            'trades': None,
        }

    async def cancel_order(self, id, symbol=None, params={}):
        """
        cancels an open order
        :param str id: order id
        :param str|None symbol: unified symbol of the market the order was made in
        :param dict params: extra parameters specific to the lykke api endpoint
        :returns dict: An `order structure <https://docs.ccxt.com/en/latest/manual.html#order-structure>`
        """
        request = {
            'orderId': id,
        }
        #
        #     {
        #         "payload":null,
        #         "error":null
        #     }
        #
        return await self.privateDeleteOrdersOrderId(self.extend(request, params))

    async def cancel_all_orders(self, symbol=None, params={}):
        """
        cancel all open orders
        :param str|None symbol: unified market symbol, only orders in the market of self symbol are cancelled when symbol is not None
        :param dict params: extra parameters specific to the lykke api endpoint
        :returns [dict]: a list of `order structures <https://docs.ccxt.com/en/latest/manual.html#order-structure>`
        """
        await self.load_markets()
        request = {
            # 'side': 'Buy',
        }
        market = None
        if symbol is not None:
            market = self.market(symbol)
            request['assetPairId'] = market['id']
        #
        #     {
        #         "payload":null,
        #         "error":null
        #     }
        #
        return await self.privateDeleteOrders(self.extend(request, params))

    async def fetch_order(self, id, symbol=None, params={}):
        """
        fetches information on an order made by the user
        :param str|None symbol: not used by lykke fetchOrder
        :param dict params: extra parameters specific to the lykke api endpoint
        :returns dict: An `order structure <https://docs.ccxt.com/en/latest/manual.html#order-structure>`
        """
        await self.load_markets()
        request = {
            'orderId': id,
        }
        response = await self.privateGetOrdersOrderId(self.extend(request, params))
        payload = self.safe_value(response, 'payload')
        #
        #     {
        #         "payload":{
        #             "id":"1b367978-7e4f-454b-b870-64040d484443",
        #             "timestamp":1644155923357,
        #             "lastTradeTimestamp":1644155923357,
        #             "status":"Matched",
        #             "assetPairId":"BCHEUR",
        #             "type":"Market",
        #             "side":"Sell",
        #             "price":280.569,
        #             "volume":0.01,
        #             "filledVolume":0.01,
        #             "remainingVolume":0.0,
        #             "cost":2.80569
        #         },
        #         "error":null
        #     }
        #
        return self.parse_order(payload)

    async def fetch_open_orders(self, symbol=None, since=None, limit=None, params={}):
        """
        fetch all unfilled currently open orders
        :param str|None symbol: unified market symbol
        :param int|None since: the earliest time in ms to fetch open orders for
        :param int|None limit: the maximum number of  open orders structures to retrieve
        :param dict params: extra parameters specific to the lykke api endpoint
        :returns [dict]: a list of `order structures <https://docs.ccxt.com/en/latest/manual.html#order-structure>`
        """
        await self.load_markets()
        market = None
        if symbol is not None:
            market = self.market(symbol)
        request = {
            # 'offset': 0,
            # 'take': 1,
        }
        if limit is not None:
            request['take'] = limit
        response = await self.privateGetOrdersActive(self.extend(request, params))
        payload = self.safe_value(response, 'payload')
        #
        #     {
        #         "payload":[
        #             {
        #                 "id":"b26f58f5-8542-4b4c-9815-91562b523cc3",
        #                 "timestamp":1644157177155,
        #                 "lastTradeTimestamp":null,
        #                 "status":"Placed",
        #                 "assetPairId":"BCHEUR",
        #                 "type":"Limit",
        #                 "side":"Sell",
        #                 "price":666.666,
        #                 "volume":0.01,
        #                 "filledVolume":0.00,
        #                 "remainingVolume":0.01,
        #                 "cost":0.00000
        #             }
        #         ],
        #         "error":null
        #     }
        #
        return self.parse_orders(payload, market, since, limit)

    async def fetch_closed_orders(self, symbol=None, since=None, limit=None, params={}):
        """
        fetches information on multiple closed orders made by the user
        :param str|None symbol: unified market symbol of the market orders were made in
        :param int|None since: the earliest time in ms to fetch orders for
        :param int|None limit: the maximum number of  orde structures to retrieve
        :param dict params: extra parameters specific to the lykke api endpoint
        :returns [dict]: a list of `order structures <https://docs.ccxt.com/en/latest/manual.html#order-structure>`
        """
        await self.load_markets()
        market = None
        if symbol is not None:
            market = self.market(symbol)
        request = {
            # 'offset': 0,
            # 'take': 1,
        }
        if limit is not None:
            request['take'] = limit
        response = await self.privateGetOrdersClosed(self.extend(request, params))
        payload = self.safe_value(response, 'payload')
        #
        #     {
        #         "payload":[
        #             {
        #                 "id":"1b367978-7e4f-454b-b870-64040d484443",
        #                 "timestamp":1644155923357,
        #                 "lastTradeTimestamp":1644155923357,
        #                 "status":"Matched",
        #                 "assetPairId":"BCHEUR",
        #                 "type":"Market",
        #                 "side":"Sell",
        #                 "price":280.569,
        #                 "volume":0.01,
        #                 "filledVolume":0.01,
        #                 "remainingVolume":0.0,
        #                 "cost":2.80569
        #             }
        #         ],
        #         "error":null
        #     }
        #
        return self.parse_orders(payload, market, since, limit)

    async def fetch_my_trades(self, symbol=None, since=None, limit=None, params={}):
        """
        fetch all trades made by the user
        :param str|None symbol: unified market symbol
        :param int|None since: the earliest time in ms to fetch trades for
        :param int|None limit: the maximum number of trades structures to retrieve
        :param dict params: extra parameters specific to the lykke api endpoint
        :returns [dict]: a list of `trade structures <https://docs.ccxt.com/en/latest/manual.html#trade-structure>`
        """
        await self.load_markets()
        request = {
            # 'side': 'buy',
            # 'offset': 0,
            # 'take': 1,
            # 'to': 0,
        }
        market = None
        if limit is not None:
            request['take'] = limit  # How many maximum items have to be returned, max 1000 default 100.
        if symbol is not None:
            market = self.market(symbol)
            request['assetPairId'] = market['id']
        if since is not None:
            request['from'] = since
        response = await self.privateGetTrades(self.extend(request, params))
        payload = self.safe_value(response, 'payload')
        #
        #     {
        #         "payload":[
        #             {
        #                 "id":"813a3ffa-1c4b-45cb-b13f-1c077ea2748b",
        #                 "timestamp":1644155923357,
        #                 "assetPairId":"BCHEUR",
        #                 "orderId":"1b367978-7e4f-454b-b870-64040d484443",
        #                 "role":"Taker",
        #                 "side":"sell",
        #                 "price":280.569,
        #                 "baseVolume":0.01,
        #                 "quoteVolume":2.8056,
        #                 "baseAssetId":"2a34d6a6-5839-40e5-836f-c1178fa09b89",
        #                 "quoteAssetId":"EUR",
        #                 "fee":null
        #             }
        #         ],
        #         "error":null
        #     }
        #
        return self.parse_trades(payload, market, since, limit)

    def parse_bid_ask(self, bidask, priceKey=0, amountKey=1):
        price = self.safe_string(bidask, priceKey)
        amount = Precise.string_abs(self.safe_string(bidask, amountKey))
        return [self.parse_number(price), self.parse_number(amount)]

    async def fetch_deposit_address(self, code, params={}):
        """
        fetch the deposit address for a currency associated with self account
        :param str code: unified currency code
        :param dict params: extra parameters specific to the lykke api endpoint
        :returns dict: an `address structure <https://docs.ccxt.com/en/latest/manual.html#address-structure>`
        """
        await self.load_markets()
        currency = self.currency(code)
        request = {
            'assetId': self.safe_string(currency, 'id'),
        }
        response = await self.privateGetOperationsDepositsAddressesAssetId(self.extend(request, params))
        #
        #     {
        #         "assetId":"2a34d6a6-5839-40e5-836f-c1178fa09b89",
        #         "symbol":"BCH",
        #         "address":null,
        #         "baseAddress":null,
        #         "addressExtension":null,
        #         "state":"Active"
        #     }
        #
        address = self.safe_string(response, 'baseAddress')
        tag = self.safe_string(response, 'addressExtension')
        self.check_address(address)
        return {
            'currency': code,
            'address': address,
            'tag': tag,
            'network': None,
            'info': response,
        }

    def parse_transaction(self, transaction, currency=None):
        #
        # withdraw
        #     "3035b1ad-2005-4587-a986-1f7966be78e0"
        #
        # fetchTransactions
        #     {
        #         "operationId":"787201c8-f1cc-45c0-aec1-fa06eeea426b",
        #         "assetId":"2a34d6a6-5839-40e5-836f-c1178fa09b89",
        #         "totalVolume":0.1,
        #         "fee":0.0,
        #         "type":"deposit",
        #         "timestamp":1644146723620
        #     }
        #
        id = None
        assetId = None
        code = None
        amount = None
        fee = None
        type = None
        timestamp = None
        if isinstance(transaction, str):
            id = transaction
        else:
            id = self.safe_string(transaction, 'operationId')
            assetId = self.safe_string(transaction, 'assetId')
            code = self.safe_currency_code(assetId, currency)
            amount = self.safe_number(transaction, 'totalVolume')
            type = self.safe_string(transaction, 'type')
            timestamp = self.safe_integer(transaction, 'timestamp')
            feeCost = self.safe_number(transaction, 'fee')
            fee = {
                'currency': code,
                'cost': feeCost,
            }
        return {
            'info': transaction,
            'id': id,
            'txid': None,
            'timestamp': timestamp,
            'datetime': self.iso8601(timestamp),
            'network': None,
            'addressFrom': None,
            'address': None,
            'addressTo': None,
            'tagFrom': None,
            'tag': None,
            'tagTo': None,
            'type': type,
            'amount': amount,
            'currency': code,
            'status': None,
            'updated': None,
            'fee': fee,
        }

    async def fetch_transactions(self, code=None, since=None, limit=None, params={}):
        """
        fetch history of deposits and withdrawals
        :param str|None code: unified currency code for the currency of the transactions, default is None
        :param int|None since: timestamp in ms of the earliest transaction, default is None
        :param int|None limit: max number of transactions to return, default is None
        :param dict params: extra parameters specific to the lykke api endpoint
        :returns dict: a list of `transaction structure <https://docs.ccxt.com/en/latest/manual.html#transaction-structure>`
        """
        await self.load_markets()
        request = {
            # 'offset': 0,
            # 'take': 1,
        }
        if limit is not None:
            request['take'] = limit
        response = await self.privateGetOperations(self.extend(request, params))
        payload = self.safe_value(response, 'payload', [])
        #
        #     {
        #         "payload":[
        #             {
        #                 "operationId":"787201c8-f1cc-45c0-aec1-fa06eeea426b",
        #                 "assetId":"2a34d6a6-5839-40e5-836f-c1178fa09b89",
        #                 "totalVolume":0.1,
        #                 "fee":0.0,
        #                 "type":"deposit",
        #                 "timestamp":1644146723620
        #             }
        #         ],
        #         "error":null
        #     }
        #
        currency = None
        if code is not None:
            currency = self.currency(code)
        return self.parse_transactions(payload, currency, since, limit)

    async def withdraw(self, code, amount, address, tag=None, params={}):
        """
        make a withdrawal
        :param str code: unified currency code
        :param float amount: the amount to withdraw
        :param str address: the address to withdraw to
        :param str|None tag:
        :param dict params: extra parameters specific to the lykke api endpoint
        :returns dict: a `transaction structure <https://docs.ccxt.com/en/latest/manual.html#transaction-structure>`
        """
        await self.load_markets()
        self.check_address(address)
        currency = self.currency(code)
        request = {
            'assetId': currency['id'],
            'volume': float(self.currency_to_precision(code, amount)),
            'destinationAddress': address,
            # 'destinationAddressExtension': tag,
        }
        if tag is not None:
            request['destinationAddressExtension'] = tag
        response = await self.privatePostOperationsWithdrawals(self.extend(request, params))
        #
        #     "3035b1ad-2005-4587-a986-1f7966be78e0"
        #
        return self.parse_transaction(response, currency)

    def sign(self, path, api='public', method='GET', params={}, headers=None, body=None):
        url = self.urls['api'][api] + '/' + self.implode_params(path, params)
        query = self.omit(params, self.extract_params(path))
        headers = {
            'Accept': 'application/json',
            'Content-Type': 'application/json',
        }
        if api == 'public':
            if query:
                url += '?' + self.urlencode(query)
        elif api == 'private':
            if (method == 'GET') or (method == 'DELETE'):
                if query:
                    url += '?' + self.urlencode(query)
            self.check_required_credentials()
            headers['Authorization'] = 'Bearer ' + self.apiKey
            if method == 'POST':
                if params:
                    body = self.json(params)
            if path == 'operations/withdrawals':
                headers['X-Request-ID'] = self.uuid()
        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
        error = self.safe_value(response, 'error', {})
        errorCode = self.safe_string(error, 'code')
        if (errorCode is not None) and (errorCode != '0'):
            feedback = self.id + ' ' + body
            message = self.safe_string(error, 'message')
            self.throw_exactly_matched_exception(self.exceptions['exact'], errorCode, feedback)
            self.throw_broadly_matched_exception(self.exceptions['broad'], message, feedback)
            raise ExchangeError(feedback)
