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

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

from ccxt.async_support.base.exchange import Exchange
import hashlib
from ccxt.base.errors import ExchangeError
from ccxt.base.errors import AuthenticationError
from ccxt.base.errors import PermissionDenied
from ccxt.base.errors import AccountNotEnabled
from ccxt.base.errors import ArgumentsRequired
from ccxt.base.errors import BadRequest
from ccxt.base.errors import BadSymbol
from ccxt.base.errors import InsufficientFunds
from ccxt.base.errors import InvalidAddress
from ccxt.base.errors import InvalidOrder
from ccxt.base.errors import OrderNotFound
from ccxt.base.errors import NotSupported
from ccxt.base.errors import RateLimitExceeded
from ccxt.base.decimal_to_precision import TICK_SIZE
from ccxt.base.precise import Precise


class mexc(Exchange):

    def describe(self):
        return self.deep_extend(super(mexc, self).describe(), {
            'id': 'mexc',
            'name': 'MEXC Global',
            'countries': ['SC'],  # Seychelles
            'rateLimit': 50,  # default rate limit is 20 times per second
            'version': 'v2',
            'certified': True,
            'pro': True,
            'has': {
                'CORS': None,
                'spot': True,
                'margin': None,  # has but unimplemented
                'swap': True,
                'future': False,
                'option': False,
                'addMargin': True,
                'cancelAllOrders': True,
                'cancelOrder': True,
                'createMarketOrder': False,
                'createOrder': True,
                'createReduceOnlyOrder': False,
                'createStopLimitOrder': True,
                'createStopMarketOrder': False,
                'createStopOrder': True,
                'fetchBalance': True,
                'fetchCanceledOrders': True,
                'fetchClosedOrders': True,
                'fetchCurrencies': True,
                'fetchDepositAddress': True,
                'fetchDepositAddressesByNetwork': True,
                'fetchDeposits': True,
                'fetchFundingHistory': True,
                'fetchFundingRate': True,
                'fetchFundingRateHistory': True,
                'fetchFundingRates': False,
                'fetchIndexOHLCV': True,
                'fetchLeverage': None,
                'fetchLeverageTiers': True,
                'fetchMarginMode': False,
                'fetchMarketLeverageTiers': 'emulated',
                'fetchMarkets': True,
                'fetchMarkOHLCV': True,
                'fetchMyTrades': True,
                'fetchOHLCV': True,
                'fetchOpenInterestHistory': False,
                'fetchOpenOrders': True,
                'fetchOrder': True,
                'fetchOrderBook': True,
                'fetchOrderTrades': True,
                'fetchPosition': True,
                'fetchPositionMode': True,
                'fetchPositions': True,
                'fetchPositionsRisk': False,
                'fetchPremiumIndexOHLCV': True,
                'fetchStatus': True,
                'fetchTicker': True,
                'fetchTickers': True,
                'fetchTime': True,
                'fetchTrades': True,
                'fetchTradingFee': False,
                'fetchTradingFees': True,
                'fetchTransfer': True,
                'fetchTransfers': True,
                'fetchWithdrawals': True,
                'reduceMargin': True,
                'setLeverage': True,
                'setMarginMode': False,
                'setPositionMode': True,
                'transfer': True,
                'withdraw': True,
            },
            'timeframes': {
                '1m': '1m',
                '5m': '5m',
                '15m': '15m',
                '30m': '30m',
                '1h': '1h',
                '1d': '1d',
                '1w': '1w',
                '1M': '1M',
            },
            'urls': {
                'logo': 'https://user-images.githubusercontent.com/1294454/137283979-8b2a818d-8633-461b-bfca-de89e8c446b2.jpg',
                'api': {
                    'spot': {
                        'public': 'https://www.mexc.com/open/api/v2',
                        'private': 'https://www.mexc.com/open/api/v2',
                    },
                    'contract': {
                        'public': 'https://contract.mexc.com/api/v1/contract',
                        'private': 'https://contract.mexc.com/api/v1/private',
                    },
                },
                'www': 'https://www.mexc.com/',
                'doc': [
                    'https://mxcdevelop.github.io/APIDoc/',
                ],
                'fees': [
                    'https://www.mexc.com/fee',
                ],
                'referral': 'https://m.mexc.com/auth/signup?inviteCode=1FQ1G',
            },
            'api': {
                'contract': {
                    'public': {
                        'get': {
                            'ping': 2,
                            'detail': 2,
                            'support_currencies': 2,
                            'depth/{symbol}': 2,
                            'depth_commits/{symbol}/{limit}': 2,
                            'index_price/{symbol}': 2,
                            'fair_price/{symbol}': 2,
                            'funding_rate/{symbol}': 2,
                            'kline/{symbol}': 2,
                            'kline/index_price/{symbol}': 2,
                            'kline/fair_price/{symbol}': 2,
                            'deals/{symbol}': 2,
                            'ticker': 2,
                            'risk_reverse': 2,
                            'risk_reverse/history': 2,
                            'funding_rate/history': 2,
                        },
                    },
                    'private': {
                        'get': {
                            'account/assets': 2,
                            'account/asset/{currency}': 2,
                            'account/transfer_record': 2,
                            'position/list/history_positions': 2,
                            'position/open_positions': 2,
                            'position/funding_records': 2,
                            'position/position_mode': 2,
                            'order/list/open_orders/{symbol}': 2,
                            'order/list/history_orders': 2,
                            'order/external/{symbol}/{external_oid}': 2,
                            'order/get/{order_id}': 2,
                            'order/batch_query': 8,
                            'order/deal_details/{order_id}': 2,
                            'order/list/order_deals': 2,
                            'planorder/list/orders': 2,
                            'stoporder/list/orders': 2,
                            'stoporder/order_details/{stop_order_id}': 2,
                            'account/risk_limit': 2,
                            'account/tiered_fee_rate': 2,
                        },
                        'post': {
                            'position/change_margin': 2,
                            'position/change_leverage': 2,
                            'position/change_position_mode': 2,
                            'order/submit': 2,
                            'order/submit_batch': 40,
                            'order/cancel': 2,
                            'order/cancel_with_external': 2,
                            'order/cancel_all': 2,
                            'account/change_risk_level': 2,
                            'planorder/place': 2,
                            'planorder/cancel': 2,
                            'planorder/cancel_all': 2,
                            'stoporder/cancel': 2,
                            'stoporder/cancel_all': 2,
                            'stoporder/change_price': 2,
                            'stoporder/change_plan_price': 2,
                        },
                    },
                },
                'spot': {
                    'public': {
                        'get': {
                            'market/symbols': 1,
                            'market/coin/list': 2,
                            'common/timestamp': 1,
                            'common/ping': 1,
                            'market/ticker': 1,
                            'market/depth': 1,
                            'market/deals': 1,
                            'market/kline': 1,
                            'market/api_default_symbols': 2,
                        },
                    },
                    'private': {
                        'get': {
                            'account/info': 1,
                            'order/open_orders': 1,
                            'order/list': 1,
                            'order/query': 1,
                            'order/deals': 1,
                            'order/deal_detail': 1,
                            'asset/deposit/address/list': 2,
                            'asset/deposit/list': 2,
                            'asset/address/list': 2,
                            'asset/withdraw/list': 2,
                            'asset/internal/transfer/record': 10,
                            'account/balance': 10,
                            'asset/internal/transfer/info': 10,
                            'market/api_symbols': 2,
                        },
                        'post': {
                            'order/place': 1,
                            'order/place_batch': 1,
                            'asset/withdraw': 2,
                            'asset/internal/transfer': 10,
                        },
                        'delete': {
                            'order/cancel': 1,
                            'order/cancel_by_symbol': 1,
                            'asset/withdraw': 2,
                        },
                    },
                },
            },
            'precisionMode': TICK_SIZE,
            'fees': {
                'trading': {
                    'tierBased': False,
                    'percentage': True,
                    'maker': self.parse_number('0.002'),  # maker / taker
                    'taker': self.parse_number('0.002'),
                },
            },
            'options': {
                'timeframes': {
                    'spot': {
                        '1m': '1m',
                        '5m': '5m',
                        '15m': '15m',
                        '30m': '30m',
                        '1h': '1h',
                        '1d': '1d',
                        '1M': '1M',
                    },
                    'contract': {
                        '1m': 'Min1',
                        '5m': 'Min5',
                        '15m': 'Min15',
                        '30m': 'Min30',
                        '1h': 'Min60',
                        '4h': 'Hour4',
                        '8h': 'Hour8',
                        '1d': 'Day1',
                        '1w': 'Week1',
                        '1M': 'Month1',
                    },
                },
                'defaultType': 'spot',  # spot, swap
                'networks': {
                    'TRX': 'TRC20',
                    'ETH': 'ERC20',
                    'BEP20': 'BEP20(BSC)',
                    'BSC': 'BEP20(BSC)',
                },
                'accountsByType': {
                    'spot': 'MAIN',
                    'swap': 'CONTRACT',
                },
                'transfer': {
                    'accountsById': {
                        'MAIN': 'spot',
                        'CONTRACT': 'swap',
                    },
                    'status': {
                        'SUCCESS': 'ok',
                        'FAILED': 'failed',
                        'WAIT': 'pending',
                    },
                },
                'fetchOrdersByState': {
                    'method': 'spotPrivateGetOrderList',  # contractPrivateGetPlanorderListOrders
                },
                'cancelOrder': {
                    'method': 'spotPrivateDeleteOrderCancel',  # contractPrivatePostOrderCancel contractPrivatePostPlanorderCancel
                },
            },
            'commonCurrencies': {
                'BEYONDPROTOCOL': 'BEYOND',
                'BIFI': 'BIFIF',
                'BYN': 'BeyondFi',
                'COFI': 'COFIX',  # conflict with CoinFi
                'DFI': 'DfiStarter',
                'DFT': 'dFuture',
                'DRK': 'DRK',
                'EGC': 'Egoras Credit',
                'FLUX1': 'FLUX',  # switched places
                'FLUX': 'FLUX1',  # switched places
                'FREE': 'FreeRossDAO',  # conflict with FREE Coin
                'GMT': 'GMT Token',
                'HERO': 'Step Hero',  # conflict with Metahero
                'MIMO': 'Mimosa',
                'PROS': 'Pros.Finance',  # conflict with Prosper
                'SIN': 'Sin City Token',
                'SOUL': 'Soul Swap',
                'STEPN': 'GMT',
            },
            'exceptions': {
                'exact': {
                    '400': BadRequest,  # Invalid parameter
                    '401': AuthenticationError,  # Invalid signature, fail to pass the validation
                    '402': AuthenticationError,  # {"success":false,"code":402,"message":"API key expired!"}
                    '403': PermissionDenied,  # {"msg":"no permission to access the endpoint","code":403}
                    '429': RateLimitExceeded,  # too many requests, rate limit rule is violated
                    '703': PermissionDenied,  # Require trade read permission!
                    '1000': AccountNotEnabled,  # {"success":false,"code":1000,"message":"Please open contract account first!"}
                    '1002': InvalidOrder,  # {"success":false,"code":1002,"message":"Contract not allow place order!"}
                    '10072': AuthenticationError,  # Invalid access key
                    '10073': AuthenticationError,  # Invalid request time
                    '10075': PermissionDenied,  # {"msg":"IP [xxx.xxx.xxx.xxx] not in the ip white list","code":10075}
                    '10101': InsufficientFunds,  # {"code":10101,"msg":"Insufficient balance"}
                    '10216': InvalidAddress,  # {"code":10216,"msg":"No available deposit address"}
                    '10232': BadSymbol,  # {"code":10232,"msg":"The currency not exist"}
                    '30000': BadSymbol,  # Trading is suspended for the requested symbol
                    '30001': InvalidOrder,  # Current trading type(bid or ask) is not allowed
                    '30002': InvalidOrder,  # Invalid trading amount, smaller than the symbol minimum trading amount
                    '30003': InvalidOrder,  # Invalid trading amount, greater than the symbol maximum trading amount
                    '30004': InsufficientFunds,  # Insufficient balance
                    '30005': InvalidOrder,  # Oversell error
                    '30010': InvalidOrder,  # Price out of allowed range
                    '30014': BadSymbol,  # {"msg":"invalid symbol","code":30014}
                    '30016': BadSymbol,  # Market is closed
                    '30019': InvalidOrder,  # Orders count over limit for batch processing
                    '30020': BadSymbol,  # Restricted symbol, API access is not allowed for the time being
                    '30021': BadSymbol,  # Invalid symbol
                    '33333': BadSymbol,  # {"code":33333,"msg":"currency can not be null"}
                },
                'broad': {
                    'price and quantity must be positive': InvalidOrder,  # {"msg":"price and quantity must be positive","code":400}
                },
            },
        })

    async def fetch_time(self, params={}):
        """
        fetches the current integer timestamp in milliseconds from the exchange server
        :param dict params: extra parameters specific to the mexc api endpoint
        :returns int: the current integer timestamp in milliseconds from the exchange server
        """
        marketType, query = self.handle_market_type_and_params('fetchTime', None, params)
        method = self.get_supported_mapping(marketType, {
            'spot': 'spotPublicGetCommonTimestamp',
            'swap': 'contractPublicGetPing',
        })
        response = await getattr(self, method)(self.extend(query))
        #
        # spot
        #
        #     {
        #         "code":200,
        #         "data":1633375641837
        #     }
        #
        # contract
        #
        #     {
        #         "success":true,
        #         "code":0,
        #         "data":1634095541710
        #     }
        #
        return self.safe_integer(response, 'data')

    async def fetch_status(self, params={}):
        """
        the latest known information on the availability of the exchange API
        :param dict params: extra parameters specific to the mexc api endpoint
        :returns dict: a `status structure <https://docs.ccxt.com/en/latest/manual.html#exchange-status-structure>`
        """
        response = await self.spotPublicGetCommonPing(params)
        #
        #     {"code":200}
        #
        code = self.safe_integer(response, 'code')
        status = 'ok' if (code == 200) else 'maintenance'
        return {
            'status': status,
            'updated': None,
            'eta': None,
            'url': None,
            'info': response,
        }

    async def fetch_currencies(self, params={}):
        """
        fetches all available currencies on an exchange
        :param dict params: extra parameters specific to the mexc api endpoint
        :returns dict: an associative dictionary of currencies
        """
        response = await self.spotPublicGetMarketCoinList(params)
        #
        #     {
        #         "code":200,
        #         "data":[
        #             {
        #                 "currency":"AGLD",
        #                 "coins":[
        #                     {
        #                         "chain":"ERC20",
        #                         "precision":18,
        #                         "fee":8.09,
        #                         "is_withdraw_enabled":true,
        #                         "is_deposit_enabled":true,
        #                         "deposit_min_confirm":16,
        #                         "withdraw_limit_max":500000.0,
        #                         "withdraw_limit_min":14.0
        #                     }
        #                 ],
        #                 "full_name":"Adventure Gold"
        #             },
        #         ]
        #     }
        #
        data = self.safe_value(response, 'data', [])
        result = {}
        for i in range(0, len(data)):
            currency = data[i]
            id = self.safe_string(currency, 'currency')
            code = self.safe_currency_code(id)
            name = self.safe_string(currency, 'full_name')
            currencyActive = False
            minPrecision = None
            currencyFee = None
            currencyWithdrawMin = None
            currencyWithdrawMax = None
            networks = {}
            chains = self.safe_value(currency, 'coins', [])
            depositEnabled = False
            withdrawEnabled = False
            for j in range(0, len(chains)):
                chain = chains[j]
                networkId = self.safe_string(chain, 'chain')
                network = self.safe_network(networkId)
                isDepositEnabled = self.safe_value(chain, 'is_deposit_enabled', False)
                isWithdrawEnabled = self.safe_value(chain, 'is_withdraw_enabled', False)
                active = (isDepositEnabled and isWithdrawEnabled)
                currencyActive = active or currencyActive
                withdrawMin = self.safe_string(chain, 'withdraw_limit_min')
                withdrawMax = self.safe_string(chain, 'withdraw_limit_max')
                currencyWithdrawMin = withdrawMin if (currencyWithdrawMin is None) else currencyWithdrawMin
                currencyWithdrawMax = withdrawMax if (currencyWithdrawMax is None) else currencyWithdrawMax
                if Precise.string_gt(currencyWithdrawMin, withdrawMin):
                    currencyWithdrawMin = withdrawMin
                if Precise.string_lt(currencyWithdrawMax, withdrawMax):
                    currencyWithdrawMax = withdrawMax
                if isDepositEnabled:
                    depositEnabled = True
                if isWithdrawEnabled:
                    withdrawEnabled = True
                precision = self.parse_precision(self.safe_string(chain, 'precision'))
                if precision is not None:
                    minPrecision = precision if (minPrecision is None) else Precise.string_min(precision, minPrecision)
                networks[network] = {
                    'info': chain,
                    'id': networkId,
                    'network': network,
                    'active': active,
                    'deposit': isDepositEnabled,
                    'withdraw': isWithdrawEnabled,
                    'fee': self.safe_number(chain, 'fee'),
                    'precision': self.parse_number(minPrecision),
                    'limits': {
                        'withdraw': {
                            'min': withdrawMin,
                            'max': withdrawMax,
                        },
                    },
                }
            networkKeys = list(networks.keys())
            networkKeysLength = len(networkKeys)
            if (networkKeysLength == 1) or ('NONE' in networks):
                defaultNetwork = self.safe_value_2(networks, 'NONE', networkKeysLength - 1)
                if defaultNetwork is not None:
                    currencyFee = defaultNetwork['fee']
            result[code] = {
                'id': id,
                'code': code,
                'info': currency,
                'name': name,
                'active': currencyActive,
                'deposit': depositEnabled,
                'withdraw': withdrawEnabled,
                'fee': currencyFee,
                'precision': self.parse_number(minPrecision),
                'limits': {
                    'amount': {
                        'min': None,
                        'max': None,
                    },
                    'withdraw': {
                        'min': currencyWithdrawMin,
                        'max': currencyWithdrawMax,
                    },
                },
                'networks': networks,
            }
        return result

    async def fetch_markets(self, params={}):
        """
        retrieves data on all markets for mexc
        :param dict params: extra parameters specific to the exchange api endpoint
        :returns [dict]: an array of objects representing market data
        """
        defaultType = self.safe_string_2(self.options, 'fetchMarkets', 'defaultType', 'spot')
        type = self.safe_string(params, 'type', defaultType)
        query = self.omit(params, 'type')
        spot = (type == 'spot')
        swap = (type == 'swap')
        if not spot and not swap:
            raise ExchangeError(self.id + " does not support '" + type + "' type, set exchange.options['defaultType'] to 'spot' or 'swap''")  # eslint-disable-line quotes
        if spot:
            return await self.fetch_spot_markets(query)
        elif swap:
            return await self.fetch_contract_markets(query)

    async def fetch_contract_markets(self, params={}):
        response = await self.contractPublicGetDetail(params)
        #
        #     {
        #         "success":true,
        #         "code":0,
        #         "data":[
        #             {
        #                 "symbol":"BTC_USDT",
        #                 "displayName":"BTC_USDT永续",
        #                 "displayNameEn":"BTC_USDT SWAP",
        #                 "positionOpenType":3,
        #                 "baseCoin":"BTC",
        #                 "quoteCoin":"USDT",
        #                 "settleCoin":"USDT",
        #                 "contractSize":0.0001,
        #                 "minLeverage":1,
        #                 "maxLeverage":125,
        #                 "priceScale":2,
        #                 "volScale":0,
        #                 "amountScale":4,
        #                 "priceUnit":0.5,
        #                 "volUnit":1,
        #                 "minVol":1,
        #                 "maxVol":1000000,
        #                 "bidLimitPriceRate":0.1,
        #                 "askLimitPriceRate":0.1,
        #                 "takerFeeRate":0.0006,
        #                 "makerFeeRate":0.0002,
        #                 "maintenanceMarginRate":0.004,
        #                 "initialMarginRate":0.008,
        #                 "riskBaseVol":10000,
        #                 "riskIncrVol":200000,
        #                 "riskIncrMmr":0.004,
        #                 "riskIncrImr":0.004,
        #                 "riskLevelLimit":5,
        #                 "priceCoefficientVariation":0.1,
        #                 "indexOrigin":["BINANCE","GATEIO","HUOBI","MXC"],
        #                 "state":0,  # 0 enabled, 1 delivery, 2 completed, 3 offline, 4 pause
        #                 "isNew":false,
        #                 "isHot":true,
        #                 "isHidden":false
        #             },
        #         ]
        #     }
        #
        data = self.safe_value(response, 'data', [])
        result = []
        for i in range(0, len(data)):
            market = data[i]
            id = self.safe_string(market, 'symbol')
            baseId = self.safe_string(market, 'baseCoin')
            quoteId = self.safe_string(market, 'quoteCoin')
            settleId = self.safe_string(market, 'settleCoin')
            base = self.safe_currency_code(baseId)
            quote = self.safe_currency_code(quoteId)
            settle = self.safe_currency_code(settleId)
            state = self.safe_string(market, 'state')
            result.append({
                'id': id,
                'symbol': base + '/' + quote + ':' + settle,
                'base': base,
                'quote': quote,
                'settle': settle,
                'baseId': baseId,
                'quoteId': quoteId,
                'settleId': settleId,
                'type': 'swap',
                'spot': False,
                'margin': False,
                'swap': True,
                'future': False,
                'option': False,
                'active': (state == '0'),
                'contract': True,
                'linear': True,
                'inverse': False,
                'taker': self.safe_number(market, 'takerFeeRate'),
                'maker': self.safe_number(market, 'makerFeeRate'),
                'contractSize': self.safe_number(market, 'contractSize'),
                'expiry': None,
                'expiryDatetime': None,
                'strike': None,
                'optionType': None,
                'precision': {
                    'amount': self.safe_number(market, 'volUnit'),
                    'price': self.safe_number(market, 'priceUnit'),
                },
                'limits': {
                    'leverage': {
                        'min': self.safe_number(market, 'minLeverage'),
                        'max': self.safe_number(market, 'maxLeverage'),
                    },
                    'amount': {
                        'min': self.safe_number(market, 'minVol'),
                        'max': self.safe_number(market, 'maxVol'),
                    },
                    'price': {
                        'min': None,
                        'max': None,
                    },
                    'cost': {
                        'min': None,
                        'max': None,
                    },
                },
                'info': market,
            })
        return result

    async def fetch_spot_markets(self, params={}):
        response = await self.spotPublicGetMarketSymbols(params)
        #
        #     {
        #         "code":200,
        #         "data":[
        #             {
        #                 "symbol":"DFD_USDT",
        #                 "state":"ENABLED",
        #                 "countDownMark":1,
        #                 "vcoinName":"DFD",
        #                 "vcoinStatus":1,
        #                 "price_scale":4,
        #                 "quantity_scale":2,
        #                 "min_amount":"5",  # not an amount = cost
        #                 "max_amount":"5000000",
        #                 "maker_fee_rate":"0.002",
        #                 "taker_fee_rate":"0.002",
        #                 "limited":true,
        #                 "etf_mark":0,
        #                 "symbol_partition":"ASSESS"
        #             },
        #         ]
        #     }
        #
        data = self.safe_value(response, 'data', [])
        response2 = await self.spotPublicGetMarketApiDefaultSymbols(params)
        #
        #     {
        #         "code":200,
        #         "data":{
        #             "symbol":[
        #                 "ALEPH_USDT","OGN_USDT","HC_USDT",
        #              ]
        #         }
        #     }
        #
        data2 = self.safe_value(response2, 'data', {})
        symbols = self.safe_value(data2, 'symbol', [])
        result = []
        for i in range(0, len(data)):
            market = data[i]
            id = self.safe_string(market, 'symbol')
            baseId, quoteId = id.split('_')
            base = self.safe_currency_code(baseId)
            quote = self.safe_currency_code(quoteId)
            state = self.safe_string(market, 'state')
            active = False
            for j in range(0, len(symbols)):
                if symbols[j] == id:
                    if state == 'ENABLED':
                        active = True
                    break
            result.append({
                'id': id,
                'symbol': base + '/' + quote,
                'base': base,
                'quote': quote,
                'settle': None,
                'baseId': baseId,
                'quoteId': quoteId,
                'settleId': None,
                'type': 'spot',
                'spot': True,
                'margin': False,
                'swap': False,
                'future': False,
                'option': False,
                'active': active,
                'contract': False,
                'linear': None,
                'inverse': None,
                'taker': self.safe_number(market, 'taker_fee_rate'),
                'maker': self.safe_number(market, 'maker_fee_rate'),
                'contractSize': None,
                'expiry': None,
                'expiryDatetime': None,
                'strike': None,
                'optionType': None,
                'precision': {
                    'amount': self.parse_number(self.parse_precision(self.safe_string(market, 'quantity_scale'))),
                    'price': self.parse_number(self.parse_precision(self.safe_string(market, 'price_scale'))),
                },
                'limits': {
                    'leverage': {
                        'min': None,
                        'max': None,
                    },
                    'amount': {
                        'min': None,
                        'max': None,
                    },
                    'price': {
                        'min': None,
                        'max': None,
                    },
                    'cost': {
                        'min': self.safe_number(market, 'min_amount'),
                        'max': self.safe_number(market, 'max_amount'),
                    },
                },
                'info': market,
            })
        return result

    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 mexc api endpoint
        :returns dict: an array of `ticker structures <https://docs.ccxt.com/en/latest/manual.html#ticker-structure>`
        """
        await self.load_markets()
        marketType, query = self.handle_market_type_and_params('fetchTickers', None, params)
        method = self.get_supported_mapping(marketType, {
            'spot': 'spotPublicGetMarketTicker',
            'swap': 'contractPublicGetTicker',
        })
        response = await getattr(self, method)(self.extend(query))
        #
        #     {
        #         "success":true,
        #         "code":0,
        #         "data":[
        #             {
        #                 "symbol":"NKN_USDT",
        #                 "lastPrice":0.36199,
        #                 "bid1":0.35908,
        #                 "ask1":0.36277,
        #                 "volume24":657754,
        #                 "amount24":239024.53998,
        #                 "holdVol":149969,
        #                 "lower24Price":0.34957,
        #                 "high24Price":0.37689,
        #                 "riseFallRate":0.0117,
        #                 "riseFallValue":0.00419,
        #                 "indexPrice":0.36043,
        #                 "fairPrice":0.36108,
        #                 "fundingRate":0.000535,
        #                 "maxBidPrice":0.43251,
        #                 "minAskPrice":0.28834,
        #                 "timestamp":1634163352075
        #             },
        #         ]
        #     }
        #
        data = self.safe_value(response, 'data', [])
        return self.parse_tickers(data, symbols)

    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 mexc 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 = {
            'symbol': market['id'],
        }
        method = None
        if market['spot']:
            method = 'spotPublicGetMarketTicker'
        elif market['swap']:
            method = 'contractPublicGetTicker'
        response = await getattr(self, method)(self.extend(request, params))
        #
        # spot
        #
        #     {
        #         "code":200,
        #         "data":[
        #             {
        #                 "symbol":"BTC_USDT",
        #                 "volume":"880.821523",
        #                 "high":"49496.95",  # highest price over the past 24 hours
        #                 "low":"46918.4",  # lowest
        #                 "bid":"49297.64",  # current buying price == the best price you can sell for
        #                 "ask":"49297.75",  # current selling price == the best price you can buy for
        #                 "open":"48764.9",  # open price 24h ago
        #                 "last":"49297.73",  # last = close
        #                 "time":1633378200000,  # timestamp
        #                 "change_rate":"0.0109265"  #(last / open) - 1
        #             }
        #         ]
        #     }
        #
        # swap / contract
        #
        #     {
        #         "success":true,
        #         "code":0,
        #         "data":{
        #             "symbol":"ETH_USDT",
        #             "lastPrice":3581.3,
        #             "bid1":3581.25,
        #             "ask1":3581.5,
        #             "volume24":4045530,
        #             "amount24":141331823.5755,
        #             "holdVol":5832946,
        #             "lower24Price":3413.4,
        #             "high24Price":3588.7,
        #             "riseFallRate":0.0275,
        #             "riseFallValue":95.95,
        #             "indexPrice":3580.7852,
        #             "fairPrice":3581.08,
        #             "fundingRate":0.000063,
        #             "maxBidPrice":3938.85,
        #             "minAskPrice":3222.7,
        #             "timestamp":1634162885016
        #         }
        #     }
        #
        if market['spot']:
            data = self.safe_value(response, 'data', [])
            ticker = self.safe_value(data, 0)
            return self.parse_ticker(ticker, market)
        elif market['swap']:
            data = self.safe_value(response, 'data', {})
            return self.parse_ticker(data, market)

    def parse_ticker(self, ticker, market=None):
        #
        # spot
        #
        #     {
        #         "symbol":"BTC_USDT",
        #         "volume":"880.821523",
        #         "high":"49496.95",
        #         "low":"46918.4",
        #         "bid":"49297.64",
        #         "ask":"49297.75",
        #         "open":"48764.9",
        #         "last":"49297.73",
        #         "time":1633378200000,
        #         "change_rate":"0.0109265"
        #     }
        #
        # contract
        #
        #     {
        #         "symbol":"ETH_USDT",
        #         "lastPrice":3581.3,
        #         "bid1":3581.25,
        #         "ask1":3581.5,
        #         "volume24":4045530,
        #         "amount24":141331823.5755,
        #         "holdVol":5832946,
        #         "lower24Price":3413.4,
        #         "high24Price":3588.7,
        #         "riseFallRate":0.0275,
        #         "riseFallValue":95.95,
        #         "indexPrice":3580.7852,
        #         "fairPrice":3581.08,
        #         "fundingRate":0.000063,
        #         "maxBidPrice":3938.85,
        #         "minAskPrice":3222.7,
        #         "timestamp":1634162885016
        #     }
        #
        timestamp = self.safe_integer_2(ticker, 'time', 'timestamp')
        marketId = self.safe_string(ticker, 'symbol')
        symbol = self.safe_symbol(marketId, market, '_')
        baseVolume = self.safe_string_2(ticker, 'volume', 'volume24')
        quoteVolume = self.safe_string(ticker, 'amount24')
        open = self.safe_string(ticker, 'open')
        last = self.safe_string_2(ticker, 'last', 'lastPrice')
        change = self.safe_string(ticker, 'riseFallValue')
        riseFallRate = self.safe_string(ticker, 'riseFallRate')
        percentage = Precise.string_add(riseFallRate, '1')
        return self.safe_ticker({
            'symbol': symbol,
            'timestamp': timestamp,
            'datetime': self.iso8601(timestamp),
            'high': self.safe_string_2(ticker, 'high', 'high24Price'),
            'low': self.safe_string_2(ticker, 'low', 'lower24Price'),
            'bid': self.safe_string_2(ticker, 'bid', 'bid1'),
            'bidVolume': None,
            'ask': self.safe_string_2(ticker, 'ask', 'ask1'),
            'askVolume': None,
            'vwap': None,
            'open': open,
            'close': last,
            'last': last,
            'previousClose': None,
            'change': change,
            'percentage': percentage,
            'average': None,
            'baseVolume': baseVolume,
            'quoteVolume': quoteVolume,
            'info': ticker,
        }, market)

    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 mexc 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 = {
            'symbol': market['id'],
        }
        method = None
        if market['spot']:
            method = 'spotPublicGetMarketDepth'
            if limit is None:
                limit = 100  # the spot api requires a limit
            request['depth'] = limit
        elif market['swap']:
            method = 'contractPublicGetDepthSymbol'
            if limit is not None:
                request['limit'] = limit
        response = await getattr(self, method)(self.extend(request, params))
        #
        # spot
        #
        #     {
        #         "code":200,
        #         "data":{
        #             "asks":[
        #                 {"price":"49060.56","quantity":"0.099842"},
        #                 {"price":"49060.58","quantity":"0.016003"},
        #                 {"price":"49060.6","quantity":"0.023677"}
        #             ],
        #             "bids":[
        #                 {"price":"49060.45","quantity":"1.693009"},
        #                 {"price":"49060.44","quantity":"0.000843"},
        #                 {"price":"49059.98","quantity":"0.735"},
        #             ],
        #             "version":"202454074",
        #         }
        #     }
        #
        # swap / contract
        #
        #     {
        #         "success":true,
        #         "code":0,
        #         "data":{
        #             "asks":[
        #                 [3445.7,48379,1],
        #                 [3445.75,34994,1],
        #                 [3445.8,68634,2],
        #             ],
        #             "bids":[
        #                 [3445.55,44081,1],
        #                 [3445.5,24857,1],
        #                 [3445.45,50272,1],
        #             ],
        #             "version":2827730444,
        #             "timestamp":1634117846232
        #         }
        #     }
        #
        data = self.safe_value(response, 'data', {})
        priceKey = 'price' if market['spot'] else 0
        amountKey = 'quantity' if market['spot'] else 1
        timestamp = self.safe_integer(data, 'timestamp')
        orderbook = self.parse_order_book(data, symbol, timestamp, 'bids', 'asks', priceKey, amountKey)
        orderbook['nonce'] = self.safe_integer(data, 'version')
        return orderbook

    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 mexc 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 = {
            'symbol': market['id'],
        }
        if limit is not None:
            request['limit'] = limit  # default 100, max 100
        method = None
        if market['spot']:
            method = 'spotPublicGetMarketDeals'
        elif market['swap']:
            method = 'contractPublicGetDealsSymbol'
        response = await getattr(self, method)(self.extend(request, params))
        #
        # spot
        #
        #     {
        #         "code":200,
        #         "data":[
        #             {"trade_time":1633381766725,"trade_price":"0.068981","trade_quantity":"0.005","trade_type":"BID"},
        #             {"trade_time":1633381732705,"trade_price":"0.068979","trade_quantity":"0.006","trade_type":"BID"},
        #             {"trade_time":1633381694604,"trade_price":"0.068975","trade_quantity":"0.011","trade_type":"ASK"},
        #         ]
        #     }
        #
        # swap / contract
        #
        #     {
        #         "success":true,
        #         "code":0,
        #         "data":[
        #             {"p":3598.85,"v":52,"T":1,"O":2,"M":2,"t":1634169038038},
        #             {"p":3599.2,"v":15,"T":2,"O":3,"M":1,"t":1634169035603},
        #             {"p":3600.15,"v":229,"T":2,"O":1,"M":2,"t":1634169026354},
        #         ]
        #     }
        #
        data = self.safe_value(response, 'data', [])
        return self.parse_trades(data, market, since, limit)

    def parse_trade(self, trade, market=None):
        #
        # public fetchTrades
        #
        #     spot
        #
        #     {
        #         "trade_time":1633381766725,
        #         "trade_price":"0.068981",
        #         "trade_quantity":"0.005",
        #         "trade_type":"BID"
        #     }
        #
        #     swap / contract
        #
        #     {
        #         "p":3598.85,
        #         "v":52,
        #         "T":1,  # 1 buy, 2 sell
        #         "O":2,  # 1 opens a position, 2 does not open a position
        #         "M":2,  # self-trading, 1 yes, 2 no
        #         "t":1634169038038
        #     }
        #
        # private fetchMyTrades, fetchOrderTrades
        #
        #     {
        #         "id":"b160b8f072d9403e96289139d5544809",
        #         "symbol":"USDC_USDT",
        #         "quantity":"150",
        #         "price":"0.9997",
        #         "amount":"149.955",
        #         "fee":"0.29991",
        #         "trade_type":"ASK",
        #         "order_id":"d798765285374222990bbd14decb86cd",
        #         "is_taker":true,
        #         "fee_currency":"USDT",
        #         "create_time":1633984904000
        #     }
        #
        timestamp = self.safe_integer_2(trade, 'create_time', 'trade_time')
        timestamp = self.safe_integer(trade, 't', timestamp)
        marketId = self.safe_string(trade, 'symbol')
        market = self.safe_market(marketId, market, '_')
        symbol = market['symbol']
        priceString = self.safe_string_2(trade, 'price', 'trade_price')
        priceString = self.safe_string(trade, 'p', priceString)
        amountString = self.safe_string_2(trade, 'quantity', 'trade_quantity')
        amountString = self.safe_string(trade, 'v', amountString)
        costString = self.safe_string(trade, 'amount')
        side = self.safe_string_2(trade, 'trade_type', 'T')
        if (side == 'BID') or (side == '1'):
            side = 'buy'
        elif (side == 'ASK') or (side == '2'):
            side = 'sell'
        id = self.safe_string_2(trade, 'id', 'trade_time')
        if id is None:
            id = self.safe_string(trade, 't', id)
            if id is not None:
                id += '-' + market['id'] + '-' + amountString
        feeCostString = self.safe_string(trade, 'fee')
        fee = None
        if feeCostString is not None:
            feeCurrencyId = self.safe_string(trade, 'fee_currency')
            feeCurrencyCode = self.safe_currency_code(feeCurrencyId)
            fee = {
                'cost': feeCostString,
                'currency': feeCurrencyCode,
            }
        orderId = self.safe_string(trade, 'order_id')
        isTaker = self.safe_value(trade, 'is_taker', True)
        takerOrMaker = 'taker' if isTaker else 'maker'
        return self.safe_trade({
            'info': trade,
            'id': id,
            'order': orderId,
            'timestamp': timestamp,
            'datetime': self.iso8601(timestamp),
            'symbol': symbol,
            'type': None,
            'side': side,
            'takerOrMaker': takerOrMaker,
            'price': priceString,
            'amount': amountString,
            'cost': costString,
            'fee': fee,
        }, market)

    async def fetch_trading_fees(self, params={}):
        """
        fetch the trading fees for multiple markets
        :param dict params: extra parameters specific to the mexc api endpoint
        :returns dict: a dictionary of `fee structures <https://docs.ccxt.com/en/latest/manual.html#fee-structure>` indexed by market symbols
        """
        await self.load_markets()
        response = await self.spotPublicGetMarketSymbols(params)
        #
        #     {
        #         "code":200,
        #         "data":[
        #             {
        #                 "symbol":"DFD_USDT",
        #                 "state":"ENABLED",
        #                 "countDownMark":1,
        #                 "vcoinName":"DFD",
        #                 "vcoinStatus":1,
        #                 "price_scale":4,
        #                 "quantity_scale":2,
        #                 "min_amount":"5",  # not an amount = cost
        #                 "max_amount":"5000000",
        #                 "maker_fee_rate":"0.002",
        #                 "taker_fee_rate":"0.002",
        #                 "limited":true,
        #                 "etf_mark":0,
        #                 "symbol_partition":"ASSESS"
        #             },
        #             ...
        #         ]
        #     }
        #
        data = self.safe_value(response, 'data', [])
        result = {}
        for i in range(0, len(data)):
            fee = data[i]
            marketId = self.safe_string(fee, 'symbol')
            market = self.safe_market(marketId, None, '_')
            symbol = market['symbol']
            result[symbol] = {
                'info': fee,
                'symbol': symbol,
                'maker': self.safe_number(fee, 'maker_fee_rate'),
                'taker': self.safe_number(fee, 'taker_fee_rate'),
                'percentage': True,
                'tierBased': False,
            }
        return result

    async def fetch_ohlcv(self, symbol, timeframe='1m', since=None, limit=None, params={}):
        """
        fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
        :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|None since: timestamp in ms of the earliest candle to fetch
        :param int|None limit: the maximum amount of candles to fetch
        :param dict params: extra parameters specific to the mexc api endpoint
        :returns [[int]]: A list of candles ordered as timestamp, open, high, low, close, volume
        """
        await self.load_markets()
        market = self.market(symbol)
        options = self.safe_value(self.options, 'timeframes', {})
        timeframes = self.safe_value(options, market['type'], {})
        timeframeValue = self.safe_string(timeframes, timeframe)
        if timeframeValue is None:
            raise NotSupported(self.id + ' fetchOHLCV() does not support ' + timeframe + ' timeframe for ' + market['type'] + ' markets')
        request = {
            'symbol': market['id'],
            'interval': timeframeValue,
        }
        method = None
        if market['spot']:
            method = 'spotPublicGetMarketKline'
            if since is not None:
                request['start_time'] = int(since / 1000)
            if limit is not None:
                request['limit'] = limit  # default 100
        elif market['swap']:
            method = 'contractPublicGetKlineSymbol'
            if since is not None:
                request['start'] = int(since / 1000)
            # request['end'] = self.seconds()
        response = await getattr(self, method)(self.extend(request, params))
        #
        # spot
        #
        #     {
        #         "code":200,
        #         "data":[
        #             [1633377000,"49227.47","49186.21","49227.47","49169.48","0.5984809999999999","29434.259665989997"],
        #             [1633377060,"49186.21","49187.03","49206.64","49169.18","0.3658478","17990.651234393"],
        #             [1633377120,"49187.03","49227.2","49227.2","49174.4","0.0687651","3382.353190352"],
        #         ],
        #     }
        #
        # swap / contract
        #
        #     {
        #         "success":true,
        #         "code":0,
        #         "data":{
        #             "time":[1634052300,1634052360,1634052420],
        #             "open":[3492.2,3491.3,3495.65],
        #             "close":[3491.3,3495.65,3495.2],
        #             "high":[3495.85,3496.55,3499.4],
        #             "low":[3491.15,3490.9,3494.2],
        #             "vol":[1740.0,351.0,314.0],
        #             "amount":[60793.623,12260.4885,10983.1375],
        #         }
        #     }
        #
        if market['spot']:
            data = self.safe_value(response, 'data', [])
            return self.parse_ohlcvs(data, market, timeframe, since, limit)
        elif market['swap']:
            data = self.safe_value(response, 'data', {})
            result = self.convert_trading_view_to_ohlcv(data, 'time', 'open', 'high', 'low', 'close', 'vol')
            return self.parse_ohlcvs(result, market, timeframe, since, limit)

    def parse_ohlcv(self, ohlcv, market=None):
        #
        # the ordering in spot candles is OCHLV
        #
        #     [
        #         1633377000,  # 0 timestamp(unix seconds)
        #         "49227.47",  # 1 open price
        #         "49186.21",  # 2 closing price
        #         "49227.47",  # 3 high
        #         "49169.48",  # 4 low
        #         "0.5984809999999999",  # 5 base volume
        #         "29434.259665989997",  # 6 quote volume
        #     ]
        #
        # the ordering in swap / contract candles is OHLCV
        #
        return [
            self.safe_timestamp(ohlcv, 0),
            self.safe_number(ohlcv, 1),
            self.safe_number(ohlcv, 3 if market['spot'] else 2),
            self.safe_number(ohlcv, 4 if market['spot'] else 3),
            self.safe_number(ohlcv, 2 if market['spot'] else 4),
            self.safe_number(ohlcv, 5),
        ]

    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 mexc api endpoint
        :returns dict: a `balance structure <https://docs.ccxt.com/en/latest/manual.html?#balance-structure>`
        """
        await self.load_markets()
        marketType, query = self.handle_market_type_and_params('fetchBalance', None, params)
        method = self.get_supported_mapping(marketType, {
            'spot': 'spotPrivateGetAccountInfo',
            'margin': 'spotPrivateGetAccountInfo',
            'swap': 'contractPrivateGetAccountAssets',
        })
        spot = (marketType == 'spot')
        response = await getattr(self, method)(query)
        #
        # spot
        #
        #     {
        #         code: "200",
        #         data: {
        #             USDC: {frozen: "0", available: "150"}
        #         }
        #     }
        #
        # swap / contract
        #
        #     {
        #         "success":true,
        #         "code":0,
        #         "data":[
        #             {"currency":"BSV","positionMargin":0,"availableBalance":0,"cashBalance":0,"frozenBalance":0,"equity":0,"unrealized":0,"bonus":0},
        #             {"currency":"BCH","positionMargin":0,"availableBalance":0,"cashBalance":0,"frozenBalance":0,"equity":0,"unrealized":0,"bonus":0},
        #             {"currency":"CRV","positionMargin":0,"availableBalance":0,"cashBalance":0,"frozenBalance":0,"equity":0,"unrealized":0,"bonus":0},
        #         ]
        #     }
        #
        data = self.safe_value(response, 'data', {})
        currentTime = self.milliseconds()
        result = {
            'info': response,
            'timestamp': currentTime,
            'datetime': self.iso8601(currentTime),
        }
        if spot:
            currencyIds = list(data.keys())
            for i in range(0, len(currencyIds)):
                currencyId = currencyIds[i]
                code = self.safe_currency_code(currencyId)
                balance = self.safe_value(data, currencyId, {})
                account = self.account()
                account['free'] = self.safe_string(balance, 'available')
                account['used'] = self.safe_string(balance, 'frozen')
                result[code] = account
        else:
            for i in range(0, len(data)):
                balance = data[i]
                currencyId = self.safe_string(balance, 'currency')
                code = self.safe_currency_code(currencyId)
                account = self.account()
                account['free'] = self.safe_string(balance, 'availableBalance')
                account['used'] = self.safe_string(balance, 'frozenBalance')
                result[code] = account
        return self.safe_balance(result)

    def safe_network(self, networkId):
        if networkId.find('BSC') >= 0:
            return 'BEP20'
        parts = networkId.split(' ')
        networkId = ''.join(parts)
        networkId = networkId.replace('-20', '20')
        networksById = {
            'ETH': 'ETH',
            'ERC20': 'ERC20',
            'BEP20(BSC)': 'BEP20',
            'TRX': 'TRC20',
        }
        return self.safe_string(networksById, networkId, networkId)

    def parse_deposit_address(self, depositAddress, currency=None):
        #
        #     {"chain":"ERC-20","address":"0x55cbd73db24eafcca97369e3f2db74b2490586e6"},
        #     {"chain":"MATIC","address":"0x05aa3236f1970eae0f8feb17ec19435b39574d74"},
        #     {"chain":"TRC20","address":"TGaPfhW41EXD3sAfs1grLF6DKfugfqANNw"},
        #     {"chain":"SOL","address":"5FSpUKuh2gjw4mF89T2e7sEjzUA1SkRKjBChFqP43KhV"},
        #     {"chain":"ALGO","address":"B3XTZND2JJTSYR7R2TQVCUDT4QSSYVAIZYDPWVBX34DGAYATBU3AUV43VU"}
        #
        #
        address = self.safe_string(depositAddress, 'address')
        code = self.safe_currency_code(None, currency)
        networkId = self.safe_string(depositAddress, 'chain')
        network = self.safe_network(networkId)
        self.check_address(address)
        return {
            'currency': code,
            'address': address,
            'tag': None,
            'network': network,
            'info': depositAddress,
        }

    async def fetch_deposit_addresses_by_network(self, code, params={}):
        """
        fetch a dictionary of addresses for a currency, indexed by network
        :param str code: unified currency code of the currency for the deposit address
        :param dict params: extra parameters specific to the mexc api endpoint
        :returns dict: a dictionary of `address structures <https://docs.ccxt.com/en/latest/manual.html#address-structure>` indexed by the network
        """
        await self.load_markets()
        currency = self.currency(code)
        request = {
            'currency': currency['id'],
        }
        response = await self.spotPrivateGetAssetDepositAddressList(self.extend(request, params))
        #
        #     {
        #         "code":200,
        #         "data":{
        #             "currency":"USDC",
        #             "chains":[
        #                 {"chain":"ERC-20","address":"0x55cbd73db24eafcca97369e3f2db74b2490586e6"},
        #                 {"chain":"MATIC","address":"0x05aa3236f1970eae0f8feb17ec19435b39574d74"},
        #                 {"chain":"TRC20","address":"TGaPfhW41EXD3sAfs1grLF6DKfugfqANNw"},
        #                 {"chain":"SOL","address":"5FSpUKuh2gjw4mF89T2e7sEjzUA1SkRKjBChFqP43KhV"},
        #                 {"chain":"ALGO","address":"B3XTZND2JJTSYR7R2TQVCUDT4QSSYVAIZYDPWVBX34DGAYATBU3AUV43VU"}
        #             ]
        #         }
        #     }
        #
        data = self.safe_value(response, 'data', {})
        chains = self.safe_value(data, 'chains', [])
        depositAddresses = []
        for i in range(0, len(chains)):
            depositAddress = self.parse_deposit_address(chains[i], currency)
            depositAddresses.append(depositAddress)
        return self.index_by(depositAddresses, 'network')

    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 mexc api endpoint
        :returns dict: an `address structure <https://docs.ccxt.com/en/latest/manual.html#address-structure>`
        """
        rawNetwork = self.safe_string_upper(params, 'network')
        params = self.omit(params, 'network')
        response = await self.fetch_deposit_addresses_by_network(code, params)
        networks = self.safe_value(self.options, 'networks', {})
        network = self.safe_string(networks, rawNetwork, rawNetwork)
        result = None
        if network is None:
            result = self.safe_value(response, code)
            if result is None:
                alias = self.safe_string(networks, code, code)
                result = self.safe_value(response, alias)
                if result is None:
                    defaultNetwork = self.safe_string(self.options, 'defaultNetwork', 'ERC20')
                    result = self.safe_value(response, defaultNetwork)
                    if result is None:
                        values = list(response.values())
                        result = self.safe_value(values, 0)
                        if result is None:
                            raise InvalidAddress(self.id + ' fetchDepositAddress() cannot find deposit address for ' + code)
            return result
        # TODO: add support for all aliases here
        result = self.safe_value(response, rawNetwork)
        if result is None:
            raise InvalidAddress(self.id + ' fetchDepositAddress() cannot find ' + network + ' deposit address for ' + code)
        return result

    async def fetch_deposits(self, code=None, since=None, limit=None, params={}):
        """
        fetch all deposits made to an account
        :param str|None code: unified currency code
        :param int|None since: the earliest time in ms to fetch deposits for
        :param int|None limit: the maximum number of deposits structures to retrieve
        :param dict params: extra parameters specific to the mexc api endpoint
        :returns [dict]: a list of `transaction structures <https://docs.ccxt.com/en/latest/manual.html#transaction-structure>`
        """
        await self.load_markets()
        request = {
            # 'currency': currency['id'],
            # 'state': 'state',
            # 'start_time': since,  # default 1 day
            # 'end_time': self.milliseconds(),
            # 'page_num': 1,
            # 'page_size': limit,  # default 20, maximum 50
        }
        currency = None
        if code is not None:
            currency = self.currency(code)
            request['currency'] = currency['id']
        if since is not None:
            request['start_time'] = since
        if limit is not None:
            request['limit'] = limit
        response = await self.spotPrivateGetAssetDepositList(self.extend(request, params))
        #
        #     {
        #         "code":200,
        #         "data":{
        #             "page_size":20,
        #             "total_page":1,
        #             "total_size":1,
        #             "page_num":1,
        #             "result_list":[
        #                 {
        #                     "currency":"USDC",
        #                     "amount":150.0,
        #                     "fee":0.0,
        #                     "confirmations":19,
        #                     "address":"0x55cbd73db24eafcca97369e3f2db74b2490586e6",
        #                     "state":"SUCCESS",
        #                     "tx_id":"0xc65a9b09e1b71def81bf8bb3ec724c0c1b2b4c82200c8c142e4ea4c1469fd789:0",
        #                     "require_confirmations":12,
        #                     "create_time":"2021-10-11T18:58:25.000+00:00",
        #                     "update_time":"2021-10-11T19:01:06.000+00:00"
        #                 }
        #             ]
        #         }
        #     }
        #
        data = self.safe_value(response, 'data', {})
        resultList = self.safe_value(data, 'result_list', [])
        return self.parse_transactions(resultList, currency, since, limit)

    async def fetch_withdrawals(self, code=None, since=None, limit=None, params={}):
        """
        fetch all withdrawals made from an account
        :param str|None code: unified currency code
        :param int|None since: the earliest time in ms to fetch withdrawals for
        :param int|None limit: the maximum number of withdrawals structures to retrieve
        :param dict params: extra parameters specific to the mexc api endpoint
        :returns [dict]: a list of `transaction structures <https://docs.ccxt.com/en/latest/manual.html#transaction-structure>`
        """
        await self.load_markets()
        request = {
            # 'withdrawal_id': '4b450616042a48c99dd45cacb4b092a7',  # string
            # 'currency': currency['id'],
            # 'state': 'state',
            # 'start_time': since,  # default 1 day
            # 'end_time': self.milliseconds(),
            # 'page_num': 1,
            # 'page_size': limit,  # default 20, maximum 50
        }
        currency = None
        if code is not None:
            currency = self.currency(code)
            request['currency'] = currency['id']
        if since is not None:
            request['start_time'] = since
        if limit is not None:
            request['limit'] = limit
        response = await self.spotPrivateGetAssetWithdrawList(self.extend(request, params))
        #
        #     {
        #         "code":200,
        #         "data":{
        #             "page_size":20,
        #             "total_page":1,
        #             "total_size":1,
        #             "page_num":1,
        #             "result_list":[
        #                 {
        #                     "id":"4b450616042a48c99dd45cacb4b092a7",
        #                     "currency":"USDT-TRX",
        #                     "address":"TRHKnx74Gb8UVcpDCMwzZVe4NqXfkdtPak",
        #                     "amount":30.0,
        #                     "fee":1.0,
        #                     "remark":"self is my first withdrawal remark",
        #                     "state":"WAIT",
        #                     "create_time":"2021-10-11T20:45:08.000+00:00"
        #                 }
        #             ]
        #         }
        #     }
        #
        data = self.safe_value(response, 'data', {})
        resultList = self.safe_value(data, 'result_list', [])
        return self.parse_transactions(resultList, currency, since, limit)

    def parse_transaction(self, transaction, currency=None):
        #
        # fetchDeposits
        #
        #     {
        #         "currency":"USDC",
        #         "amount":150.0,
        #         "fee":0.0,
        #         "confirmations":19,
        #         "address":"0x55cbd73db24eafcca97369e3f2db74b2490586e6",
        #         "state":"SUCCESS",
        #         "tx_id":"0xc65a9b09e1b71def81bf8bb3ec724c0c1b2b4c82200c8c142e4ea4c1469fd789:0",
        #         "require_confirmations":12,
        #         "create_time":"2021-10-11T18:58:25.000+00:00",
        #         "update_time":"2021-10-11T19:01:06.000+00:00"
        #     }
        #
        # fetchWithdrawals
        #
        #     {
        #         "id":"4b450616042a48c99dd45cacb4b092a7",
        #         "currency":"USDT-TRX",
        #         "address":"TRHKnx74Gb8UVcpDCMwzZVe4NqXfkdtPak",
        #         "amount":30.0,
        #         "fee":1.0,
        #         "remark":"self is my first withdrawal remark",
        #         "state":"WAIT",
        #         "create_time":"2021-10-11T20:45:08.000+00:00"
        #     }
        #
        id = self.safe_string(transaction, 'id')
        type = 'deposit' if (id is None) else 'withdrawal'
        timestamp = self.parse8601(self.safe_string(transaction, 'create_time'))
        updated = self.parse8601(self.safe_string(transaction, 'update_time'))
        currencyId = self.safe_string(transaction, 'currency')
        network = None
        if (currencyId is not None) and (currencyId.find('-') >= 0):
            parts = currencyId.split('-')
            currencyId = self.safe_string(parts, 0)
            networkId = self.safe_string(parts, 1)
            network = self.safe_network(networkId)
        code = self.safe_currency_code(currencyId, currency)
        status = self.parse_transaction_status(self.safe_string(transaction, 'state'))
        amountString = self.safe_string(transaction, 'amount')
        address = self.safe_string(transaction, 'address')
        txid = self.safe_string(transaction, 'tx_id')
        fee = None
        feeCostString = self.safe_string(transaction, 'fee')
        if feeCostString is not None:
            fee = {
                'cost': self.parse_number(feeCostString),
                'currency': code,
            }
        if type == 'withdrawal':
            # mexc withdrawal amount includes the fee
            amountString = Precise.string_sub(amountString, feeCostString)
        return {
            'info': transaction,
            'id': id,
            'txid': txid,
            'timestamp': timestamp,
            'datetime': self.iso8601(timestamp),
            'network': network,
            'address': address,
            'addressTo': None,
            'addressFrom': None,
            'tag': None,
            'tagTo': None,
            'tagFrom': None,
            'type': type,
            'amount': self.parse_number(amountString),
            'currency': code,
            'status': status,
            'updated': updated,
            'fee': fee,
        }

    def parse_transaction_status(self, status):
        statuses = {
            'WAIT': 'pending',
            'WAIT_PACKAGING': 'pending',
            'SUCCESS': 'ok',
        }
        return self.safe_string(statuses, status, status)

    async def fetch_position(self, symbol, params={}):
        """
        fetch data on a single open contract trade position
        :param str symbol: unified market symbol of the market the position is held in, default is None
        :param dict params: extra parameters specific to the mexc api endpoint
        :returns dict: a `position structure <https://docs.ccxt.com/en/latest/manual.html#position-structure>`
        """
        await self.load_markets()
        market = self.market(symbol)
        request = {
            'symbol': market['id'],
        }
        response = await self.fetch_positions(self.extend(request, params))
        firstPosition = self.safe_value(response, 0)
        return self.parse_position(firstPosition, market)

    async def fetch_positions(self, symbols=None, params={}):
        """
        fetch all open positions
        :param [str]|None symbols: list of unified market symbols
        :param dict params: extra parameters specific to the mexc api endpoint
        :returns [dict]: a list of `position structure <https://docs.ccxt.com/en/latest/manual.html#position-structure>`
        """
        await self.load_markets()
        response = await self.contractPrivateGetPositionOpenPositions(params)
        #
        #     {
        #         "success": True,
        #         "code": 0,
        #         "data": [
        #             {
        #                 "positionId": 1394650,
        #                 "symbol": "ETH_USDT",
        #                 "positionType": 1,
        #                 "openType": 1,
        #                 "state": 1,
        #                 "holdVol": 1,
        #                 "frozenVol": 0,
        #                 "closeVol": 0,
        #                 "holdAvgPrice": 1217.3,
        #                 "openAvgPrice": 1217.3,
        #                 "closeAvgPrice": 0,
        #                 "liquidatePrice": 1211.2,
        #                 "oim": 0.1290338,
        #                 "im": 0.1290338,
        #                 "holdFee": 0,
        #                 "realised": -0.0073,
        #                 "leverage": 100,
        #                 "createTime": 1609991676000,
        #                 "updateTime": 1609991676000,
        #                 "autoAddIm": False
        #             }
        #         ]
        #     }
        #
        data = self.safe_value(response, 'data', [])
        return self.parse_positions(data, symbols)

    def parse_position(self, position, market=None):
        #
        #     {
        #         "positionId": 1394650,
        #         "symbol": "ETH_USDT",
        #         "positionType": 1,
        #         "openType": 1,
        #         "state": 1,
        #         "holdVol": 1,
        #         "frozenVol": 0,
        #         "closeVol": 0,
        #         "holdAvgPrice": 1217.3,
        #         "openAvgPrice": 1217.3,
        #         "closeAvgPrice": 0,
        #         "liquidatePrice": 1211.2,
        #         "oim": 0.1290338,
        #         "im": 0.1290338,
        #         "holdFee": 0,
        #         "realised": -0.0073,
        #         "leverage": 100,
        #         "createTime": 1609991676000,
        #         "updateTime": 1609991676000,
        #         "autoAddIm": False
        #     }
        #
        market = self.safe_market(self.safe_string(position, 'symbol'), market)
        symbol = market['symbol']
        contracts = self.safe_string(position, 'holdVol')
        entryPrice = self.safe_number(position, 'openAvgPrice')
        initialMargin = self.safe_string(position, 'im')
        rawSide = self.safe_string(position, 'positionType')
        side = 'long' if (rawSide == '1') else 'short'
        openType = self.safe_string(position, 'margin_mode')
        marginMode = 'isolated' if (openType == '1') else 'cross'
        leverage = self.safe_string(position, 'leverage')
        liquidationPrice = self.safe_number(position, 'liquidatePrice')
        timestamp = self.safe_number(position, 'updateTime')
        return {
            'info': position,
            'symbol': symbol,
            'contracts': self.parse_number(contracts),
            'contractSize': None,
            'entryPrice': entryPrice,
            'collateral': None,
            'side': side,
            'unrealizedProfit': None,
            'leverage': self.parse_number(leverage),
            'percentage': None,
            'marginMode': marginMode,
            'notional': None,
            'markPrice': None,
            'liquidationPrice': liquidationPrice,
            'initialMargin': self.parse_number(initialMargin),
            'initialMarginPercentage': None,
            'maintenanceMargin': None,
            'maintenanceMarginPercentage': None,
            'marginRatio': None,
            'timestamp': timestamp,
            'datetime': self.iso8601(timestamp),
        }

    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 mexc 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)
        marketType, query = self.handle_market_type_and_params('createOrder', market, params)
        if marketType == 'spot':
            return await self.create_spot_order(symbol, type, side, amount, price, query)
        elif marketType == 'swap':
            return await self.create_swap_order(symbol, type, side, amount, price, query)

    async def create_spot_order(self, symbol, type, side, amount, price=None, params={}):
        await self.load_markets()
        market = self.market(symbol)
        orderSide = None
        if side == 'buy':
            orderSide = 'BID'
        elif side == 'sell':
            orderSide = 'ASK'
        orderType = type.upper()
        isMarketOrder = orderType == 'MARKET'
        if isMarketOrder:
            raise InvalidOrder(self.id + ' createOrder() does not support market orders, only limit orders are allowed')
        if orderType == 'LIMIT':
            orderType = 'LIMIT_ORDER'
        postOnly = self.is_post_only(isMarketOrder, orderType == 'POST_ONLY', params)
        timeInForce = self.safe_string_upper(params, 'timeInForce')
        ioc = (timeInForce == 'IOC')
        if postOnly:
            orderType = 'POST_ONLY'
        elif ioc:
            orderType = 'IMMEDIATE_OR_CANCEL'
        if timeInForce == 'FOK':
            raise InvalidOrder(self.id + ' createOrder() does not support timeInForce FOK, only IOC, PO, and GTC are allowed')
        if ((orderType != 'POST_ONLY') and (orderType != 'IMMEDIATE_OR_CANCEL') and (orderType != 'LIMIT_ORDER')):
            raise InvalidOrder(self.id + ' createOrder() does not support ' + type + ' order type, only LIMIT, LIMIT_ORDER, POST_ONLY or IMMEDIATE_OR_CANCEL are allowed')
        request = {
            'symbol': market['id'],
            'price': self.price_to_precision(symbol, price),
            'quantity': self.amount_to_precision(symbol, amount),
            'trade_type': orderSide,
            'order_type': orderType,  # LIMIT_ORDER，POST_ONLY，IMMEDIATE_OR_CANCEL
        }
        clientOrderId = self.safe_string_2(params, 'clientOrderId', 'client_order_id')
        if clientOrderId is not None:
            request['client_order_id'] = clientOrderId
        params = self.omit(params, ['type', 'clientOrderId', 'client_order_id', 'postOnly', 'timeInForce'])
        response = await self.spotPrivatePostOrderPlace(self.extend(request, params))
        #
        #     {"code":200,"data":"2ff3163e8617443cb9c6fc19d42b1ca4"}
        #
        return self.parse_order(response, market)

    async def create_swap_order(self, symbol, type, side, amount, price=None, params={}):
        await self.load_markets()
        market = self.market(symbol)
        openType = self.safe_integer(params, 'openType')
        if openType is None:
            raise ArgumentsRequired(self.id + ' createSwapOrder() requires an integer openType parameter, 1 for isolated margin, 2 for cross margin')
        if (type != 'limit') and (type != 'market') and (type != 1) and (type != 2) and (type != 3) and (type != 4) and (type != 5) and (type != 6):
            raise InvalidOrder(self.id + ' createSwapOrder() order type must either limit, market, or 1 for limit orders, 2 for post-only orders, 3 for IOC orders, 4 for FOK orders, 5 for market orders or 6 to convert market price to current price')
        isMarketOrder = (type == 'market') or (type == 5)
        postOnly = self.is_post_only(isMarketOrder, type == 2, params)
        if postOnly:
            type = 2
        elif type == 'limit':
            type = 1
        elif type == 'market':
            type = 5
        timeInForce = self.safe_string_upper(params, 'timeInForce')
        ioc = (timeInForce == 'IOC')
        fok = (timeInForce == 'FOK')
        if ioc:
            type = 3
        elif fok:
            type = 4
        if (side != 1) and (side != 2) and (side != 3) and (side != 4):
            raise InvalidOrder(self.id + ' createSwapOrder() order side must be 1 open long, 2 close short, 3 open short or 4 close long')
        request = {
            'symbol': market['id'],
            # 'price': float(self.price_to_precision(symbol, price)),
            'vol': float(self.amount_to_precision(symbol, amount)),
            # 'leverage': int,  # required for isolated margin
            'side': side,  # 1 open long, 2 close short, 3 open short, 4 close long
            #
            # supported order types
            #
            #     1 limit
            #     2 post only maker(PO)
            #     3 transact or cancel instantly(IOC)
            #     4 transact completely or cancel completely(FOK)
            #     5 market orders
            #     6 convert market price to current price
            #
            'type': type,
            'openType': openType,  # 1 isolated, 2 cross
            # 'positionId': 1394650,  # long, filling in self parameter when closing a position is recommended
            # 'externalOid': clientOrderId,
            # 'triggerPrice': 10.0,  # Required for trigger order
            # 'triggerType': 1,  # Required for trigger order 1: more than or equal, 2: less than or equal
            # 'executeCycle': 1,  # Required for trigger order 1: 24 hours,2: 7 days
            # 'trend': 1,  # Required for trigger order 1: latest price, 2: fair price, 3: index price
            # 'orderType': 1,  # Required for trigger order 1: limit order,2:Post Only Maker,3: close or cancel instantly ,4: close or cancel completely,5: Market order
        }
        method = 'contractPrivatePostOrderSubmit'
        stopPrice = self.safe_number_2(params, 'triggerPrice', 'stopPrice')
        params = self.omit(params, ['stopPrice', 'triggerPrice', 'timeInForce', 'postOnly'])
        if stopPrice is not None:
            method = 'contractPrivatePostPlanorderPlace'
            request['triggerPrice'] = self.price_to_precision(symbol, stopPrice)
            request['triggerType'] = self.safe_integer(params, 'triggerType', 1)
            request['executeCycle'] = self.safe_integer(params, 'executeCycle', 1)
            request['trend'] = self.safe_integer(params, 'trend', 1)
            request['orderType'] = self.safe_integer(params, 'orderType', type)
        if (type != 5) and (type != 6) and (type != 'market'):
            request['price'] = float(self.price_to_precision(symbol, price))
        if openType == 1:
            leverage = self.safe_integer(params, 'leverage')
            if leverage is None:
                raise ArgumentsRequired(self.id + ' createSwapOrder() requires a leverage parameter for isolated margin orders')
        clientOrderId = self.safe_string_2(params, 'clientOrderId', 'externalOid')
        if clientOrderId is not None:
            request['externalOid'] = clientOrderId
        params = self.omit(params, ['clientOrderId', 'externalOid'])
        response = await getattr(self, method)(self.extend(request, params))
        #
        # Swap
        #     {"code":200,"data":"2ff3163e8617443cb9c6fc19d42b1ca4"}
        #
        # Trigger
        #     {"success":true,"code":0,"data":259208506303929856}
        #
        return self.parse_order(response, market)

    async def cancel_order(self, id, symbol=None, params={}):
        """
        cancels an open order
        :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 mexc api endpoint
        :returns dict: An `order structure <https://docs.ccxt.com/en/latest/manual.html#order-structure>`
        """
        if symbol is None:
            raise ArgumentsRequired(self.id + ' cancelOrder() requires a symbol argument')
        await self.load_markets()
        market = self.market(symbol)
        options = self.safe_value(self.options, 'cancelOrder', {})
        defaultMethod = self.safe_string(options, 'method', 'spotPrivateDeleteOrderCancel')
        method = self.safe_string(params, 'method', defaultMethod)
        stop = self.safe_value(params, 'stop')
        request = {}
        if market['type'] == 'spot':
            method = 'spotPrivateDeleteOrderCancel'
            clientOrderId = self.safe_string_2(params, 'clientOrderId', 'client_order_ids')
            if clientOrderId is not None:
                params = self.omit(params, ['clientOrderId', 'client_order_ids'])
                request['client_order_ids'] = clientOrderId
            else:
                request['order_ids'] = id
        elif stop:
            method = 'contractPrivatePostPlanorderCancel'
            request = []
            if isinstance(id, list):
                for i in range(0, len(id)):
                    request.append({
                        'symbol': market['id'],
                        'orderId': id[i],
                    })
            elif isinstance(id, str):
                request.append({
                    'symbol': market['id'],
                    'orderId': id,
                })
        elif market['type'] == 'swap':
            method = 'contractPrivatePostOrderCancel'
            request = [id]
        response = await getattr(self, method)(request)  # dont self.extend with params, otherwise ARRAY will be turned into OBJECT
        #
        # Spot
        #
        #     {"code":200,"data":{"965245851c444078a11a7d771323613b":"success"}}
        #
        # Swap
        #
        #     {
        #         "success": True,
        #         "code": 0,
        #         "data": [
        #             {
        #                 "orderId": 268726891790294528,
        #                 "errorCode": 0,
        #                 "errorMsg": "success"
        #             }
        #         ]
        #     }
        #
        # Trigger
        #
        #     {
        #         "success": True,
        #         "code": 0
        #     }
        #
        data = self.safe_value(response, 'data', [])
        if stop:
            data = response
        return self.parse_order(data, market)

    def parse_order_status(self, status, market=None):
        statuses = {}
        if market['type'] == 'spot':
            statuses = {
                'NEW': 'open',
                'FILLED': 'closed',
                'PARTIALLY_FILLED': 'open',
                'CANCELED': 'canceled',
                'PARTIALLY_CANCELED': 'canceled',
            }
        elif market['type'] == 'swap':
            statuses = {
                '2': 'open',
                '3': 'closed',
                '4': 'canceled',
            }
        else:
            statuses = {
                '1': 'open',
                '2': 'canceled',
                '3': 'closed',
            }
        return self.safe_string(statuses, status, status)

    def parse_order(self, order, market=None):
        # TODO update parseOrder to reflect type, timeInForce, and postOnly from fetchOrder()
        #
        # createOrder
        #
        # spot
        #
        #     {"code":200,"data":"2ff3163e8617443cb9c6fc19d42b1ca4"}
        #
        # swap / contract
        #
        #     {"success": True, "code": 0, "data": 102057569836905984}
        #
        # spot fetchOpenOrders
        #
        #     {
        #         "id":"965245851c444078a11a7d771323613b",
        #         "symbol":"ETH_USDT",
        #         "price":"3430",
        #         "quantity":"0.01",
        #         "state":"NEW",
        #         "type":"BID",
        #         "remain_quantity":"0.01",
        #         "remain_amount":"34.3",
        #         "create_time":1633989029039,
        #         "client_order_id":"",
        #         "order_type":"LIMIT_ORDER"
        #     }
        #
        # swap fetchOpenOrders, fetchClosedOrders, fetchCanceledOrders, fetchOrder
        #
        #     {
        #         "orderId": "266578267438402048",
        #         "symbol": "BTC_USDT",
        #         "positionId": 0,
        #         "price": 30000,
        #         "vol": 11,
        #         "leverage": 20,
        #         "side": 1,
        #         "category": 1,
        #         "orderType": 1,
        #         "dealAvgPrice": 0,
        #         "dealVol": 0,
        #         "orderMargin": 1.6896,
        #         "takerFee": 0,
        #         "makerFee": 0,
        #         "profit": 0,
        #         "feeCurrency": "USDT",
        #         "openType": 1,
        #         "state": 2,
        #         "externalOid": "_m_8d673a31c47642d9a59993aca61ae394",
        #         "errorCode": 0,
        #         "usedMargin": 0,
        #         "createTime": 1649227612000,
        #         "updateTime": 1649227611000,
        #         "positionMode": 1
        #     }
        #
        # spot fetchClosedOrders, fetchCanceledOrders, fetchOrder
        #
        #     {
        #         "id":"d798765285374222990bbd14decb86cd",
        #         "symbol":"USDC_USDT",
        #         "price":"0.9988",
        #         "quantity":"150",
        #         "state":"FILLED",  # CANCELED
        #         "type":"ASK",  # BID
        #         "deal_quantity":"150",
        #         "deal_amount":"149.955",
        #         "create_time":1633984904000,
        #         "order_type":"MARKET_ORDER"  # LIMIT_ORDER
        #     }
        #
        # trigger fetchClosedOrders, fetchCanceledOrders, fetchOpenOrders
        #
        #     {
        #         "id": "266583973507973632",
        #         "symbol": "BTC_USDT",
        #         "leverage": 20,
        #         "side": 1,
        #         "triggerPrice": 30000,
        #         "price": 31000,
        #         "vol": 11,
        #         "openType": 1,
        #         "triggerType": 2,
        #         "state": 2,
        #         "executeCycle": 87600,
        #         "trend": 1,
        #         "orderType": 1,
        #         "errorCode": 0,
        #         "createTime": 1649228972000,
        #         "updateTime": 1649230287000
        #     }
        #
        # spot cancelOrder
        #
        #     {"965245851c444078a11a7d771323613b":"success"}
        #
        # swap cancelOrder
        #
        #     {
        #         "orderId": 268726891790294528,
        #         "errorCode": 0,
        #         "errorMsg": "success"
        #     }
        #
        # trigger cancelOrder
        #
        #     {
        #         "success": True,
        #         "code": 0
        #     }
        #
        id = self.safe_string_2(order, 'data', 'id')
        status = None
        if id is None:
            keys = list(order.keys())
            id = self.safe_string(keys, 0)
            state = self.safe_string(order, id)
            if state == 'success':
                status = 'canceled'
        state = self.safe_string(order, 'state')
        timestamp = self.safe_integer_2(order, 'create_time', 'createTime')
        price = self.safe_string(order, 'price')
        amount = self.safe_string_2(order, 'quantity', 'vol')
        remaining = self.safe_string(order, 'remain_quantity')
        filled = self.safe_string_2(order, 'deal_quantity', 'dealVol')
        cost = self.safe_string(order, 'deal_amount')
        marketId = self.safe_string(order, 'symbol')
        symbol = self.safe_symbol(marketId, market, '_')
        sideCheck = self.safe_integer(order, 'side')
        side = None
        bidOrAsk = self.safe_string(order, 'type')
        if bidOrAsk == 'BID':
            side = 'buy'
        elif bidOrAsk == 'ASK':
            side = 'sell'
        if sideCheck == 1:
            side = 'open long'
        elif side == 2:
            side = 'close short'
        elif side == 3:
            side = 'open short'
        elif side == 4:
            side = 'close long'
        status = self.parse_order_status(state, market)
        clientOrderId = self.safe_string_2(order, 'client_order_id', 'orderId')
        rawOrderType = self.safe_string_2(order, 'orderType', 'order_type')
        orderType = None
        # swap: 1:price limited order, 2:Post Only Maker, 3:transact or cancel instantly, 4:transact completely or cancel completely，5:market orders, 6:convert market price to current price
        # spot: LIMIT_ORDER, POST_ONLY, IMMEDIATE_OR_CANCEL
        timeInForce = None
        postOnly = None
        if rawOrderType is not None:
            postOnly = False
            if rawOrderType == '1':
                orderType = 'limit'
                timeInForce = 'GTC'
            elif rawOrderType == '2':
                orderType = 'limit'
                timeInForce = 'PO'
                postOnly = True
            elif rawOrderType == '3':
                orderType = 'limit'
                timeInForce = 'IOC'
            elif rawOrderType == '4':
                orderType = 'limit'
                timeInForce = 'FOK'
            elif (rawOrderType == '5') or (rawOrderType == '6'):
                orderType = 'market'
                timeInForce = 'GTC'
            elif rawOrderType == 'LIMIT_ORDER':
                orderType = 'limit'
                timeInForce = 'GTC'
            elif rawOrderType == 'POST_ONLY':
                orderType = 'limit'
                timeInForce = 'PO'
                postOnly = True
            elif rawOrderType == 'IMMEDIATE_OR_CANCEL':
                orderType = 'limit'
                timeInForce = 'IOC'
        return self.safe_order({
            'id': id,
            'clientOrderId': clientOrderId,
            'timestamp': timestamp,
            'datetime': self.iso8601(timestamp),
            'lastTradeTimestamp': self.safe_integer(order, 'updateTime'),
            'status': status,
            'symbol': symbol,
            'type': orderType,
            'timeInForce': timeInForce,
            'postOnly': postOnly,
            'side': side,
            'price': price,
            'stopPrice': self.safe_string(order, 'triggerPrice'),
            'average': self.safe_string(order, 'dealAvgPrice'),
            'amount': amount,
            'cost': cost,
            'filled': filled,
            'remaining': remaining,
            'fee': None,
            'trades': None,
            'info': order,
        }, market)

    async def fetch_open_orders(self, symbol=None, since=None, limit=None, params={}):
        """
        fetch all unfilled currently open orders
        :param str 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 mexc api endpoint
        :returns [dict]: a list of `order structures <https://docs.ccxt.com/en/latest/manual.html#order-structure>`
        """
        if symbol is None:
            raise ArgumentsRequired(self.id + ' fetchOpenOrders() requires a symbol argument')
        await self.load_markets()
        market = self.market(symbol)
        request = {
            'symbol': market['id'],  # spot, swap
            # 'start_time': since,  # spot
            # 'limit': limit,  # spot default 50, max 1000
            # 'trade_type': 'BID',  # spot BID / ASK
            # 'page_num': 1,  # swap required default 1
            # 'page_size': limit,  # swap required default 20 max 100
            # 'end_time': 1633988662382,  # trigger order
        }
        marketType, query = self.handle_market_type_and_params('fetchOpenOrders', market, params)
        method = self.get_supported_mapping(marketType, {
            'spot': 'spotPrivateGetOrderOpenOrders',
            'swap': 'contractPrivateGetOrderListOpenOrdersSymbol',
        })
        stop = self.safe_value(params, 'stop')
        if stop:
            return await self.fetch_orders_by_state('1', symbol, since, limit, params)
        response = await getattr(self, method)(self.extend(request, query))
        #
        # Spot
        #
        #     {
        #         "code":200,
        #         "data":[
        #             {
        #                 "id":"965245851c444078a11a7d771323613b",
        #                 "symbol":"ETH_USDT",
        #                 "price":"3430",
        #                 "quantity":"0.01",
        #                 "state":"NEW",
        #                 "type":"BID",
        #                 "remain_quantity":"0.01",
        #                 "remain_amount":"34.3",
        #                 "create_time":1633989029039,
        #                 "client_order_id":"",
        #                 "order_type":"LIMIT_ORDER"
        #             },
        #         ]
        #     }
        #
        # Swap
        #
        #     {
        #         "success": True,
        #         "code": 0,
        #         "data": [
        #             {
        #                 "orderId": "266578267438402048",
        #                 "symbol": "BTC_USDT",
        #                 "positionId": 0,
        #                 "price": 30000,
        #                 "vol": 11,
        #                 "leverage": 20,
        #                 "side": 1,
        #                 "category": 1,
        #                 "orderType": 1,
        #                 "dealAvgPrice": 0,
        #                 "dealVol": 0,
        #                 "orderMargin": 1.6896,
        #                 "takerFee": 0,
        #                 "makerFee": 0,
        #                 "profit": 0,
        #                 "feeCurrency": "USDT",
        #                 "openType": 1,
        #                 "state": 2,
        #                 "externalOid": "_m_8d673a31c47642d9a59993aca61ae394",
        #                 "errorCode": 0,
        #                 "usedMargin": 0,
        #                 "createTime": 1649227612000,
        #                 "updateTime": 1649227611000,
        #                 "positionMode": 1
        #             }
        #         ]
        #     }
        #
        # Trigger
        #
        #     {
        #         "success": True,
        #         "code": 0,
        #         "data": [
        #             {
        #                 "id": "267198217203040768",
        #                 "symbol": "BTC_USDT",
        #                 "leverage": 20,
        #                 "side": 1,
        #                 "triggerPrice": 31111,
        #                 "price": 31115,
        #                 "vol": 2,
        #                 "openType": 1,
        #                 "triggerType": 2,
        #                 "state": 1,
        #                 "executeCycle": 87600,
        #                 "trend": 1,
        #                 "orderType": 1,
        #                 "errorCode": 0,
        #                 "createTime": 1649375419000,
        #                 "updateTime": 1649375419000
        #             }
        #         ]
        #     }
        #
        data = self.safe_value(response, 'data', [])
        return self.parse_orders(data, market, since, limit)

    async def fetch_order(self, id, symbol=None, params={}):
        """
        fetches information on an order made by the user
        :param str symbol: unified symbol of the market the order was made in
        :param dict params: extra parameters specific to the mexc api endpoint
        :returns dict: An `order structure <https://docs.ccxt.com/en/latest/manual.html#order-structure>`
        """
        if symbol is None:
            raise ArgumentsRequired(self.id + ' fetchOrder() requires a symbol argument')
        await self.load_markets()
        market = self.market(symbol)
        marketType, query = self.handle_market_type_and_params('fetchOrder', market, params)
        request = {
            'order_ids': id,
        }
        method = self.get_supported_mapping(marketType, {
            'spot': 'spotPrivateGetOrderQuery',
            'swap': 'contractPrivateGetOrderBatchQuery',
        })
        response = await getattr(self, method)(self.extend(request, query))
        #
        # Spot
        #
        #     {
        #         "code":200,
        #         "data":[
        #             {
        #                 "id":"2ff3163e8617443cb9c6fc19d42b1ca4",
        #                 "symbol":"ETH_USDT",
        #                 "price":"3420",
        #                 "quantity":"0.01",
        #                 "state":"CANCELED",
        #                 "type":"BID",
        #                 "deal_quantity":"0",
        #                 "deal_amount":"0",
        #                 "create_time":1633988662000,
        #                 "order_type":"LIMIT_ORDER"
        #             }
        #         ]
        #     }
        #
        # Swap
        #
        #     {
        #         "success": True,
        #         "code": 0,
        #         "data": [
        #             {
        #                 "orderId": "259208506647860224",
        #                 "symbol": "BTC_USDT",
        #                 "positionId": 0,
        #                 "price": 30000,
        #                 "vol": 10,
        #                 "leverage": 20,
        #                 "side": 1,
        #                 "category": 1,
        #                 "orderType": 1,
        #                 "dealAvgPrice": 0,
        #                 "dealVol": 0,
        #                 "orderMargin": 1.536,
        #                 "takerFee": 0,
        #                 "makerFee": 0,
        #                 "profit": 0,
        #                 "feeCurrency": "USDT",
        #                 "openType": 1,
        #                 "state": 4,
        #                 "externalOid": "planorder_279208506303929856_10",
        #                 "errorCode": 0,
        #                 "usedMargin": 0,
        #                 "createTime": 1647470524000,
        #                 "updateTime": 1647470540000,
        #                 "positionMode": 1
        #             }
        #         ]
        #     }
        #
        data = self.safe_value(response, 'data', [])
        firstOrder = self.safe_value(data, 0)
        if firstOrder is None:
            raise OrderNotFound(self.id + ' fetchOrder() could not find the order id ' + id)
        return self.parse_order(firstOrder, market)

    async def fetch_orders_by_state(self, state, symbol=None, since=None, limit=None, params={}):
        if symbol is None:
            raise ArgumentsRequired(self.id + ' fetchOrdersByState() requires a symbol argument')
        await self.load_markets()
        market = self.market(symbol)
        request = {
            'symbol': market['id'],
            # 'start_time': since,  # default 7 days, max 30 days
            # 'limit': limit,  # default 50, max 1000
            # 'trade_type': 'BID',  # BID / ASK
            'states': state,  # NEW, FILLED, PARTIALLY_FILLED, CANCELED, PARTIALLY_CANCELED, trigger orders: 1 untriggered, 2 cancelled, 3 executed, 4 invalid, 5 execution failed
            # 'end_time': 1633988662000,  # trigger orders
            # 'page_num': 1,  # trigger orders default is 1
            # 'page_size': limit,  # trigger orders default 20 max 100
        }
        stop = self.safe_value(params, 'stop')
        limitRequest = 'page_size' if stop else 'limit'
        if limit is not None:
            request[limitRequest] = limit
        if since is not None:
            request['start_time'] = since
        options = self.safe_value(self.options, 'fetchOrdersByState', {})
        defaultMethod = self.safe_string(options, 'method', 'spotPrivateGetOrderList')
        method = self.safe_string(params, 'method', defaultMethod)
        method = self.get_supported_mapping(market['type'], {
            'spot': 'spotPrivateGetOrderList',
            'swap': 'contractPrivateGetOrderListHistoryOrders',
        })
        if stop:
            method = 'contractPrivateGetPlanorderListOrders'
        query = self.omit(params, ['method', 'stop'])
        response = await getattr(self, method)(self.extend(request, query))
        data = self.safe_value(response, 'data', [])
        return self.parse_orders(data, market, since, limit)

    async def fetch_canceled_orders(self, symbol=None, since=None, limit=None, params={}):
        """
        fetches information on multiple canceled orders made by the user
        :param str symbol: unified market symbol of the market orders were made in
        :param int|None since: timestamp in ms of the earliest order, default is None
        :param int|None limit: max number of orders to return, default is None
        :param dict params: extra parameters specific to the mexc api endpoint
        :returns dict: a list of `order structures <https://docs.ccxt.com/en/latest/manual.html#order-structure>`
        """
        if symbol is None:
            raise ArgumentsRequired(self.id + ' fetchCanceledOrders() requires a symbol argument')
        await self.load_markets()
        market = self.market(symbol)
        stop = self.safe_value(params, 'stop')
        state = 'CANCELED'
        if market['type'] == 'swap':
            state = '4'
        elif stop:
            state = '2'
        return await self.fetch_orders_by_state(state, symbol, since, limit, params)

    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 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 mexc api endpoint
        :returns [dict]: a list of `order structures <https://docs.ccxt.com/en/latest/manual.html#order-structure>`
        """
        if symbol is None:
            raise ArgumentsRequired(self.id + ' fetchClosedOrders() requires a symbol argument')
        await self.load_markets()
        market = self.market(symbol)
        stop = self.safe_value(params, 'stop')
        state = 'FILLED'
        if stop or market['type'] == 'swap':
            state = '3'
        return await self.fetch_orders_by_state(state, symbol, since, limit, 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 mexc api endpoint
        :returns [dict]: a list of `order structures <https://docs.ccxt.com/en/latest/manual.html#order-structure>`
        """
        await self.load_markets()
        market = self.market(symbol)
        request = {
            'symbol': market['id'],
        }
        method = self.get_supported_mapping(market['type'], {
            'spot': 'spotPrivateDeleteOrderCancelBySymbol',
            'swap': 'contractPrivatePostOrderCancelAll',
        })
        stop = self.safe_value(params, 'stop')
        if stop:
            method = 'contractPrivatePostPlanorderCancelAll'
        query = self.omit(params, ['method', 'stop'])
        response = await getattr(self, method)(self.extend(request, query))
        #
        # Spot
        #
        #     {
        #         "code": 200,
        #         "data": [
        #             {
        #                 "msg": "success",
        #                 "order_id": "75ecf99feef04538b78e4622beaba6eb",
        #                 "client_order_id": "a9329e86f2094b0d8b58e92c25029554"
        #             },
        #             {
        #                 "msg": "success",
        #                 "order_id": "139413c48f8b4c018f452ce796586bcf"
        #             },
        #             {
        #                 "msg": "success",
        #                 "order_id": "b58ef34c570e4917981f276d44091484"
        #             }
        #         ]
        #     }
        #
        # Swap and Trigger
        #
        #     {
        #         "success": True,
        #         "code": 0
        #     }
        #
        return response

    async def fetch_my_trades(self, symbol=None, since=None, limit=None, params={}):
        """
        fetch all trades made by the user
        :param str 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 mexc api endpoint
        :returns [dict]: a list of `trade structures <https://docs.ccxt.com/en/latest/manual.html#trade-structure>`
        """
        if symbol is None:
            raise ArgumentsRequired(self.id + ' fetchMyTrades() requires a symbol argument')
        await self.load_markets()
        market = self.market(symbol)
        request = {
            'symbol': market['id'],
            # 'start_time': since,  # default 7 days, max 30 days
            # 'limit': limit,  # default 50, max 1000
        }
        if since is not None:
            request['start_time'] = since
        if limit is not None:
            request['limit'] = limit
        response = await self.spotPrivateGetOrderDeals(self.extend(request, params))
        #
        #     {
        #         "code":200,
        #         "data":[
        #             {
        #                 "id":"b160b8f072d9403e96289139d5544809",
        #                 "symbol":"USDC_USDT",
        #                 "quantity":"150",
        #                 "price":"0.9997",
        #                 "amount":"149.955",
        #                 "fee":"0.29991",
        #                 "trade_type":"ASK",
        #                 "order_id":"d798765285374222990bbd14decb86cd",
        #                 "is_taker":true,
        #                 "fee_currency":"USDT",
        #                 "create_time":1633984904000
        #             }
        #         ]
        #     }
        #
        data = self.safe_value(response, 'data', [])
        return self.parse_trades(data, market, since, limit)

    async def fetch_order_trades(self, id, symbol=None, since=None, limit=None, params={}):
        """
        fetch all the trades made from a single order
        :param str id: order id
        :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 to retrieve
        :param dict params: extra parameters specific to the mexc api endpoint
        :returns [dict]: a list of `trade structures <https://docs.ccxt.com/en/latest/manual.html#trade-structure>`
        """
        await self.load_markets()
        market = None
        if symbol is not None:
            market = self.market(symbol)
        request = {
            'order_id': id,
        }
        response = await self.spotPrivateGetOrderDealDetail(self.extend(request, params))
        #
        #     {
        #         "code":200,
        #         "data":[
        #             {
        #                 "id":"b160b8f072d9403e96289139d5544809",
        #                 "symbol":"USDC_USDT",
        #                 "quantity":"150",
        #                 "price":"0.9997",
        #                 "amount":"149.955",
        #                 "fee":"0.29991",
        #                 "trade_type":"ASK",
        #                 "order_id":"d798765285374222990bbd14decb86cd",
        #                 "is_taker":true,
        #                 "fee_currency":"USDT",
        #                 "create_time":1633984904000
        #             }
        #         ]
        #     }
        #
        data = self.safe_value(response, 'data', [])
        return self.parse_trades(data, market, since, limit)

    async def modify_margin_helper(self, symbol, amount, addOrReduce, params={}):
        positionId = self.safe_integer(params, 'positionId')
        if positionId is None:
            raise ArgumentsRequired(self.id + ' modifyMarginHelper() requires a positionId parameter')
        await self.load_markets()
        market = self.market(symbol)
        amount = self.amount_to_precision(symbol, amount)
        request = {
            'positionId': positionId,
            'amount': amount,
            'type': addOrReduce,
        }
        response = await self.contractPrivatePostPositionChangeMargin(self.extend(request, params))
        #
        #     {
        #         "success": True,
        #         "code": 0
        #     }
        #
        type = 'add' if (addOrReduce == 'ADD') else 'reduce'
        return self.extend(self.parse_margin_modification(response, market), {
            'amount': self.parse_number(amount),
            'type': type,
        })

    def parse_margin_modification(self, data, market=None):
        statusRaw = self.safe_value(data, 'success')
        status = 'ok' if (statusRaw is True) else 'failed'
        return {
            'info': data,
            'type': None,
            'amount': None,
            'code': None,
            'symbol': self.safe_symbol(None, market),
            'status': status,
        }

    async def reduce_margin(self, symbol, amount, params={}):
        """
        remove margin from a position
        :param str symbol: unified market symbol
        :param float amount: the amount of margin to remove
        :param dict params: extra parameters specific to the mexc api endpoint
        :returns dict: a `margin structure <https://docs.ccxt.com/en/latest/manual.html#reduce-margin-structure>`
        """
        return await self.modify_margin_helper(symbol, amount, 'SUB', params)

    async def add_margin(self, symbol, amount, params={}):
        """
        add margin
        :param str symbol: unified market symbol
        :param float amount: amount of margin to add
        :param dict params: extra parameters specific to the mexc api endpoint
        :returns dict: a `margin structure <https://docs.ccxt.com/en/latest/manual.html#add-margin-structure>`
        """
        return await self.modify_margin_helper(symbol, amount, 'ADD', params)

    async def set_leverage(self, leverage, symbol=None, params={}):
        """
        set the level of leverage for a market
        :param float leverage: the rate of leverage
        :param str|None symbol: unified market symbol
        :param dict params: extra parameters specific to the mexc api endpoint
        :returns dict: response from the exchange
        """
        await self.load_markets()
        request = {
            'leverage': leverage,
        }
        positionId = self.safe_integer(params, 'positionId')
        if positionId is None:
            openType = self.safe_number(params, 'openType')  # 1 or 2
            positionType = self.safe_number(params, 'positionType')  # 1 or 2
            market = self.market(symbol) if (symbol is not None) else None
            if (openType is None) or (positionType is None) or (market is None):
                raise ArgumentsRequired(self.id + ' setLeverage() requires a positionId parameter or a symbol argument with openType and positionType parameters, use openType 1 or 2 for isolated or cross margin respectively, use positionType 1 or 2 for long or short positions')
            else:
                request['openType'] = openType
                request['symbol'] = market['id']
                request['positionType'] = positionType
        else:
            request['positionId'] = positionId
        return await self.contractPrivatePostPositionChangeLeverage(self.extend(request, params))

    async def fetch_transfer(self, id, code=None, params={}):
        request = {
            'transact_id': id,
        }
        response = await self.spotPrivateGetAssetInternalTransferInfo(self.extend(request, params))
        #
        #     {
        #         code: '200',
        #         data: {
        #             currency: 'USDT',
        #             amount: '1',
        #             transact_id: '954877a2ef54499db9b28a7cf9ebcf41',
        #             from: 'MAIN',
        #             to: 'CONTRACT',
        #             transact_state: 'SUCCESS'
        #         }
        #     }
        #
        data = self.safe_value(response, 'data', {})
        return self.parse_transfer(data)

    async def fetch_transfers(self, code=None, since=None, limit=None, params={}):
        """
        fetch a history of internal transfers made on an account
        :param str|None code: unified currency code of the currency transferred
        :param int|None since: the earliest time in ms to fetch transfers for
        :param int|None limit: the maximum number of  transfers structures to retrieve
        :param dict params: extra parameters specific to the mexc api endpoint
        :returns [dict]: a list of `transfer structures <https://docs.ccxt.com/en/latest/manual.html#transfer-structure>`
        """
        await self.load_markets()
        request = {}
        currency = None
        if code is not None:
            currency = self.currency(code)
            request['currency'] = currency['id']
        if since is not None:
            request['start_time'] = since
        if limit is not None:
            if limit > 50:
                raise ExchangeError('This exchange supports a maximum limit of 50')
            request['page-size'] = limit
        response = await self.spotPrivateGetAssetInternalTransferRecord(self.extend(request, params))
        #
        #     {
        #         code: '200',
        #         data: {
        #             total_page: '1',
        #             total_size: '5',
        #             result_list: [{
        #                     currency: 'USDT',
        #                     amount: '1',
        #                     transact_id: '954877a2ef54499db9b28a7cf9ebcf41',
        #                     from: 'MAIN',
        #                     to: 'CONTRACT',
        #                     transact_state: 'SUCCESS'
        #                 },
        #                 ...
        #             ]
        #         }
        #     }
        #
        data = self.safe_value(response, 'data', {})
        resultList = self.safe_value(data, 'result_list', [])
        return self.parse_transfers(resultList, currency, since, limit)

    async def transfer(self, code, amount, fromAccount, toAccount, params={}):
        """
        transfer currency internally between wallets on the same account
        :param str code: unified currency code
        :param float amount: amount to transfer
        :param str fromAccount: account to transfer from
        :param str toAccount: account to transfer to
        :param dict params: extra parameters specific to the mexc api endpoint
        :returns dict: a `transfer structure <https://docs.ccxt.com/en/latest/manual.html#transfer-structure>`
        """
        await self.load_markets()
        currency = self.currency(code)
        accountsByType = self.safe_value(self.options, 'accountsByType', {})
        fromId = self.safe_string(accountsByType, fromAccount, fromAccount)
        toId = self.safe_string(accountsByType, toAccount, toAccount)
        request = {
            'currency': currency['id'],
            'amount': amount,
            'from': fromId,
            'to': toId,
        }
        response = await self.spotPrivatePostAssetInternalTransfer(self.extend(request, params))
        #
        #     {
        #         code: '200',
        #         data: {
        #             currency: 'USDT',
        #             amount: '1',
        #             transact_id: 'b60c1df8e7b24b268858003f374ecb75',
        #             from: 'MAIN',
        #             to: 'CONTRACT',
        #             transact_state: 'WAIT'
        #         }
        #     }
        #
        data = self.safe_value(response, 'data', {})
        return self.parse_transfer(data, currency)

    def parse_transfer(self, transfer, currency=None):
        #
        #     {
        #         currency: 'USDT',
        #         amount: '1',
        #         transact_id: 'b60c1df8e7b24b268858003f374ecb75',
        #         from: 'MAIN',
        #         to: 'CONTRACT',
        #         transact_state: 'WAIT'
        #     }
        #
        transferOptions = self.safe_value(self.options, 'transfer', {})
        transferStatusById = self.safe_value(transferOptions, 'status', {})
        currencyId = self.safe_string(transfer, 'currency')
        id = self.safe_string(transfer, 'transact_id')
        fromId = self.safe_string(transfer, 'from')
        toId = self.safe_string(transfer, 'to')
        accountsById = self.safe_value(transferOptions, 'accountsById', {})
        fromAccount = self.safe_string(accountsById, fromId)
        toAccount = self.safe_string(accountsById, toId)
        statusId = self.safe_string(transfer, 'transact_state')
        return {
            'info': transfer,
            'id': id,
            'timestamp': None,
            'datetime': None,
            'currency': self.safe_currency_code(currencyId, currency),
            'amount': self.safe_number(transfer, 'amount'),
            'fromAccount': fromAccount,
            'toAccount': toAccount,
            'status': self.safe_string(transferStatusById, statusId),
        }

    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 mexc api endpoint
        :returns dict: a `transaction structure <https://docs.ccxt.com/en/latest/manual.html#transaction-structure>`
        """
        tag, params = self.handle_withdraw_tag_and_params(tag, params)
        networks = self.safe_value(self.options, 'networks', {})
        network = self.safe_string_upper_2(params, 'network', 'chain')  # self line allows the user to specify either ERC20 or ETH
        network = self.safe_string(networks, network, network)  # handle ETH > ERC-20 alias
        self.check_address(address)
        await self.load_markets()
        currency = self.currency(code)
        if tag is not None:
            address += ':' + tag
        request = {
            'currency': currency['id'],
            'address': address,
            'amount': amount,
        }
        if network is not None:
            request['chain'] = network
            params = self.omit(params, ['network', 'chain'])
        response = await self.spotPrivatePostAssetWithdraw(self.extend(request, params))
        #
        #     {
        #         "code":200,
        #         "data": {
        #             "withdrawId":"25fb2831fb6d4fc7aa4094612a26c81d"
        #         }
        #     }
        #
        data = self.safe_value(response, 'data', {})
        return {
            'info': data,
            'id': self.safe_string(data, 'withdrawId'),
        }

    def sign(self, path, api='public', method='GET', params={}, headers=None, body=None):
        section, access = api
        url = self.urls['api'][section][access] + '/' + self.implode_params(path, params)
        params = self.omit(params, self.extract_params(path))
        if access == 'public':
            if params:
                url += '?' + self.urlencode(params)
        else:
            self.check_required_credentials()
            timestamp = str(self.milliseconds())
            auth = ''
            headers = {
                'ApiKey': self.apiKey,
                'Request-Time': timestamp,
                'Content-Type': 'application/json',
            }
            if method == 'POST':
                auth = self.json(params)
                body = auth
            else:
                params = self.keysort(params)
                if params:
                    auth += self.urlencode(params)
                    url += '?' + auth
            auth = self.apiKey + timestamp + auth
            signature = self.hmac(self.encode(auth), self.encode(self.secret), hashlib.sha256)
            headers['Signature'] = signature
        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
        #     {"code":10232,"msg":"The currency not exist"}
        #     {"code":10216,"msg":"No available deposit address"}
        #
        #     {
        #         "success":true,
        #         "code":0,
        #         "data":1634095541710
        #     }
        #
        success = self.safe_value(response, 'success', False)
        if success is True:
            return
        responseCode = self.safe_string(response, 'code')
        if (responseCode != '200') and (responseCode != '0'):
            feedback = self.id + ' ' + body
            self.throw_broadly_matched_exception(self.exceptions['broad'], body, feedback)
            self.throw_exactly_matched_exception(self.exceptions['exact'], responseCode, feedback)
            raise ExchangeError(feedback)

    async def fetch_funding_history(self, symbol=None, since=None, limit=None, params={}):
        """
        fetch the history of funding payments paid and received on self account
        :param str|None symbol: unified market symbol
        :param int|None since: the earliest time in ms to fetch funding history for
        :param int|None limit: the maximum number of funding history structures to retrieve
        :param dict params: extra parameters specific to the mexc api endpoint
        :returns dict: a `funding history structure <https://docs.ccxt.com/en/latest/manual.html#funding-history-structure>`
        """
        await self.load_markets()
        market = None
        request = {
            # 'symbol': market['id'],
            # 'position_id': positionId,
            # 'page_num': 1,
            # 'page_size': limit,  # default 20, max 100
        }
        if symbol is not None:
            market = self.market(symbol)
            request['symbol'] = market['id']
        if limit is not None:
            request['page_size'] = limit
        response = await self.contractPrivateGetPositionFundingRecords(self.extend(request, params))
        #
        #     {
        #         "success": True,
        #         "code": 0,
        #         "data": {
        #             "pageSize": 20,
        #             "totalCount": 2,
        #             "totalPage": 1,
        #             "currentPage": 1,
        #             "resultList": [
        #                 {
        #                     "id": 7423910,
        #                     "symbol": "BTC_USDT",
        #                     "positionType": 1,
        #                     "positionValue": 29.30024,
        #                     "funding": 0.00076180624,
        #                     "rate": -0.000026,
        #                     "settleTime": 1643299200000
        #                 },
        #                 {
        #                     "id": 7416473,
        #                     "symbol": "BTC_USDT",
        #                     "positionType": 1,
        #                     "positionValue": 28.9188,
        #                     "funding": 0.0014748588,
        #                     "rate": -0.000051,
        #                     "settleTime": 1643270400000
        #                 }
        #             ]
        #         }
        #     }
        #
        data = self.safe_value(response, 'data', {})
        resultList = self.safe_value(data, 'resultList', [])
        result = []
        for i in range(0, len(resultList)):
            entry = resultList[i]
            timestamp = self.safe_integer(entry, 'settleTime')
            result.append({
                'info': entry,
                'symbol': symbol,
                'code': None,
                'timestamp': timestamp,
                'datetime': self.iso8601(timestamp),
                'id': self.safe_number(entry, 'id'),
                'amount': self.safe_number(entry, 'funding'),
            })
        return result

    def parse_funding_rate(self, contract, market=None):
        #
        #     {
        #         "symbol": "BTC_USDT",
        #         "fundingRate": 0.000014,
        #         "maxFundingRate": 0.003,
        #         "minFundingRate": -0.003,
        #         "collectCycle": 8,
        #         "nextSettleTime": 1643241600000,
        #         "timestamp": 1643240373359
        #     }
        #
        nextFundingRate = self.safe_number(contract, 'fundingRate')
        nextFundingTimestamp = self.safe_integer(contract, 'nextSettleTime')
        marketId = self.safe_string(contract, 'symbol')
        symbol = self.safe_symbol(marketId, market)
        timestamp = self.safe_integer(contract, 'timestamp')
        datetime = self.iso8601(timestamp)
        return {
            'info': contract,
            'symbol': symbol,
            'markPrice': None,
            'indexPrice': None,
            'interestRate': None,
            'estimatedSettlePrice': None,
            'timestamp': timestamp,
            'datetime': datetime,
            'fundingRate': nextFundingRate,
            'fundingTimestamp': nextFundingTimestamp,
            'fundingDatetime': self.iso8601(nextFundingTimestamp),
            'nextFundingRate': None,
            'nextFundingTimestamp': None,
            'nextFundingDatetime': None,
            'previousFundingRate': None,
            'previousFundingTimestamp': None,
            'previousFundingDatetime': None,
        }

    async def fetch_funding_rate(self, symbol, params={}):
        """
        fetch the current funding rate
        :param str symbol: unified market symbol
        :param dict params: extra parameters specific to the mexc api endpoint
        :returns dict: a `funding rate structure <https://docs.ccxt.com/en/latest/manual.html#funding-rate-structure>`
        """
        await self.load_markets()
        market = self.market(symbol)
        request = {
            'symbol': market['id'],
        }
        response = await self.contractPublicGetFundingRateSymbol(self.extend(request, params))
        #
        #     {
        #         "success": True,
        #         "code": 0,
        #         "data": {
        #             "symbol": "BTC_USDT",
        #             "fundingRate": 0.000014,
        #             "maxFundingRate": 0.003,
        #             "minFundingRate": -0.003,
        #             "collectCycle": 8,
        #             "nextSettleTime": 1643241600000,
        #             "timestamp": 1643240373359
        #         }
        #     }
        #
        result = self.safe_value(response, 'data', {})
        return self.parse_funding_rate(result, market)

    async def fetch_funding_rate_history(self, symbol=None, since=None, limit=None, params={}):
        """
        fetches historical funding rate prices
        :param str|None symbol: unified symbol of the market to fetch the funding rate history for
        :param int|None since: not used by mexc, but filtered internally by ccxt
        :param int|None limit: mexc limit is page_size default 20, maximum is 100
        :param dict params: extra parameters specific to the mexc api endpoint
        :returns [dict]: a list of `funding rate structures <https://docs.ccxt.com/en/latest/manual.html?#funding-rate-history-structure>`
        """
        if symbol is None:
            raise ArgumentsRequired(self.id + ' fetchFundingRateHistory() requires a symbol argument')
        await self.load_markets()
        market = self.market(symbol)
        request = {
            'symbol': market['id'],
            # 'page_size': limit,  # optional
            # 'page_num': 1,  # optional, current page number, default is 1
        }
        if limit is not None:
            request['page_size'] = limit
        response = await self.contractPublicGetFundingRateHistory(self.extend(request, params))
        #
        #    {
        #        "success": True,
        #        "code": 0,
        #        "data": {
        #            "pageSize": 2,
        #            "totalCount": 21,
        #            "totalPage": 11,
        #            "currentPage": 1,
        #            "resultList": [
        #                {
        #                    "symbol": "BTC_USDT",
        #                    "fundingRate": 0.000266,
        #                    "settleTime": 1609804800000
        #                },
        #                {
        #                    "symbol": "BTC_USDT",
        #                    "fundingRate": 0.00029,
        #                    "settleTime": 1609776000000
        #                }
        #            ]
        #        }
        #    }
        #
        data = self.safe_value(response, 'data')
        result = self.safe_value(data, 'resultList', [])
        rates = []
        for i in range(0, len(result)):
            entry = result[i]
            marketId = self.safe_string(entry, 'symbol')
            symbol = self.safe_symbol(marketId)
            timestamp = self.safe_integer(entry, 'settleTime')
            rates.append({
                'info': entry,
                'symbol': symbol,
                'fundingRate': self.safe_number(entry, 'fundingRate'),
                'timestamp': timestamp,
                'datetime': self.iso8601(timestamp),
            })
        sorted = self.sort_by(rates, 'timestamp')
        return self.filter_by_symbol_since_limit(sorted, market['symbol'], since, limit)

    async def fetch_leverage_tiers(self, symbols=None, params={}):
        """
        retrieve information on the maximum leverage, and maintenance margin for trades of varying trade sizes
        :param [str]|None symbols: list of unified market symbols
        :param dict params: extra parameters specific to the mexc api endpoint
        :returns dict: a dictionary of `leverage tiers structures <https://docs.ccxt.com/en/latest/manual.html#leverage-tiers-structure>`, indexed by market symbols
        """
        await self.load_markets()
        response = await self.contractPublicGetDetail(params)
        #
        #     {
        #         "success":true,
        #         "code":0,
        #         "data":[
        #             {
        #                 "symbol": "BTC_USDT",
        #                 "displayName": "BTC_USDT永续",
        #                 "displayNameEn": "BTC_USDT SWAP",
        #                 "positionOpenType": 3,
        #                 "baseCoin": "BTC",
        #                 "quoteCoin": "USDT",
        #                 "settleCoin": "USDT",
        #                 "contractSize": 0.0001,
        #                 "minLeverage": 1,
        #                 "maxLeverage": 125,
        #                 "priceScale": 2,
        #                 "volScale": 0,
        #                 "amountScale": 4,
        #                 "priceUnit": 0.5,
        #                 "volUnit": 1,
        #                 "minVol": 1,
        #                 "maxVol": 1000000,
        #                 "bidLimitPriceRate": 0.1,
        #                 "askLimitPriceRate": 0.1,
        #                 "takerFeeRate": 0.0006,
        #                 "makerFeeRate": 0.0002,
        #                 "maintenanceMarginRate": 0.004,
        #                 "initialMarginRate": 0.008,
        #                 "riskBaseVol": 10000,
        #                 "riskIncrVol": 200000,
        #                 "riskIncrMmr": 0.004,
        #                 "riskIncrImr": 0.004,
        #                 "riskLevelLimit": 5,
        #                 "priceCoefficientVariation": 0.1,
        #                 "indexOrigin": ["BINANCE","GATEIO","HUOBI","MXC"],
        #                 "state": 0,  # 0 enabled, 1 delivery, 2 completed, 3 offline, 4 pause
        #                 "isNew": False,
        #                 "isHot": True,
        #                 "isHidden": False
        #             },
        #             ...
        #         ]
        #     }
        #
        data = self.safe_value(response, 'data')
        return self.parse_leverage_tiers(data, symbols, 'symbol')

    def parse_market_leverage_tiers(self, info, market):
        """
         * @ignore
        :param dict info: Exchange response for 1 market
        :param dict market: CCXT market
        """
        #
        #    {
        #        "symbol": "BTC_USDT",
        #        "displayName": "BTC_USDT永续",
        #        "displayNameEn": "BTC_USDT SWAP",
        #        "positionOpenType": 3,
        #        "baseCoin": "BTC",
        #        "quoteCoin": "USDT",
        #        "settleCoin": "USDT",
        #        "contractSize": 0.0001,
        #        "minLeverage": 1,
        #        "maxLeverage": 125,
        #        "priceScale": 2,
        #        "volScale": 0,
        #        "amountScale": 4,
        #        "priceUnit": 0.5,
        #        "volUnit": 1,
        #        "minVol": 1,
        #        "maxVol": 1000000,
        #        "bidLimitPriceRate": 0.1,
        #        "askLimitPriceRate": 0.1,
        #        "takerFeeRate": 0.0006,
        #        "makerFeeRate": 0.0002,
        #        "maintenanceMarginRate": 0.004,
        #        "initialMarginRate": 0.008,
        #        "riskBaseVol": 10000,
        #        "riskIncrVol": 200000,
        #        "riskIncrMmr": 0.004,
        #        "riskIncrImr": 0.004,
        #        "riskLevelLimit": 5,
        #        "priceCoefficientVariation": 0.1,
        #        "indexOrigin": ["BINANCE","GATEIO","HUOBI","MXC"],
        #        "state": 0,  # 0 enabled, 1 delivery, 2 completed, 3 offline, 4 pause
        #        "isNew": False,
        #        "isHot": True,
        #        "isHidden": False
        #    }
        #
        maintenanceMarginRate = self.safe_string(info, 'maintenanceMarginRate')
        initialMarginRate = self.safe_string(info, 'initialMarginRate')
        maxVol = self.safe_string(info, 'maxVol')
        riskIncrVol = self.safe_string(info, 'riskIncrVol')
        riskIncrMmr = self.safe_string(info, 'riskIncrMmr')
        riskIncrImr = self.safe_string(info, 'riskIncrImr')
        floor = '0'
        tiers = []
        quoteId = self.safe_string(info, 'quoteCoin')
        while(Precise.string_lt(floor, maxVol)):
            cap = Precise.string_add(floor, riskIncrVol)
            tiers.append({
                'tier': self.parse_number(Precise.string_div(cap, riskIncrVol)),
                'currency': self.safe_currency_code(quoteId),
                'minNotional': self.parse_number(floor),
                'maxNotional': self.parse_number(cap),
                'maintenanceMarginRate': self.parse_number(maintenanceMarginRate),
                'maxLeverage': self.parse_number(Precise.string_div('1', initialMarginRate)),
                'info': info,
            })
            initialMarginRate = Precise.string_add(initialMarginRate, riskIncrImr)
            maintenanceMarginRate = Precise.string_add(maintenanceMarginRate, riskIncrMmr)
            floor = cap
        return tiers

    async def set_position_mode(self, hedged, symbol=None, params={}):
        request = {
            'positionMode': 1 if hedged else 2,  # 1 Hedge, 2 One-way, before changing position mode make sure that there are no active orders, planned orders, or open positions, the risk limit level will be reset to 1
        }
        response = await self.contractPrivatePostPositionChangePositionMode(self.extend(request, params))
        #
        #     {
        #         "success":true,
        #         "code":0
        #     }
        #
        return response

    async def fetch_position_mode(self, symbol=None, params={}):
        response = await self.contractPrivateGetPositionPositionMode(params)
        #
        #     {
        #         "success":true,
        #         "code":0,
        #         "data":2
        #     }
        #
        positionMode = self.safe_integer(response, 'data')
        return {
            'info': response,
            'hedged': (positionMode == 1),
        }
