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

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

from ccxt_zagrava.base.exchange import Exchange
from ccxt_zagrava.abstract.currencycom import ImplicitAPI
import hashlib
from ccxt_zagrava.base.types import Account, Balances, Currencies, Currency, Int, Leverage, Market, Num, Order, OrderBook, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, TradingFees, Transaction
from typing import List
from ccxt_zagrava.base.errors import ExchangeError
from ccxt_zagrava.base.errors import AuthenticationError
from ccxt_zagrava.base.errors import ArgumentsRequired
from ccxt_zagrava.base.errors import BadRequest
from ccxt_zagrava.base.errors import BadSymbol
from ccxt_zagrava.base.errors import InsufficientFunds
from ccxt_zagrava.base.errors import InvalidOrder
from ccxt_zagrava.base.errors import OrderNotFound
from ccxt_zagrava.base.errors import NotSupported
from ccxt_zagrava.base.errors import DDoSProtection
from ccxt_zagrava.base.errors import ExchangeNotAvailable
from ccxt_zagrava.base.errors import InvalidNonce
from ccxt_zagrava.base.decimal_to_precision import TICK_SIZE
from ccxt_zagrava.base.precise import Precise


class currencycom(Exchange, ImplicitAPI):

    def describe(self):
        return self.deep_extend(super(currencycom, self).describe(), {
            'id': 'currencycom',
            'name': 'Currency.com',
            'countries': ['BY'],  # Belarus
            'rateLimit': 100,
            'certified': False,
            'pro': True,
            'version': 'v2',
            # new metainfo interface
            'has': {
                'CORS': None,
                'spot': True,
                'margin': True,
                'swap': True,
                'future': False,
                'option': False,
                'addMargin': None,
                'cancelAllOrders': None,
                'cancelOrder': True,
                'cancelOrders': None,
                'createDepositAddress': None,
                'createLimitOrder': True,
                'createMarketOrder': True,
                'createOrder': True,
                'createStopLimitOrder': True,
                'createStopMarketOrder': True,
                'createStopOrder': True,
                'editOrder': 'emulated',
                'fetchAccounts': True,
                'fetchBalance': True,
                'fetchBidsAsks': None,
                'fetchBorrowRateHistory': None,
                'fetchCanceledOrders': None,
                'fetchClosedOrder': None,
                'fetchClosedOrders': None,
                'fetchCrossBorrowRate': False,
                'fetchCrossBorrowRates': False,
                'fetchCurrencies': True,
                'fetchDeposit': None,
                'fetchDepositAddress': True,
                'fetchDepositAddresses': False,
                'fetchDepositAddressesByNetwork': False,
                'fetchDeposits': True,
                'fetchDepositsWithdrawals': True,
                'fetchFundingHistory': False,
                'fetchFundingRate': False,
                'fetchFundingRateHistory': False,
                'fetchFundingRates': False,
                'fetchIndexOHLCV': False,
                'fetchIsolatedBorrowRate': False,
                'fetchIsolatedBorrowRates': False,
                'fetchL2OrderBook': True,
                'fetchLedger': True,
                'fetchLedgerEntry': False,
                'fetchLeverage': True,
                'fetchLeverageTiers': False,
                'fetchMarginMode': False,
                'fetchMarkets': True,
                'fetchMarkOHLCV': False,
                'fetchMyTrades': True,
                'fetchOHLCV': True,
                'fetchOpenOrder': None,
                'fetchOpenOrders': True,
                'fetchOrder': True,
                'fetchOrderBook': True,
                'fetchOrderBooks': None,
                'fetchOrders': None,
                'fetchOrderTrades': None,
                'fetchPosition': None,
                'fetchPositionMode': False,
                'fetchPositions': True,
                'fetchPositionsRisk': None,
                'fetchPremiumIndexOHLCV': False,
                'fetchTicker': True,
                'fetchTickers': True,
                'fetchTime': True,
                'fetchTrades': True,
                'fetchTradingFee': False,
                'fetchTradingFees': True,
                'fetchTradingLimits': None,
                'fetchTransactionFee': None,
                'fetchTransactionFees': None,
                'fetchTransactions': 'emulated',
                'fetchTransfers': None,
                'fetchWithdrawal': None,
                'fetchWithdrawals': True,
                'reduceMargin': None,
                'sandbox': True,
                'setLeverage': None,
                'setMarginMode': None,
                'setPositionMode': None,
                'signIn': None,
                'transfer': None,
                'withdraw': None,
            },
            'timeframes': {
                '1m': '1m',
                '5m': '5m',
                '10m': '10m',
                '15m': '15m',
                '30m': '30m',
                '1h': '1h',
                '4h': '4h',
                '1d': '1d',
                '1w': '1w',
            },
            'hostname': 'backend.currency.com',
            'urls': {
                'logo': 'https://user-images.githubusercontent.com/1294454/83718672-36745c00-a63e-11ea-81a9-677b1f789a4d.jpg',
                'api': {
                    'public': 'https://api-adapter.{hostname}/api',
                    'private': 'https://api-adapter.{hostname}/api',
                    'marketcap': 'https://marketcap.{hostname}/api',
                },
                'test': {
                    'public': 'https://demo-api-adapter.{hostname}/api',
                    'private': 'https://demo-api-adapter.{hostname}/api',
                },
                'www': 'https://www.currency.com',
                'referral': 'https://currency.com/trading/signup?c=362jaimv&pid=referral',
                'doc': [
                    'https://currency.com/api',
                ],
                'fees': 'https://currency.com/fees-charges',
            },
            # rate-limits are described at: https://currency.com/api-get-started
            'api': {
                'public': {
                    'get': {
                        'v1/time': 1,
                        'v1/exchangeInfo': 1,
                        'v1/depth': 1,
                        'v1/aggTrades': 1,
                        'v1/klines': 1,
                        'v1/ticker/24hr': 1,
                        'v2/time': 1,
                        'v2/exchangeInfo': 1,
                        'v2/depth': 1,
                        'v2/aggTrades': 1,
                        'v2/klines': 1,
                        'v2/ticker/24hr': 1,
                    },
                },
                'marketcap': {
                    'get': {
                        'v1/assets': 1,
                        'v1/candles': 1,
                        'v1/orderbook': 1,
                        'v1/summary': 1,
                        'v1/ticker': 1,
                        'v1/token/assets': 1,
                        'v1/token/orderbook': 1,
                        'v1/token/summary': 1,
                        'v1/token/ticker': 1,
                        'v1/token/trades': 1,
                        'v1/token_crypto/OHLC': 1,
                        'v1/token_crypto/assets': 1,
                        'v1/token_crypto/orderbook': 1,
                        'v1/token_crypto/summary': 1,
                        'v1/token_crypto/ticker': 1,
                        'v1/token_crypto/trades': 1,
                        'v1/trades': 1,
                    },
                },
                'private': {
                    'get': {
                        'v1/account': 1,
                        'v1/currencies': 1,
                        'v1/deposits': 1,
                        'v1/depositAddress': 1,
                        'v1/ledger': 1,
                        'v1/leverageSettings': 1,
                        'v1/myTrades': 1,
                        'v1/openOrders': 1,
                        'v1/tradingPositions': 1,
                        'v1/tradingPositionsHistory': 1,
                        'v1/transactions': 1,
                        'v1/withdrawals': 1,
                        'v2/account': 1,
                        'v2/currencies': 1,
                        'v2/deposits': 1,
                        'v2/depositAddress': 1,
                        'v2/ledger': 1,
                        'v2/leverageSettings': 1,
                        'v2/myTrades': 1,
                        'v2/openOrders': 1,
                        'v2/tradingPositions': 1,
                        'v2/tradingPositionsHistory': 1,
                        'v2/transactions': 1,
                        'v2/withdrawals': 1,
                        'v2/fetchOrder': 1,
                    },
                    'post': {
                        'v1/order': 1,
                        'v1/updateTradingPosition': 1,
                        'v1/updateTradingOrder': 1,
                        'v1/closeTradingPosition': 1,
                        'v2/order': 1,
                        'v2/updateTradingPosition': 1,
                        'v2/updateTradingOrder': 1,
                        'v2/closeTradingPosition': 1,
                    },
                    'delete': {
                        'v1/order': 1,
                        'v2/order': 1,
                    },
                },
            },
            'fees': {
                'trading': {
                    'feeSide': 'get',
                    'tierBased': False,
                    'percentage': True,
                    'taker': self.parse_number('0.002'),
                    'maker': self.parse_number('0.002'),
                },
            },
            'precisionMode': TICK_SIZE,
            # exchange-specific options
            'options': {
                'defaultTimeInForce': 'GTC',  # 'GTC' = Good To Cancel(default), 'IOC' = Immediate Or Cancel, 'FOK' = Fill Or Kill
                'warnOnFetchOpenOrdersWithoutSymbol': True,
                'recvWindow': 5 * 1000,  # 5 sec, default
                'timeDifference': 0,  # the difference between system clock and Binance clock
                'adjustForTimeDifference': False,  # controls the adjustment logic upon instantiation
                'parseOrderToPrecision': False,  # force amounts and costs in parseOrder to precision
                'newOrderRespType': {
                    'market': 'FULL',  # 'ACK' for order id, 'RESULT' for full order or 'FULL' for order with fills
                    'limit': 'RESULT',  # we change it from 'ACK' by default to 'RESULT'
                    'stop': 'RESULT',
                },
                'leverage_markets_suffix': '_LEVERAGE',
                'collateralCurrencies': ['USD', 'EUR', 'USDT'],
            },
            'exceptions': {
                'broad': {
                    'FIELD_VALIDATION_ERROR Cancel is available only for LIMIT order': InvalidOrder,
                    'API key does not exist': AuthenticationError,
                    'Order would trigger immediately.': InvalidOrder,
                    'Account has insufficient balance for requested action.': InsufficientFunds,
                    'Rest API trading is not enabled.': ExchangeNotAvailable,
                    'Combination of parameters invalid': BadRequest,
                    'Invalid limit price': BadRequest,
                    'Only leverage symbol allowed here:': BadSymbol,  # when you fetchLeverage for non-leverage symbols, like 'BTC/USDT' instead of 'BTC/USDT_LEVERAGE': {"code":"-1128","msg":"Only leverage symbol allowed here: BTC/USDT"}
                    'market data service is not available': ExchangeNotAvailable,  # {"code":"-1021","msg":"market data service is not available"}
                    'your time is ahead of server': InvalidNonce,  # {"code":"-1021","msg":"your time is ahead of server"}
                    'Can not find account': BadRequest,  # -1128
                    'You mentioned an invalid value for the price parameter': BadRequest,  # -1030
                },
                'exact': {
                    '-1000': ExchangeNotAvailable,  # {"code":-1000,"msg":"An unknown error occured while processing the request."}
                    '-1013': InvalidOrder,  # createOrder -> 'invalid quantity'/'invalid price'/MIN_NOTIONAL
                    # '-1021': InvalidNonce,  # {"code":"-1021","msg":"your time is ahead of server"}  # see above in the broad section
                    '-1022': AuthenticationError,  # {"code":-1022,"msg":"Signature for self request is not valid."}
                    '-1030': InvalidOrder,  # {"code":"-1030","msg":"You mentioned an invalid value for the price parameter."}
                    '-1100': InvalidOrder,  # createOrder(symbol, 1, asdf) -> 'Illegal characters found in parameter 'price'
                    '-1104': ExchangeError,  # Not all sent parameters were read, read 8 parameters but was sent 9
                    '-1025': AuthenticationError,  # {"code":-1025,"msg":"Invalid API-key, IP, or permissions for action"}
                    '-1128': BadRequest,  # {"code":-1128,"msg":"Combination of optional parameters invalid."} | {"code":"-1128","msg":"Combination of parameters invalid"} | {"code":"-1128","msg":"Invalid limit price"} | {"code":"-1128","msg":"Can not find account: null"}
                    '-2010': ExchangeError,  # generic error code for createOrder -> 'Account has insufficient balance for requested action.', {"code":-2010,"msg":"Rest API trading is not enabled."}, etc...
                    '-2011': OrderNotFound,  # cancelOrder(1, 'BTC/USDT') -> 'UNKNOWN_ORDER'
                    '-2013': OrderNotFound,  # fetchOrder(1, 'BTC/USDT') -> 'Order does not exist'
                    '-2014': AuthenticationError,  # {"code":-2014, "msg": "API-key format invalid."}
                    '-2015': AuthenticationError,  # "Invalid API-key, IP, or permissions for action."
                },
            },
            'commonCurrencies': {
                'ACN': 'Accenture',
                'AMC': 'AMC Entertainment Holdings',
                'BNS': 'Bank of Nova Scotia',
                'CAR': 'Avis Budget Group Inc',
                'CLR': 'Continental Resources',
                'EDU': 'New Oriental Education & Technology Group Inc',
                'ETN': 'Eaton',
                'FOX': 'Fox Corporation',
                'GM': 'General Motors Co',
                'IQ': 'iQIYI',
                'OSK': 'Oshkosh',
                'PLAY': "Dave & Buster's Entertainment",
            },
        })

    def nonce(self):
        return self.milliseconds() - self.options['timeDifference']

    def fetch_time(self, params={}):
        """
        fetches the current integer timestamp in milliseconds from the exchange server
        :see: https://apitradedoc.currency.com/swagger-ui.html#/rest-api/timeUsingGET
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns int: the current integer timestamp in milliseconds from the exchange server
        """
        response = self.publicGetV2Time(params)
        #
        #     {
        #         "serverTime": 1590998366609
        #     }
        #
        return self.safe_integer(response, 'serverTime')

    def fetch_currencies(self, params={}) -> Currencies:
        """
        fetches all available currencies on an exchange
        :see: https://apitradedoc.currency.com/swagger-ui.html#/rest-api/getCurrenciesUsingGET
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: an associative dictionary of currencies
        """
        # requires authentication
        if not self.check_required_credentials(False):
            return None
        response = self.privateGetV2Currencies(params)
        #
        #     [
        #         {
        #             "name": "Euro",
        #             "displaySymbol": "EUR.cx",
        #             "precision": "2",
        #             "type": "FIAT",
        #             "minWithdrawal": "90.0",
        #             "maxWithdrawal": "1.0E+8",
        #             "commissionMin": "0.02",  # some instruments do not have self property
        #             "commissionPercent": "1.5",  # some instruments do not have self property
        #             "minDeposit": "90.0",
        #         },
        #         {
        #             "name": "Bitcoin",
        #             "displaySymbol": "BTC",
        #             "precision": "8",
        #             "type": "CRYPTO",  # only a few major currencies have self value, others like USDT have a value of "TOKEN"
        #             "minWithdrawal": "0.00020",
        #             "commissionFixed": "0.00010",
        #             "minDeposit": "0.00010",
        #         },
        #     ]
        #
        result: dict = {}
        for i in range(0, len(response)):
            currency = response[i]
            id = self.safe_string(currency, 'displaySymbol')
            code = self.safe_currency_code(id)
            fee = self.safe_number(currency, 'commissionFixed')
            result[code] = {
                'id': id,
                'code': code,
                'type': self.safe_string_lower(currency, 'type'),
                'name': self.safe_string(currency, 'name'),
                'active': None,
                'deposit': None,
                'withdraw': None,
                'fee': fee,
                'precision': self.parse_number(self.parse_precision(self.safe_string(currency, 'precision'))),
                'limits': {
                    'amount': {
                        'min': None,
                        'max': None,
                    },
                    'withdraw': {
                        'min': self.safe_number(currency, 'minWithdrawal'),
                        'max': self.safe_number(currency, 'maxWithdrawal'),
                    },
                    'deposit': {
                        'min': self.safe_number(currency, 'minDeposit'),
                        'max': None,
                    },
                },
                'info': currency,
            }
        return result

    def fetch_markets(self, params={}) -> List[Market]:
        """
        retrieves data on all markets for currencycom
        :see: https://apitradedoc.currency.com/swagger-ui.html#/rest-api/exchangeInfoUsingGET
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict[]: an array of objects representing market data
        """
        response = self.publicGetV2ExchangeInfo(params)
        #
        #     {
        #         "timezone": "UTC",
        #         "serverTime": "1645186287261",
        #         "rateLimits": [
        #             {rateLimitType: "REQUEST_WEIGHT", interval: "MINUTE", intervalNum: "1", limit: "1200"},
        #             {rateLimitType: "ORDERS", interval: "SECOND", intervalNum: "1", limit: "10"},
        #             {rateLimitType: "ORDERS", interval: "DAY", intervalNum: "1", limit: "864000"},
        #         ],
        #         "exchangeFilters": [],
        #         "symbols": [
        #             {
        #                 "symbol": "BTC/USDT",  # BTC/USDT, BTC/USDT_LEVERAGE
        #                 "name": "Bitcoin / Tether",
        #                 "status": "TRADING",  # TRADING, BREAK, HALT
        #                 "baseAsset": "BTC",
        #                 "baseAssetPrecision": "4",
        #                 "quoteAsset": "USDT",
        #                 "quoteAssetId": "USDT",  # USDT, USDT_LEVERAGE
        #                 "quotePrecision": "4",
        #                 "orderTypes": ["LIMIT", "MARKET"],  # LIMIT, MARKET, STOP
        #                 "filters": [
        #                     {filterType: "LOT_SIZE", minQty: "0.0001", maxQty: "100", stepSize: "0.0001",},
        #                     {filterType: "MIN_NOTIONAL", minNotional: "5",},
        #                 ],
        #                 "marketModes": ["REGULAR"],  # CLOSE_ONLY, LONG_ONLY, REGULAR
        #                 "marketType": "SPOT",  # SPOT, LEVERAGE
        #                 "longRate": -0.0684932,  # LEVERAGE only
        #                 "shortRate": -0.0684932,  # LEVERAGE only
        #                 "swapChargeInterval": 1440,  # LEVERAGE only
        #                 "country": "",
        #                 "sector": "",
        #                 "industry": "",
        #                 "tradingHours": "UTC; Mon - 22:00, 22:05 -; Tue - 22:00, 22:05 -; Wed - 22:00, 22:05 -; Thu - 22:00, 22:05 -; Fri - 22:00, 23:01 -; Sat - 22:00, 22:05 -; Sun - 21:00, 22:05 -",
        #                 "tickSize": "0.01",
        #                 "tickValue": "403.4405",  # not available in BTC/USDT_LEVERAGE, but available in BTC/USD_LEVERAGE
        #                 "exchangeFee": "0.2",  # SPOT only
        #                 "tradingFee": 0.075,  # LEVERAGE only
        #                 "makerFee": -0.025,  # LEVERAGE only
        #                 "takerFee": 0.06,  # LEVERAGE only
        #                 "maxSLGap": 50,  # LEVERAGE only
        #                 "minSLGap": 1,  # LEVERAGE only
        #                 "maxTPGap": 50,  # LEVERAGE only
        #                 "minTPGap": 0.5,  # LEVERAGE only
        #                 "assetType": "CRYPTOCURRENCY",
        #             },
        #         ]
        #     }
        #
        if self.options['adjustForTimeDifference']:
            self.load_time_difference()
        markets = self.safe_value(response, 'symbols', [])
        result = []
        for i in range(0, len(markets)):
            market = markets[i]
            id = self.safe_string(market, 'symbol')
            baseId = self.safe_string(market, 'baseAsset')
            quoteId = self.safe_string(market, 'quoteAsset')
            base = self.safe_currency_code(baseId)
            quote = self.safe_currency_code(quoteId)
            symbol = base + '/' + quote
            typeRaw = self.safe_string(market, 'marketType')
            spot = (typeRaw == 'SPOT')
            futures = False
            swap = (typeRaw == 'LEVERAGE')
            type = 'swap' if swap else 'spot'
            margin = None
            if swap:
                symbol = symbol.replace(self.options['leverage_markets_suffix'], '')
                symbol += ':' + quote
            active = self.safe_string(market, 'status') == 'TRADING'
            # to set taker & maker fees, we use one from the below data - pairs either have 'exchangeFee' or 'tradingFee', if none of them(rare cases), then they should have 'takerFee & makerFee'
            exchangeFee = self.safe_string_2(market, 'exchangeFee', 'tradingFee')
            makerFee = self.safe_string(market, 'makerFee', exchangeFee)
            takerFee = self.safe_string(market, 'takerFee', exchangeFee)
            makerFee = Precise.string_div(makerFee, '100')
            takerFee = Precise.string_div(takerFee, '100')
            filters = self.safe_value(market, 'filters', [])
            filtersByType = self.index_by(filters, 'filterType')
            limitPriceMin = None
            limitPriceMax = None
            precisionPrice = self.safe_number(market, 'tickSize')
            if 'PRICE_FILTER' in filtersByType:
                filter = self.safe_value(filtersByType, 'PRICE_FILTER', {})
                precisionPrice = self.safe_number(filter, 'tickSize')
                # PRICE_FILTER reports zero values for maxPrice
                # since they updated filter types in November 2018
                # https://github.com/ccxt_zagrava/ccxt_zagrava/issues/4286
                # therefore limits['price']['max'] doesn't have any meaningful value except None
                limitPriceMin = self.safe_number(filter, 'minPrice')
                maxPrice = self.safe_string(filter, 'maxPrice')
                if (maxPrice is not None) and (Precise.string_gt(maxPrice, '0')):
                    limitPriceMax = maxPrice
            precisionAmount = self.parse_number(self.parse_precision(self.safe_string(market, 'baseAssetPrecision')))
            limitAmount: dict = {
                'min': None,
                'max': None,
            }
            if 'LOT_SIZE' in filtersByType:
                filter = self.safe_value(filtersByType, 'LOT_SIZE', {})
                precisionAmount = self.safe_number(filter, 'stepSize')
                limitAmount = {
                    'min': self.safe_number(filter, 'minQty'),
                    'max': self.safe_number(filter, 'maxQty'),
                }
            limitMarket: dict = {
                'min': None,
                'max': None,
            }
            if 'MARKET_LOT_SIZE' in filtersByType:
                filter = self.safe_value(filtersByType, 'MARKET_LOT_SIZE', {})
                limitMarket = {
                    'min': self.safe_number(filter, 'minQty'),
                    'max': self.safe_number(filter, 'maxQty'),
                }
            costMin = None
            if 'MIN_NOTIONAL' in filtersByType:
                filter = self.safe_value(filtersByType, 'MIN_NOTIONAL', {})
                costMin = self.safe_number(filter, 'minNotional')
            isContract = swap or futures
            result.append({
                'id': id,
                'symbol': symbol,
                'base': base,
                'quote': quote,
                'settle': None,
                'baseId': baseId,
                'quoteId': quoteId,
                'settleId': None,
                'type': type,
                'spot': spot,
                'margin': margin,
                'swap': swap,
                'future': futures,
                'option': False,
                'active': active,
                'contract': isContract,
                'linear': True if isContract else None,
                'inverse': None,
                'taker': self.parse_number(takerFee),
                'maker': self.parse_number(makerFee),
                'contractSize': None,
                'expiry': None,
                'expiryDatetime': None,
                'strike': None,
                'optionType': None,
                'precision': {
                    'amount': precisionAmount,
                    'price': precisionPrice,
                },
                'limits': {
                    'leverage': {
                        'min': None,
                        'max': None,
                    },
                    'amount': limitAmount,
                    'market': limitMarket,
                    'price': {
                        'min': limitPriceMin,
                        'max': self.parse_number(limitPriceMax),
                    },
                    'cost': {
                        'min': costMin,
                        'max': None,
                    },
                },
                'created': None,
                'info': market,
            })
        return result

    def fetch_accounts(self, params={}) -> List[Account]:
        """
        fetch all the accounts associated with a profile
        :see: https://apitradedoc.currency.com/swagger-ui.html#/rest-api/accountUsingGET
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: a dictionary of `account structures <https://docs.ccxt_zagrava.com/#/?id=account-structure>` indexed by the account type
        """
        response = self.privateGetV2Account(params)
        #
        #     {
        #         "makerCommission": "0.20",
        #         "takerCommission": "0.20",
        #         "buyerCommission": "0.20",
        #         "sellerCommission": "0.20",
        #         "canTrade": True,
        #         "canWithdraw": True,
        #         "canDeposit": True,
        #         "updateTime": "1645266330",
        #         "userId": "644722",
        #         "balances": [
        #             {
        #                 "accountId": "120702016179403605",
        #                 "collateralCurrency": False,
        #                 "asset": "CAKE",
        #                 "free": "3.1",
        #                 "locked": "0.0",
        #                 "default": False,
        #             },
        #             {
        #                 "accountId": "109698017713125316",
        #                 "collateralCurrency": True,
        #                 "asset": "USD",
        #                 "free": "17.58632",
        #                 "locked": "0.0",
        #                 "default": True,
        #             }
        #         ]
        #     }
        #
        accounts = self.safe_value(response, 'balances', [])
        result = []
        for i in range(0, len(accounts)):
            account = accounts[i]
            accountId = self.safe_string(account, 'accountId')  # must be string, because the numeric value is far too big for integer, and causes bugs
            currencyId = self.safe_string(account, 'asset')
            currencyCode = self.safe_currency_code(currencyId)
            result.append({
                'id': accountId,
                'type': None,
                'currency': currencyCode,
                'info': account,
            })
        return result

    def fetch_trading_fees(self, params={}) -> TradingFees:
        """
        fetch the trading fees for multiple markets
        :see: https://apitradedoc.currency.com/swagger-ui.html#/rest-api/accountUsingGET
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: a dictionary of `fee structures <https://docs.ccxt_zagrava.com/#/?id=fee-structure>` indexed by market symbols
        """
        self.load_markets()
        response = self.privateGetV2Account(params)
        #
        #    {
        #        "makerCommission": "0.20",
        #        "takerCommission": "0.20",
        #        "buyerCommission": "0.20",
        #        "sellerCommission": "0.20",
        #        "canTrade": True,
        #        "canWithdraw": True,
        #        "canDeposit": True,
        #        "updateTime": "1645738976",
        #        "userId": "-1924114235",
        #        "balances": []
        #    }
        #
        makerFee = self.safe_number(response, 'makerCommission')
        takerFee = self.safe_number(response, 'takerCommission')
        result: dict = {}
        for i in range(0, len(self.symbols)):
            symbol = self.symbols[i]
            result[symbol] = {
                'info': response,
                'symbol': symbol,
                'maker': makerFee,
                'taker': takerFee,
                'percentage': True,
                'tierBased': False,
            }
        return result

    def parse_balance(self, response, type=None):
        #
        #     {
        #         "makerCommission":0.20,
        #         "takerCommission":0.20,
        #         "buyerCommission":0.20,
        #         "sellerCommission":0.20,
        #         "canTrade":true,
        #         "canWithdraw":true,
        #         "canDeposit":true,
        #         "updateTime":1591056268,
        #         "balances":[
        #             {
        #                 "accountId":5470306579272368,
        #                 "collateralCurrency":true,
        #                 "asset":"ETH",
        #                 "free":0.0,
        #                 "locked":0.0,
        #                 "default":false,
        #             },
        #         ]
        #     }
        #
        result: dict = {'info': response}
        balances = self.safe_value(response, 'balances', [])
        for i in range(0, len(balances)):
            balance = balances[i]
            currencyId = self.safe_string(balance, 'asset')
            code = self.safe_currency_code(currencyId)
            account = self.account()
            account['free'] = self.safe_string(balance, 'free')
            account['used'] = self.safe_string(balance, 'locked')
            result[code] = account
        return self.safe_balance(result)

    def fetch_balance(self, params={}) -> Balances:
        """
        query for balance and get the amount of funds available for trading or funds locked in orders
        :see: https://apitradedoc.currency.com/swagger-ui.html#/rest-api/accountUsingGET
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: a `balance structure <https://docs.ccxt_zagrava.com/#/?id=balance-structure>`
        """
        self.load_markets()
        response = self.privateGetV2Account(params)
        #
        #     {
        #         "makerCommission": "0.20",
        #         "takerCommission": "0.20",
        #         "buyerCommission": "0.20",
        #         "sellerCommission": "0.20",
        #         "canTrade": True,
        #         "canWithdraw": True,
        #         "canDeposit": True,
        #         "updateTime": "1645266330",
        #         "userId": "644722",
        #         "balances": [
        #             {
        #                 "accountId": "120702016179403605",
        #                 "collateralCurrency": False,
        #                 "asset": "CAKE",
        #                 "free": "1.784",
        #                 "locked": "0.0",
        #                 "default": False,
        #             },
        #             {
        #                 "accountId": "109698017413175316",
        #                 "collateralCurrency": True,
        #                 "asset": "USD",
        #                 "free": "7.58632",
        #                 "locked": "0.0",
        #                 "default": True,
        #             }
        #         ]
        #     }
        #
        return self.parse_balance(response)

    def fetch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook:
        """
        fetches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
        :see: https://apitradedoc.currency.com/swagger-ui.html#/rest-api/depthUsingGET
        :param str symbol: unified symbol of the market to fetch the order book for
        :param int [limit]: the maximum amount of order book entries to return
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: A dictionary of `order book structures <https://docs.ccxt_zagrava.com/#/?id=order-book-structure>` indexed by market symbols
        """
        self.load_markets()
        market = self.market(symbol)
        request: dict = {
            'symbol': market['id'],
        }
        if limit is not None:
            request['limit'] = limit  # default 100, max 1000, valid limits 5, 10, 20, 50, 100, 500, 1000, 5000
        response = self.publicGetV2Depth(self.extend(request, params))
        #
        #     {
        #         "lastUpdateId":1590999849037,
        #         "asks":[
        #             [0.02495,60.0345],
        #             [0.02496,34.1],
        #             ...
        #         ],
        #         "bids":[
        #             [0.02487,72.4144854],
        #             [0.02486,24.043],
        #             ...
        #         ]
        #     }
        #
        orderbook = self.parse_order_book(response, symbol)
        orderbook['nonce'] = self.safe_integer(response, 'lastUpdateId')
        return orderbook

    def parse_ticker(self, ticker: dict, market: Market = None) -> Ticker:
        #
        # fetchTicker
        #
        #     {
        #         "symbol":"ETH/BTC",
        #         "priceChange":"0.00030",
        #         "priceChangePercent":"1.21",
        #         "weightedAvgPrice":"0.02481",
        #         "prevClosePrice":"0.02447",
        #         "lastPrice":"0.02477",
        #         "lastQty":"60.0",
        #         "bidPrice":"0.02477",
        #         "askPrice":"0.02484",
        #         "openPrice":"0.02447",
        #         "highPrice":"0.02524",
        #         "lowPrice":"0.02438",
        #         "volume":"11.97",
        #         "quoteVolume":"0.298053",
        #         "openTime":1590969600000,
        #         "closeTime":1591000072693
        #     }
        #
        # fetchTickers
        #
        #     {
        #          "symbol": "SHIB/USD_LEVERAGE",
        #          "weightedAvgPrice": "0.000027595",
        #          "lastPrice": "0.00002737",
        #          "lastQty": "1.11111111E8",
        #          "bidPrice": "0.00002737",
        #          "askPrice": "0.00002782",
        #          "highPrice": "0.00002896",
        #          "lowPrice": "0.00002738",
        #          "volume": "16472160000",
        #          "quoteVolume": "454796.3376",
        #          "openTime": "1645187472000",
        #          "closeTime": "1645273872000",
        #     }
        #
        # ws:marketData.subscribe
        #
        #     {
        #          "symbolName":"TXN",
        #          "bid":139.85,
        #          "bidQty":2500,
        #          "ofr":139.92000000000002,
        #          "ofrQty":2500,
        #          "timestamp":1597850971558
        #      }
        #
        timestamp = self.safe_integer_2(ticker, 'closeTime', 'timestamp')
        marketId = self.safe_string_2(ticker, 'symbol', 'symbolName')
        market = self.safe_market(marketId, market, '/')
        last = self.safe_string(ticker, 'lastPrice')
        return self.safe_ticker({
            'symbol': market['symbol'],
            'timestamp': timestamp,
            'datetime': self.iso8601(timestamp),
            'high': self.safe_string(ticker, 'highPrice'),
            'low': self.safe_string(ticker, 'lowPrice'),
            'bid': self.safe_string_2(ticker, 'bidPrice', 'bid'),
            'bidVolume': self.safe_string(ticker, 'bidQty'),
            'ask': self.safe_string_2(ticker, 'askPrice', 'ofr'),
            'askVolume': self.safe_string(ticker, 'ofrQty'),
            'vwap': self.safe_string(ticker, 'weightedAvgPrice'),
            'open': self.safe_string(ticker, 'openPrice'),
            'close': last,
            'last': last,
            'previousClose': self.safe_string(ticker, 'prevClosePrice'),  # previous day close
            'change': self.safe_string(ticker, 'priceChange'),
            'percentage': self.safe_string(ticker, 'priceChangePercent'),
            'average': None,
            'baseVolume': self.safe_string(ticker, 'volume'),
            'quoteVolume': self.safe_string(ticker, 'quoteVolume'),
            'info': ticker,
        }, market)

    def fetch_ticker(self, symbol: str, params={}) -> Ticker:
        """
        fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
        :see: https://apitradedoc.currency.com/swagger-ui.html#/rest-api/ticker_24hrUsingGET
        :param str symbol: unified symbol of the market to fetch the ticker for
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: a `ticker structure <https://docs.ccxt_zagrava.com/#/?id=ticker-structure>`
        """
        self.load_markets()
        market = self.market(symbol)
        request: dict = {
            'symbol': market['id'],
        }
        response = self.publicGetV2Ticker24hr(self.extend(request, params))
        #
        #     {
        #         "symbol":"ETH/BTC",
        #         "priceChange":"0.00030",
        #         "priceChangePercent":"1.21",
        #         "weightedAvgPrice":"0.02481",
        #         "prevClosePrice":"0.02447",
        #         "lastPrice":"0.02477",
        #         "lastQty":"60.0",
        #         "bidPrice":"0.02477",
        #         "askPrice":"0.02484",
        #         "openPrice":"0.02447",
        #         "highPrice":"0.02524",
        #         "lowPrice":"0.02438",
        #         "volume":"11.97",
        #         "quoteVolume":"0.298053",
        #         "openTime":1590969600000,
        #         "closeTime":1591000072693
        #     }
        #
        return self.parse_ticker(response, market)

    def fetch_tickers(self, symbols: Strings = None, params={}) -> Tickers:
        """
        fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market
        :see: https://apitradedoc.currency.com/swagger-ui.html#/rest-api/ticker_24hrUsingGET
        :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 exchange API endpoint
        :returns dict: a dictionary of `ticker structures <https://docs.ccxt_zagrava.com/#/?id=ticker-structure>`
        """
        self.load_markets()
        response = self.publicGetV2Ticker24hr(params)
        #
        #     [
        #         {
        #              "symbol": "SHIB/USD_LEVERAGE",
        #              "weightedAvgPrice": "0.000027595",
        #              "lastPrice": "0.00002737",
        #              "lastQty": "1.11111111E8",
        #              "bidPrice": "0.00002737",
        #              "askPrice": "0.00002782",
        #              "highPrice": "0.00002896",
        #              "lowPrice": "0.00002738",
        #              "volume": "16472160000",
        #              "quoteVolume": "454796.3376",
        #              "openTime": "1645187472000",
        #              "closeTime": "1645273872000",
        #         }
        #     ]
        #
        return self.parse_tickers(response, symbols)

    def parse_ohlcv(self, ohlcv, market: Market = None) -> list:
        #
        #     [
        #         1590971040000,
        #         "0.02454",
        #         "0.02456",
        #         "0.02452",
        #         "0.02456",
        #         249
        #     ]
        #
        return [
            self.safe_integer(ohlcv, 0),
            self.safe_number(ohlcv, 1),
            self.safe_number(ohlcv, 2),
            self.safe_number(ohlcv, 3),
            self.safe_number(ohlcv, 4),
            self.safe_number(ohlcv, 5),
        ]

    def fetch_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}) -> List[list]:
        """
        fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
        :see: https://apitradedoc.currency.com/swagger-ui.html#/rest-api/klinesUsingGET
        :param str symbol: unified symbol of the market to fetch OHLCV data for
        :param str timeframe: the length of time each candle represents
        :param int [since]: timestamp in ms of the earliest candle to fetch
        :param int [limit]: the maximum amount of candles to fetch
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns int[][]: A list of candles ordered, open, high, low, close, volume
        """
        self.load_markets()
        market = self.market(symbol)
        request: dict = {
            'symbol': market['id'],
            'interval': self.safe_string(self.timeframes, timeframe, timeframe),
        }
        if since is not None:
            request['startTime'] = since
        if limit is not None:
            request['limit'] = min(limit, 1000)  # default 500, max 1000
        response = self.publicGetV2Klines(self.extend(request, params))
        #
        #     [
        #         [1590971040000,"0.02454","0.02456","0.02452","0.02456",249],
        #         [1590971100000,"0.02455","0.02457","0.02452","0.02456",300],
        #         [1590971160000,"0.02455","0.02456","0.02453","0.02454",286],
        #     ]
        #
        return self.parse_ohlcvs(response, market, timeframe, since, limit)

    def parse_trade(self, trade: dict, market: Market = None) -> Trade:
        #
        # fetchTrades(public aggregate trades)
        #
        #     {
        #         "a":"1658318071",    # Aggregate tradeId
        #         "p":"0.02476",       # Price
        #         "q":"0.0",           # Official doc says: "Quantity(should be ignored)"
        #         "T":"1591001423382",  # Epoch timestamp in MS
        #         "m":false            # Was the buyer the maker
        #     }
        #
        # createOrder fills(private)
        #
        #     {
        #         "price": "9807.05",
        #         "qty": "0.01",
        #         "commission": "0",
        #         "commissionAsset": "dUSD"
        #     }
        #
        # fetchMyTrades
        #
        #     {
        #         "symbol": "DOGE/USD",
        #         "id": "116046000",
        #         "orderId": "00000000-0000-0000-0000-000006dbb8ad",
        #         "price": "0.14094",
        #         "qty": "40.0",
        #         "commission": "0.01",
        #         "commissionAsset": "USD",
        #         "time": "1645283022351",
        #         "buyer": False,
        #         "maker": False,
        #         "isBuyer": False,
        #         "isMaker": False
        #     }
        #
        timestamp = self.safe_integer_2(trade, 'T', 'time')
        priceString = self.safe_string_2(trade, 'p', 'price')
        amountString = self.safe_string_2(trade, 'q', 'qty')
        id = self.safe_string_2(trade, 'a', 'id')
        side = None
        orderId = self.safe_string(trade, 'orderId')
        takerOrMaker = None
        if 'm' in trade:
            side = 'sell' if trade['m'] else 'buy'  # self is reversed intentionally [TODO: needs reason to be mentioned]
            takerOrMaker = 'taker'  # in public trades, it's always taker
        elif 'isBuyer' in trade:
            side = 'buy' if (trade['isBuyer']) else 'sell'  # self is a True side
            takerOrMaker = 'maker' if trade['isMaker'] else 'taker'
        fee = None
        if 'commission' in trade:
            fee = {
                'cost': self.safe_string(trade, 'commission'),
                'currency': self.safe_currency_code(self.safe_string(trade, 'commissionAsset')),
            }
        marketId = self.safe_string(trade, 'symbol')
        symbol = self.safe_symbol(marketId, market)
        return self.safe_trade({
            'id': id,
            'order': orderId,
            'timestamp': timestamp,
            'datetime': self.iso8601(timestamp),
            'symbol': symbol,
            'type': None,
            'takerOrMaker': takerOrMaker,
            'side': side,
            'price': priceString,
            'amount': amountString,
            'cost': None,
            'fee': fee,
            'info': trade,
        }, market)

    def fetch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
        """
        get the list of most recent trades for a particular symbol
        :see: https://apitradedoc.currency.com/swagger-ui.html#/rest-api/aggTradesUsingGET
        :param str symbol: unified symbol of the market to fetch trades for
        :param int [since]: timestamp in ms of the earliest trade to fetch
        :param int [limit]: the maximum amount of trades to fetch
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns Trade[]: a list of `trade structures <https://docs.ccxt_zagrava.com/#/?id=public-trades>`
        """
        self.load_markets()
        market = self.market(symbol)
        request: dict = {
            'symbol': market['id'],
            # 'limit': 500,  # default 500, max 1000
        }
        if limit is not None:
            request['limit'] = min(limit, 1000)  # default 500, max 1000
        if since is not None:
            request['startTime'] = since
        response = self.publicGetV2AggTrades(self.extend(request, params))
        #
        # [
        #     {
        #         "a":"1658318071",    # Aggregate tradeId
        #         "p":"0.02476",       # Price
        #         "q":"0.0",           # Official doc says: "Quantity(should be ignored)"
        #         "T":"1591001423382",  # Epoch timestamp in MS
        #         "m":false            # Was the buyer the maker
        #     },
        # ]
        #
        return self.parse_trades(response, market, since, limit)

    def parse_order(self, order: dict, market: Market = None) -> Order:
        #
        # createOrder
        #
        # limit
        #
        #     {
        #         "symbol": "BTC/USD",
        #         "orderId": "00000000-0000-0000-0000-000006eacaa0",
        #         "transactTime": "1645281669295",
        #         "price": "30000.00000000",
        #         "origQty": "0.0002",     # might not be present for "market" order
        #         "executedQty": "0.0",    # positive for BUY, negative for SELL. This property might not be present in Leverage markets
        #         "margin": 0.1,           # present in leverage markets
        #         "status": "NEW",         # NEW, FILLED, ...
        #         "timeInForce": "GTC",
        #         "type": "LIMIT",         # LIMIT, MARKET
        #         "side": "BUY",
        #         "fills": [              # self field might not be present if there were no fills
        #             {
        #                 "price": "0.14094",
        #                 "qty": "40.0",
        #                 "commission": "0",
        #                 "commissionAsset": "dUSD",
        #             },
        #         ],
        #     }
        #
        # fetchOrder(fetchOpenOrders is an array same structure, with some extra fields)
        #
        #    {
        #        "symbol": "BTC/USD_LEVERAGE",
        #        "accountId": "123456789012345678",
        #        "orderId": "00a01234-0123-54c4-0000-123451234567",
        #        "price": "25779.35",
        #        "status": "MODIFIED",
        #        "type": "LIMIT",
        #        "timeInForceType": "GTC",
        #        "side": "BUY",
        #        "guaranteedStopLoss": False,
        #        "trailingStopLoss": False,
        #        "margin": "0.05",
        #        "takeProfit": "27020.00",
        #        "stopLoss": "24500.35",
        #        "fills": [],  # might not be present
        #        "timestamp": "1685958369623",  # "time" in "fetchOpenOrders"
        #        "expireTime": "1686167960000",  # "expireTimestamp" in "fetchOpenOrders"
        #        "quantity": "0.00040",  # "origQty" in "fetchOpenOrders"
        #        "executedQty": "0.0",  # present in "fetchOpenOrders"
        #        "updateTime": "1685958369542",  # present in "fetchOpenOrders"
        #        "leverage": True,  # present in "fetchOpenOrders"
        #        "working": True  # present in "fetchOpenOrders"
        #    }
        #
        # cancelOrder
        #
        #     {
        #         "symbol": "DOGE/USD",
        #         "orderId": "00000000-0000-0003-0000-000006db714c",
        #         "price": "0.13",
        #         "origQty": "30.0",
        #         "executedQty": "0.0",
        #         "status": "CANCELED",
        #         "timeInForce": "GTC",
        #         "type": "LIMIT",
        #         "side": "BUY",
        #     }
        #
        marketId = self.safe_string(order, 'symbol')
        symbol = self.safe_symbol(marketId, market, '/')
        id = self.safe_string(order, 'orderId')
        price = self.safe_string(order, 'price')
        amount = self.safe_string_2(order, 'origQty', 'quantity')
        filledRaw = self.safe_string(order, 'executedQty')
        filled = Precise.string_abs(filledRaw)
        status = self.parse_order_status(self.safe_string(order, 'status'))
        timeInForce = self.parse_order_time_in_force(self.safe_string_2(order, 'timeInForce', 'timeInForceType'))
        type = self.parse_order_type(self.safe_string(order, 'type'))
        side = self.parse_order_side(self.safe_string(order, 'side'))
        timestamp = self.safe_integer_n(order, ['time', 'transactTime', 'timestamp'])
        fills = self.safe_value(order, 'fills')
        return self.safe_order({
            'info': order,
            'id': id,
            'timestamp': timestamp,
            'datetime': self.iso8601(timestamp),
            'lastTradeTimestamp': None,
            'symbol': symbol,
            'type': type,
            'timeInForce': timeInForce,
            'side': side,
            'price': price,
            'stopPrice': None,
            'triggerPrice': None,
            'amount': amount,
            'cost': None,
            'average': None,
            'filled': filled,
            'remaining': None,
            'status': status,
            'fee': None,
            'trades': fills,
        }, market)

    def parse_order_status(self, status: Str):
        statuses: dict = {
            'NEW': 'open',
            'CREATED': 'open',
            'MODIFIED': 'open',
            'PARTIALLY_FILLED': 'open',
            'FILLED': 'closed',
            'CANCELED': 'canceled',
            'PENDING_CANCEL': 'canceling',
            'REJECTED': 'rejected',
            'EXPIRED': 'expired',
        }
        return self.safe_string(statuses, status, status)

    def parse_order_type(self, status):
        statuses: dict = {
            'MARKET': 'market',
            'LIMIT': 'limit',
            'STOP': 'stop',
            # temporarily we remove custom mappings
            # 'LIMIT_MAKER': '',
            # 'STOP_LOSS': 'stop-loss',
            # 'STOP_LOSS_LIMIT': 'stop-limit',
            # 'TAKE_PROFIT': 'take-profit',
            # 'TAKE_PROFIT_LIMIT': 'take-profit',
        }
        return self.safe_string(statuses, status, status)

    def parse_order_time_in_force(self, status):
        statuses: dict = {
            'GTC': 'GTC',
            'FOK': 'FOK',
            'IOC': 'IOC',
        }
        return self.safe_string(statuses, status, status)

    def parse_order_side(self, status):
        statuses: dict = {
            'BUY': 'buy',
            'SELL': 'sell',
        }
        return self.safe_string(statuses, status, status)

    def create_order(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
        """
        create a trade order
        :see: https://apitradedoc.currency.com/swagger-ui.html#/rest-api/orderUsingPOST
        :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 [price]: the price at which the order is to be fulfilled, in units of the quote currency, ignored in market orders
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: an `order structure <https://docs.ccxt_zagrava.com/#/?id=order-structure>`
        """
        self.load_markets()
        market = self.market(symbol)
        accountId = None
        if market['margin']:
            accountId = self.safe_string(self.options, 'accountId')
            accountId = self.safe_string(params, 'accountId', accountId)
            if accountId is None:
                raise ArgumentsRequired(self.id + " createOrder() requires an accountId parameter or an exchange.options['accountId'] option for " + market['type'] + ' markets')
        newOrderRespType = self.safe_value(self.options['newOrderRespType'], type, 'RESULT')
        request: dict = {
            'symbol': market['id'],
            'quantity': self.amount_to_precision(symbol, amount),
            'type': type.upper(),
            'side': side.upper(),
            'newOrderRespType': newOrderRespType,  # 'RESULT' for full order or 'FULL' for order with fills
            # 'leverage': 1,
            # 'accountId': 5470306579272968,  # required for leverage markets
            # 'takeProfit': '123.45',
            # 'stopLoss': '54.321',
            # 'guaranteedStopLoss': '54.321',
        }
        if type == 'limit':
            request['price'] = self.price_to_precision(symbol, price)
            request['timeInForce'] = self.options['defaultTimeInForce']
        else:
            if type == 'stop':
                request['type'] = 'STOP'
                request['price'] = self.price_to_precision(symbol, price)
            elif type == 'market':
                stopPrice = self.safe_value_2(params, 'triggerPrice', 'stopPrice')
                params = self.omit(params, ['triggerPrice', 'stopPrice'])
                if stopPrice is not None:
                    request['type'] = 'STOP'
                    request['price'] = self.price_to_precision(symbol, stopPrice)
        response = self.privatePostV2Order(self.extend(request, params))
        #
        # limit
        #
        #     {
        #         "symbol": "BTC/USD",
        #         "orderId": "00000000-0000-0000-0000-000006eaaaa0",
        #         "transactTime": "1645281669295",
        #         "price": "30000.00000000",
        #         "origQty": "0.0002",
        #         "executedQty": "0.0",  # positive for BUY, negative for SELL
        #         "status": "NEW",
        #         "timeInForce": "GTC",
        #         "type": "LIMIT",
        #         "side": "BUY",
        #     }
        #
        # market
        #
        #     {
        #         "symbol": "DOGE/USD",
        #         "orderId": "00000000-0000-0000-0000-000006eab8ad",
        #         "transactTime": "1645283022252",
        #         "price": "0.14066000",
        #         "origQty": "40",
        #         "executedQty": "40.0",  # positive for BUY, negative for SELL
        #         "status": "FILLED",
        #         "timeInForce": "FOK",
        #         "type": "MARKET",
        #         "side": "BUY",
        #         "fills": [
        #             {
        #                 "price": "0.14094",
        #                 "qty": "40.0",
        #                 "commission": "0",
        #                 "commissionAsset": "dUSD"
        #             }
        #         ]
        #     }
        #
        return self.parse_order(response, market)

    def fetch_order(self, id: str, symbol: Str = None, params={}):
        """
        fetches information on an order made by the user
        :see: https://apitradedoc.currency.com/swagger-ui.html#/rest-api/getOrderUsingGET
        :param str symbol: unified symbol of the market the order was made in
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: An `order structure <https://docs.ccxt_zagrava.com/#/?id=order-structure>`
        """
        if symbol is None:
            raise ArgumentsRequired(self.id + ' fetchOrder() requires a symbol argument')
        self.load_markets()
        market = self.market(symbol)
        request: dict = {
            'orderId': id,
            'symbol': market['id'],
        }
        response = self.privateGetV2FetchOrder(self.extend(request, params))
        #
        #    {
        #        "accountId": "109698017413125316",
        #        "orderId": "2810f1c5-0079-54c4-0000-000080421601",
        #        "quantity": "20.0",
        #        "price": "0.06",
        #        "timestamp": "1661157503788",
        #        "status": "CREATED",
        #        "type": "LIMIT",
        #        "timeInForceType": "GTC",
        #        "side": "BUY",
        #        "margin": "0.1",
        #        "fills": [ # might not be present
        #             {
        #                 "price": "0.14094",
        #                 "qty": "40.0",
        #                 "commission": "0",
        #                 "commissionAsset": "dUSD"
        #             }
        #        ]
        #    }
        #
        return self.parse_order(response)

    def fetch_open_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
        """
        fetch all unfilled currently open orders
        :see: https://apitradedoc.currency.com/swagger-ui.html#/rest-api/openOrdersUsingGET
        :param str symbol: unified market symbol
        :param int [since]: the earliest time in ms to fetch open orders for
        :param int [limit]: the maximum number of  open orders structures to retrieve
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns Order[]: a list of `order structures <https://docs.ccxt_zagrava.com/#/?id=order-structure>`
        """
        self.load_markets()
        market = None
        request: dict = {}
        if symbol is not None:
            market = self.market(symbol)
            request['symbol'] = market['id']
        elif self.options['warnOnFetchOpenOrdersWithoutSymbol']:
            symbols = self.symbols
            numSymbols = len(symbols)
            fetchOpenOrdersRateLimit = self.parse_to_int(numSymbols / 2)
            raise ExchangeError(self.id + ' fetchOpenOrders() WARNING: fetching open orders without specifying a symbol is rate-limited to one call per ' + str(fetchOpenOrdersRateLimit) + ' seconds. Do not call self method frequently to avoid ban. Set ' + self.id + '.options["warnOnFetchOpenOrdersWithoutSymbol"] = False to suppress self warning message.')
        response = self.privateGetV2OpenOrders(self.extend(request, params))
        #
        #     [
        #         {
        #             "symbol": "DOGE/USD",
        #             "orderId": "00000000-0000-0003-0000-000004bac57a",
        #             "price": "0.13",
        #             "origQty": "39.0",
        #             "executedQty": "0.0",  # positive for BUY, negative for SELL
        #             "status": "NEW",
        #             "timeInForce": "GTC",
        #             "type": "LIMIT",
        #             "side": "BUY",
        #             "time": "1645284216240",
        #             "updateTime": "1645284216240",
        #             "leverage": False,
        #             "working": True
        #         },
        #     ]
        #
        return self.parse_orders(response, market, since, limit, params)

    def cancel_order(self, id: str, symbol: Str = None, params={}):
        """
        cancels an open order
        :see: https://apitradedoc.currency.com/swagger-ui.html#/rest-api/cancelOrderUsingDELETE
        :param str id: order id
        :param str symbol: unified symbol of the market the order was made in
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: An `order structure <https://docs.ccxt_zagrava.com/#/?id=order-structure>`
        """
        if symbol is None:
            raise ArgumentsRequired(self.id + ' cancelOrder() requires a symbol argument')
        self.load_markets()
        market = self.market(symbol)
        origClientOrderId = self.safe_value(params, 'origClientOrderId')
        request: dict = {
            'symbol': market['id'],
            # 'orderId': int(id),
            # 'origClientOrderId': id,
        }
        if origClientOrderId is None:
            request['orderId'] = id
        else:
            request['origClientOrderId'] = origClientOrderId
        response = self.privateDeleteV2Order(self.extend(request, params))
        #
        #     {
        #         "symbol": "DOGE/USD",
        #         "orderId": "00000000-0000-0003-0000-000006db764c",
        #         "price": "0.13",
        #         "origQty": "30.0",
        #         "executedQty": "0.0",  # positive for BUY, negative for SELL
        #         "status": "CANCELED",
        #         "timeInForce": "GTC",
        #         "type": "LIMIT",
        #         "side": "BUY",
        #     }
        #
        return self.parse_order(response, market)

    def fetch_my_trades(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
        """
        fetch all trades made by the user
        :see: https://apitradedoc.currency.com/swagger-ui.html#/rest-api/myTradesUsingGET
        :param str symbol: unified market symbol
        :param int [since]: the earliest time in ms to fetch trades for
        :param int [limit]: the maximum number of trades structures to retrieve
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns Trade[]: a list of `trade structures <https://docs.ccxt_zagrava.com/#/?id=trade-structure>`
        """
        if symbol is None:
            raise ArgumentsRequired(self.id + ' fetchMyTrades() requires a symbol argument')
        self.load_markets()
        market = self.market(symbol)
        request: dict = {
            'symbol': market['id'],
        }
        if limit is not None:
            request['limit'] = limit
        response = self.privateGetV2MyTrades(self.extend(request, params))
        #
        #     [
        #         {
        #             "symbol": "DOGE/USD",
        #             "id": "116046000",
        #             "orderId": "00000000-0000-0000-0000-000006dbb8ad",
        #             "price": "0.14094",
        #             "qty": "40.0",
        #             "commission": "0.01",
        #             "commissionAsset": "USD",
        #             "time": "1645283022351",
        #             "buyer": False,
        #             "maker": False,
        #             "isBuyer": False,
        #             "isMaker": False
        #         },
        #     ]
        #
        return self.parse_trades(response, market, since, limit)

    def fetch_deposits(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Transaction]:
        """
        fetch all deposits made to an account
        :see: https://apitradedoc.currency.com/swagger-ui.html#/rest-api/getDepositsUsingGET
        :param str code: unified currency code
        :param int [since]: the earliest time in ms to fetch deposits for
        :param int [limit]: the maximum number of deposits structures to retrieve
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict[]: a list of `transaction structures <https://docs.ccxt_zagrava.com/#/?id=transaction-structure>`
        """
        return self.fetch_transactions_by_method('privateGetV2Deposits', code, since, limit, params)

    def fetch_withdrawals(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Transaction]:
        """
        fetch all withdrawals made from an account
        :see: https://apitradedoc.currency.com/swagger-ui.html#/rest-api/getWithdrawalsUsingGET
        :param str code: unified currency code
        :param int [since]: the earliest time in ms to fetch withdrawals for
        :param int [limit]: the maximum number of withdrawals structures to retrieve
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict[]: a list of `transaction structures <https://docs.ccxt_zagrava.com/#/?id=transaction-structure>`
        """
        return self.fetch_transactions_by_method('privateGetV2Withdrawals', code, since, limit, params)

    def fetch_deposits_withdrawals(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Transaction]:
        """
        fetch history of deposits and withdrawals
        :see: https://apitradedoc.currency.com/swagger-ui.html#/rest-api/getTransactionsUsingGET
        :param str [code]: unified currency code for the currency of the deposit/withdrawals, default is None
        :param int [since]: timestamp in ms of the earliest deposit/withdrawal, default is None
        :param int [limit]: max number of deposit/withdrawals to return, default is None
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: a list of `transaction structure <https://docs.ccxt_zagrava.com/#/?id=transaction-structure>`
        """
        return self.fetch_transactions_by_method('privateGetV2Transactions', code, since, limit, params)

    def fetch_transactions_by_method(self, method, code: Str = None, since: Int = None, limit: Int = None, params={}):
        self.load_markets()
        request: dict = {}
        currency = None
        if code is not None:
            currency = self.currency(code)
        if since is not None:
            request['startTime'] = since
        if limit is not None:
            request['limit'] = limit
        response = None
        if method == 'privateGetV2Deposits':
            response = self.privateGetV2Deposits(self.extend(request, params))
        elif method == 'privateGetV2Withdrawals':
            response = self.privateGetV2Withdrawals(self.extend(request, params))
        elif method == 'privateGetV2Transactions':
            response = self.privateGetV2Transactions(self.extend(request, params))
        else:
            raise NotSupported(self.id + ' fetchTransactionsByMethod() not support self method')
        #
        #    [
        #        {
        #            "id": "616769213",
        #            "balance": "2.088",
        #            "amount": "1.304",   # negative for 'withdrawal'
        #            "currency": "CAKE",
        #            "type": "deposit",
        #            "timestamp": "1645282121023",
        #            "paymentMethod": "BLOCKCHAIN",
        #            "blockchainTransactionHash": "0x57c68c1f2ae74d5eda5a2a00516361d241a5c9e1ee95bf32573523857c38c112",
        #            "status": "PROCESSED",
        #            "commission": "0.14",  # self property only exists in withdrawal
        #        },
        #    ]
        #
        return self.parse_transactions(response, currency, since, limit, params)

    def parse_transaction(self, transaction: dict, currency: Currency = None) -> Transaction:
        #
        #    {
        #        "id": "616769213",
        #        "balance": "2.088",
        #        "amount": "1.304",   # negative for 'withdrawal'
        #        "currency": "CAKE",
        #        "type": "deposit",
        #        "timestamp": "1645282121023",
        #        "paymentMethod": "BLOCKCHAIN",
        #        "blockchainTransactionHash": "0x57c68c1f2ae74d5eda5a2a00516361d241a5c9e1ee95bf32573523857c38c112",
        #        "status": "PROCESSED",
        #        "commission": "0.14",  # self property only exists in withdrawal
        #    }
        #
        timestamp = self.safe_integer(transaction, 'timestamp')
        currencyId = self.safe_string(transaction, 'currency')
        code = self.safe_currency_code(currencyId, currency)
        feeCost = self.safe_string(transaction, 'commission')
        fee = {
            'currency': None,
            'cost': None,
            'rate': None,
        }
        if feeCost is not None:
            fee['currency'] = code
            fee['cost'] = feeCost
        return {
            'info': transaction,
            'id': self.safe_string(transaction, 'id'),
            'txid': self.safe_string(transaction, 'blockchainTransactionHash'),
            'type': self.parse_transaction_type(self.safe_string(transaction, 'type')),
            'currency': code,
            'network': None,
            'amount': self.safe_number(transaction, 'amount'),
            'status': self.parse_transaction_status(self.safe_string(transaction, 'state')),
            'timestamp': timestamp,
            'datetime': self.iso8601(timestamp),
            'address': None,
            'addressFrom': None,
            'addressTo': None,
            'tag': None,
            'tagFrom': None,
            'tagTo': None,
            'updated': None,
            'internal': None,
            'comment': None,
            'fee': fee,
        }

    def parse_transaction_status(self, status: Str):
        statuses: dict = {
            'APPROVAL': 'pending',
            'PROCESSED': 'ok',
        }
        return self.safe_string(statuses, status, status)

    def parse_transaction_type(self, type):
        types: dict = {
            'deposit': 'deposit',
            'withdrawal': 'withdrawal',
        }
        return self.safe_string(types, type, type)

    def fetch_ledger(self, code: Str = None, since: Int = None, limit: Int = None, params={}):
        """
        fetch the history of changes, actions done by the user or operations that altered balance of the user
        :see: https://apitradedoc.currency.com/swagger-ui.html#/rest-api/getLedgerUsingGET
        :param str code: unified currency code, default is None
        :param int [since]: timestamp in ms of the earliest ledger entry, default is None
        :param int [limit]: max number of ledger entrys to return, default is None
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: a `ledger structure <https://docs.ccxt_zagrava.com/#/?id=ledger-structure>`
        """
        self.load_markets()
        request: dict = {}
        currency = None
        if code is not None:
            currency = self.currency(code)
        if since is not None:
            request['startTime'] = since
        if limit is not None:
            request['limit'] = limit
        response = self.privateGetV2Ledger(self.extend(request, params))
        # in the below example, first item expresses withdrawal/deposit type, second example expresses trade
        #
        # [
        #     {
        #       "id": "619031398",
        #       "balance": "0.0",
        #       "amount": "-1.088",
        #       "currency": "CAKE",
        #       "type": "withdrawal",
        #       "timestamp": "1645460496425",
        #       "commission": "0.13",
        #       "paymentMethod": "BLOCKCHAIN",  # present in withdrawal/deposit
        #       "blockchainTransactionHash": "0x400ac905557c3d34638b1c60eba110b3ee0f97f4eb0f7318015ab76e7f16b7d6",  # present in withdrawal/deposit
        #       "status": "PROCESSED"
        #     },
        #     {
        #       "id": "619031034",
        #       "balance": "8.17223588",
        #       "amount": "-0.01326294",
        #       "currency": "USD",
        #       "type": "exchange_commission",
        #       "timestamp": "1645460461235",
        #       "commission": "0.01326294",
        #       "status": "PROCESSED"
        #     },
        # ]
        #
        return self.parse_ledger(response, currency, since, limit)

    def parse_ledger_entry(self, item: dict, currency: Currency = None):
        id = self.safe_string(item, 'id')
        amountString = self.safe_string(item, 'amount')
        amount = Precise.string_abs(amountString)
        timestamp = self.safe_integer(item, 'timestamp')
        currencyId = self.safe_string(item, 'currency')
        code = self.safe_currency_code(currencyId, currency)
        feeCost = self.safe_string(item, 'commission')
        fee = None
        if feeCost is not None:
            fee = {'currency': code, 'cost': feeCost}
        direction = 'out' if Precise.string_lt(amountString, '0') else 'in'
        result: dict = {
            'id': id,
            'timestamp': timestamp,
            'datetime': self.iso8601(timestamp),
            'direction': direction,
            'account': None,
            'referenceId': self.safe_string(item, 'blockchainTransactionHash'),
            'referenceAccount': None,
            'type': self.parse_ledger_entry_type(self.safe_string(item, 'type')),
            'currency': code,
            'amount': amount,
            'before': None,
            'after': self.safe_string(item, 'balance'),
            'status': self.parse_ledger_entry_status(self.safe_string(item, 'status')),
            'fee': fee,
            'info': item,
        }
        return result

    def parse_ledger_entry_status(self, status):
        statuses: dict = {
            'APPROVAL': 'pending',
            'PROCESSED': 'ok',
            'CANCELLED': 'canceled',
        }
        return self.safe_string(statuses, status, status)

    def parse_ledger_entry_type(self, type):
        types: dict = {
            'deposit': 'transaction',
            'withdrawal': 'transaction',
            'exchange_commission': 'fee',
        }
        return self.safe_string(types, type, type)

    def fetch_leverage(self, symbol: str, params={}) -> Leverage:
        """
        fetch the set leverage for a market
        :see: https://apitradedoc.currency.com/swagger-ui.html#/rest-api/leverageSettingsUsingGET
        :param str symbol: unified market symbol
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: a `leverage structure <https://docs.ccxt_zagrava.com/#/?id=leverage-structure>`
        """
        self.load_markets()
        market = self.market(symbol)
        request: dict = {
            'symbol': market['id'],
        }
        response = self.privateGetV2LeverageSettings(self.extend(request, params))
        #
        #     {
        #         "values": [1, 2, 5, 10,],
        #         "value": "10",
        #     }
        #
        return self.parse_leverage(response, market)

    def parse_leverage(self, leverage: dict, market: Market = None) -> Leverage:
        leverageValue = self.safe_integer(leverage, 'value')
        return {
            'info': leverage,
            'symbol': market['symbol'],
            'marginMode': None,
            'longLeverage': leverageValue,
            'shortLeverage': leverageValue,
        }

    def fetch_deposit_address(self, code: str, params={}):
        """
        fetch the deposit address for a currency associated with self account
        :see: https://apitradedoc.currency.com/swagger-ui.html#/rest-api/getDepositAddressUsingGET
        :param str code: unified currency code
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: an `address structure <https://docs.ccxt_zagrava.com/#/?id=address-structure>`
        """
        self.load_markets()
        currency = self.currency(code)
        request: dict = {
            'coin': currency['id'],
        }
        response = self.privateGetV2DepositAddress(self.extend(request, params))
        #
        #     {"address":"0x97d64eb014ac779194991e7264f01c74c90327f0"}
        #
        return self.parse_deposit_address(response, currency)

    def parse_deposit_address(self, depositAddress, currency: Currency = None):
        address = self.safe_string(depositAddress, 'address')
        self.check_address(address)
        currency = self.safe_currency(None, currency)
        return {
            'currency': currency['code'],
            'address': address,
            'tag': None,
            'network': None,
            'info': depositAddress,
        }

    def sign(self, path, api='public', method='GET', params={}, headers=None, body=None):
        url = self.urls['api'][api] + '/' + path
        if path == 'historicalTrades':
            headers = {
                'X-MBX-APIKEY': self.apiKey,
            }
        if api == 'private':
            self.check_required_credentials()
            query = self.urlencode(self.extend({
                'timestamp': self.nonce(),
                'recvWindow': self.options['recvWindow'],
            }, params))
            signature = self.hmac(self.encode(query), self.encode(self.secret), hashlib.sha256)
            query += '&' + 'signature=' + signature
            headers = {
                'X-MBX-APIKEY': self.apiKey,
            }
            if (method == 'GET') or (method == 'DELETE'):
                url += '?' + query
            else:
                body = query
                headers['Content-Type'] = 'application/x-www-form-urlencoded'
        else:
            if params:
                url += '?' + self.urlencode(params)
        url = self.implode_hostname(url)
        return {'url': url, 'method': method, 'body': body, 'headers': headers}

    def fetch_positions(self, symbols: Strings = None, params={}):
        """
        fetch all open positions
        :see: https://apitradedoc.currency.com/swagger-ui.html#/rest-api/tradingPositionsUsingGET
        :param str[]|None symbols: list of unified market symbols
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict[]: a list of `position structure <https://docs.ccxt_zagrava.com/#/?id=position-structure>`
        """
        self.load_markets()
        response = self.privateGetV2TradingPositions(params)
        #
        #    {
        #        "positions": [
        #          {
        #            "accountId": "109698017416453793",
        #            "id": "00a18490-0079-54c4-0000-0000803e73d3",
        #            "instrumentId": "45463225268524228",
        #            "orderId": "00a18490-0079-54c4-0000-0000803e73d2",
        #            "openQuantity": "13.6",
        #            "openPrice": "0.75724",
        #            "closeQuantity": "0.0",
        #            "closePrice": "0",
        #            "rpl": "-0.007723848",
        #            "rplConverted": "0",
        #            "upl": "-0.006664",
        #            "uplConverted": "-0.006664",
        #            "swap": "0",
        #            "swapConverted": "0",
        #            "fee": "-0.007723848",
        #            "dividend": "0",
        #            "margin": "0.2",
        #            "state": "ACTIVE",
        #            "currency": "USD",
        #            "createdTimestamp": "1645473877236",
        #            "openTimestamp": "1645473877193",
        #            "type": "NET",
        #            "cost": "2.0583600",
        #            "symbol": "XRP/USD_LEVERAGE"
        #          }
        #        ]
        #    }
        #
        data = self.safe_list(response, 'positions', [])
        return self.parse_positions(data, symbols)

    def parse_position(self, position: dict, market: Market = None):
        #
        #    {
        #        "accountId": "109698017416453793",
        #        "id": "00a18490-0079-54c4-0000-0000803e73d3",
        #        "instrumentId": "45463225268524228",
        #        "orderId": "00a18490-0079-54c4-0000-0000803e73d2",
        #        "openQuantity": "13.6",
        #        "openPrice": "0.75724",
        #        "closeQuantity": "0.0",
        #        "closePrice": "0",
        #        "rpl": "-0.007723848",
        #        "rplConverted": "0",
        #        "upl": "-0.006664",
        #        "uplConverted": "-0.006664",
        #        "swap": "0",
        #        "swapConverted": "0",
        #        "fee": "-0.007723848",
        #        "dividend": "0",
        #        "margin": "0.2",
        #        "state": "ACTIVE",
        #        "currency": "USD",
        #        "createdTimestamp": "1645473877236",
        #        "openTimestamp": "1645473877193",
        #        "type": "NET",
        #        "cost": "2.0583600",
        #        "symbol": "XRP/USD_LEVERAGE"
        #    }
        #
        market = self.safe_market(self.safe_string(position, 'symbol'), market)
        symbol = market['symbol']
        timestamp = self.safe_integer(position, 'createdTimestamp')
        quantityRaw = self.safe_string(position, 'openQuantity')
        side = 'long' if Precise.string_gt(quantityRaw, '0') else 'short'
        quantity = Precise.string_abs(quantityRaw)
        entryPrice = self.safe_number(position, 'openPrice')
        unrealizedProfit = self.safe_number(position, 'upl')
        marginCoeff = self.safe_string(position, 'margin')
        leverage = Precise.string_div('1', marginCoeff)
        return self.safe_position({
            'info': position,
            'symbol': symbol,
            'timestamp': timestamp,
            'datetime': self.iso8601(timestamp),
            'lastUpdateTimestamp': None,
            'contracts': self.parse_number(quantity),
            'contractSize': None,
            'entryPrice': entryPrice,
            'collateral': None,
            'side': side,
            # 'realizedProfit': self.safe_number(position, 'rpl'),
            'unrealizedProfit': unrealizedProfit,
            'leverage': leverage,
            'percentage': None,
            'marginMode': None,
            'notional': None,
            'markPrice': None,
            'lastPrice': None,
            'liquidationPrice': None,
            'initialMargin': None,
            'initialMarginPercentage': None,
            'maintenanceMargin': self.parse_number(marginCoeff),
            'maintenanceMarginPercentage': None,
            'marginRatio': None,
            'id': None,
            'unrealizedPnl': None,
            'hedged': None,
            'stopLossPrice': None,
            'takeProfitPrice': None,
        })

    def handle_errors(self, httpCode: int, reason: str, url: str, method: str, headers: dict, body: str, response, requestHeaders, requestBody):
        if (httpCode == 418) or (httpCode == 429):
            raise DDoSProtection(self.id + ' ' + str(httpCode) + ' ' + reason + ' ' + body)
        # error response in a form: {"code": -1013, "msg": "Invalid quantity."}
        # following block cointains legacy checks against message patterns in "msg" property
        # will switch "code" checks eventually, when we know all of them
        if httpCode >= 400:
            if body.find('Price * QTY is zero or less') >= 0:
                raise InvalidOrder(self.id + ' order cost = amount * price is zero or less ' + body)
            if body.find('LOT_SIZE') >= 0:
                raise InvalidOrder(self.id + ' order amount should be evenly divisible by lot size ' + body)
            if body.find('PRICE_FILTER') >= 0:
                raise InvalidOrder(self.id + ' order price is invalid, i.e. exceeds allowed price precision, exceeds min price or max price limits or is invalid float value in general, use self.price_to_precision(symbol, amount) ' + body)
        if response is None:
            return None  # fallback to default error handler
        #
        #     {"code":-1128,"msg":"Combination of optional parameters invalid."}
        #
        errorCode = self.safe_string(response, 'code')
        if (errorCode is not None) and (errorCode != '0'):
            feedback = self.id + ' ' + self.json(response)
            self.throw_exactly_matched_exception(self.exceptions['exact'], errorCode, feedback)
            message = self.safe_string(response, 'msg')
            self.throw_broadly_matched_exception(self.exceptions['broad'], message, feedback)
            raise ExchangeError(feedback)
        return None
