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

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

from ccxt.base.exchange import Exchange
from ccxt.abstract.xt import ImplicitAPI
import hashlib
from ccxt.base.types import Any, Currencies, Currency, DepositAddress, Int, LedgerEntry, LeverageTier, LeverageTiers, MarginModification, Market, Num, Order, OrderSide, OrderType, Position, Str, Tickers, FundingRate, Transaction, TransferEntry
from typing import List
from ccxt.base.errors import ExchangeError
from ccxt.base.errors import AuthenticationError
from ccxt.base.errors import PermissionDenied
from ccxt.base.errors import ArgumentsRequired
from ccxt.base.errors import BadRequest
from ccxt.base.errors import BadSymbol
from ccxt.base.errors import InsufficientFunds
from ccxt.base.errors import InvalidOrder
from ccxt.base.errors import NotSupported
from ccxt.base.errors import NetworkError
from ccxt.base.errors import RateLimitExceeded
from ccxt.base.errors import OnMaintenance
from ccxt.base.errors import RequestTimeout
from ccxt.base.decimal_to_precision import TICK_SIZE
from ccxt.base.precise import Precise


class xt(Exchange, ImplicitAPI):

    def describe(self) -> Any:
        return self.deep_extend(super(xt, self).describe(), {
            'id': 'xt',
            'name': 'XT',
            'countries': ['SC'],  # Seychelles
            # spot api ratelimits are None, 10/s/ip, 50/s/ip, 100/s/ip or 200/s/ip
            # futures 3 requests per second => 1000ms / (100 * 3.33) = 3.003(get assets -> fetchMarkets & fetchCurrencies)
            # futures 10 requests per second => 1000ms / (100 * 1) = 10(all other)
            # futures 1000 times per minute for each single IP -> Otherwise account locked for 10min
            'rateLimit': 100,
            'version': 'v4',
            'certified': False,
            'pro': True,
            'has': {
                'CORS': False,
                'spot': True,
                'margin': True,
                'swap': True,
                'future': True,
                'option': False,
                'addMargin': True,
                'borrowMargin': False,
                'cancelAllOrders': True,
                'cancelOrder': True,
                'cancelOrders': True,
                'createDepositAddress': False,
                'createMarketBuyOrderWithCost': True,
                'createMarketSellOrderWithCost': False,
                'createOrder': True,
                'createPostOnlyOrder': False,
                'createReduceOnlyOrder': True,
                'editOrder': True,
                'fetchAccounts': False,
                'fetchAllGreeks': False,
                'fetchBalance': True,
                'fetchBidsAsks': True,
                'fetchBorrowInterest': False,
                'fetchBorrowRate': False,
                'fetchBorrowRateHistories': False,
                'fetchBorrowRateHistory': False,
                'fetchBorrowRatesPerSymbol': False,
                'fetchCanceledOrders': True,
                'fetchClosedOrders': True,
                'fetchCurrencies': True,
                'fetchDeposit': False,
                'fetchDepositAddress': True,
                'fetchDepositAddresses': False,
                'fetchDepositAddressesByNetwork': False,
                'fetchDeposits': True,
                'fetchDepositWithdrawals': False,
                'fetchDepositWithdrawFee': False,
                'fetchDepositWithdrawFees': False,
                'fetchFundingHistory': True,
                'fetchFundingInterval': True,
                'fetchFundingIntervals': False,
                'fetchFundingRate': True,
                'fetchFundingRateHistory': True,
                'fetchFundingRates': False,
                'fetchGreeks': False,
                'fetchIndexOHLCV': False,
                'fetchL3OrderBook': False,
                'fetchLedger': True,
                'fetchLedgerEntry': False,
                'fetchLeverage': False,
                'fetchLeverageTiers': True,
                'fetchMarketLeverageTiers': True,
                'fetchMarkets': True,
                'fetchMarkOHLCV': False,
                'fetchMyTrades': True,
                'fetchOHLCV': True,
                'fetchOpenInterest': False,
                'fetchOpenInterestHistory': False,
                'fetchOpenOrders': True,
                'fetchOption': False,
                'fetchOptionChain': False,
                'fetchOrder': True,
                'fetchOrderBook': True,
                'fetchOrderBooks': False,
                'fetchOrders': True,
                'fetchOrdersByStatus': True,
                'fetchOrderTrades': False,
                'fetchPosition': True,
                'fetchPositions': True,
                'fetchPremiumIndexOHLCV': False,
                'fetchSettlementHistory': False,
                'fetchStatus': False,
                'fetchTicker': True,
                'fetchTickers': True,
                'fetchTime': True,
                'fetchTrades': True,
                'fetchTradingFee': False,
                'fetchTradingFees': False,
                'fetchTradingLimits': False,
                'fetchTransactionFee': False,
                'fetchTransactionFees': False,
                'fetchTransactions': False,
                'fetchTransfer': False,
                'fetchTransfers': False,
                'fetchVolatilityHistory': False,
                'fetchWithdrawal': False,
                'fetchWithdrawals': True,
                'fetchWithdrawalWhitelist': False,
                'reduceMargin': True,
                'repayMargin': False,
                'setLeverage': True,
                'setMargin': False,
                'setMarginMode': True,
                'setPositionMode': False,
                'signIn': False,
                'transfer': True,
                'withdraw': True,
            },
            'precisionMode': TICK_SIZE,
            'urls': {
                'logo': 'https://user-images.githubusercontent.com/14319357/232636712-466df2fc-560a-4ca4-aab2-b1d954a58e24.jpg',
                'api': {
                    'spot': 'https://sapi.xt.com',
                    'linear': 'https://fapi.xt.com',
                    'inverse': 'https://dapi.xt.com',
                    'user': 'https://api.xt.com',
                },
                'www': 'https://xt.com',
                'referral': 'https://www.xt.com/en/accounts/register?ref=9PTM9VW',
                'doc': [
                    'https://doc.xt.com/',
                    'https://github.com/xtpub/api-doc',
                ],
                'fees': 'https://www.xt.com/en/rate',
            },
            'api': {
                'public': {
                    'spot': {
                        'get': {
                            'currencies': 1,
                            'depth': 10,
                            'kline': 1,
                            'symbol': 1,  # 1 for a single symbol
                            'ticker': 1,  # 1 for a single symbol
                            'ticker/book': 1,  # 1 for a single symbol
                            'ticker/price': 1,  # 1 for a single symbol
                            'ticker/24h': 1,  # 1 for a single symbol
                            'time': 1,
                            'trade/history': 1,
                            'trade/recent': 1,
                            'wallet/support/currency': 1,
                        },
                    },
                    'linear': {
                        'get': {
                            'future/market/v1/public/contract/risk-balance': 1,
                            'future/market/v1/public/contract/open-interest': 1,
                            'future/market/v1/public/leverage/bracket/detail': 1,
                            'future/market/v1/public/leverage/bracket/list': 1,
                            'future/market/v1/public/q/agg-ticker': 1,
                            'future/market/v1/public/q/agg-tickers': 1,
                            'future/market/v1/public/q/deal': 1,
                            'future/market/v1/public/q/depth': 1,
                            'future/market/v1/public/q/funding-rate': 1,
                            'future/market/v1/public/q/funding-rate-record': 1,
                            'future/market/v1/public/q/index-price': 1,
                            'future/market/v1/public/q/kline': 1,
                            'future/market/v1/public/q/mark-price': 1,
                            'future/market/v1/public/q/symbol-index-price': 1,
                            'future/market/v1/public/q/symbol-mark-price': 1,
                            'future/market/v1/public/q/ticker': 1,
                            'future/market/v1/public/q/tickers': 1,
                            'future/market/v1/public/symbol/coins': 3.33,
                            'future/market/v1/public/symbol/detail': 3.33,
                            'future/market/v1/public/symbol/list': 1,
                        },
                    },
                    'inverse': {
                        'get': {
                            'future/market/v1/public/contract/risk-balance': 1,
                            'future/market/v1/public/contract/open-interest': 1,
                            'future/market/v1/public/leverage/bracket/detail': 1,
                            'future/market/v1/public/leverage/bracket/list': 1,
                            'future/market/v1/public/q/agg-ticker': 1,
                            'future/market/v1/public/q/agg-tickers': 1,
                            'future/market/v1/public/q/deal': 1,
                            'future/market/v1/public/q/depth': 1,
                            'future/market/v1/public/q/funding-rate': 1,
                            'future/market/v1/public/q/funding-rate-record': 1,
                            'future/market/v1/public/q/index-price': 1,
                            'future/market/v1/public/q/kline': 1,
                            'future/market/v1/public/q/mark-price': 1,
                            'future/market/v1/public/q/symbol-index-price': 1,
                            'future/market/v1/public/q/symbol-mark-price': 1,
                            'future/market/v1/public/q/ticker': 1,
                            'future/market/v1/public/q/tickers': 1,
                            'future/market/v1/public/symbol/coins': 3.33,
                            'future/market/v1/public/symbol/detail': 3.33,
                            'future/market/v1/public/symbol/list': 1,
                        },
                    },
                },
                'private': {
                    'spot': {
                        'get': {
                            'balance': 1,
                            'balances': 1,
                            'batch-order': 1,
                            'deposit/address': 1,
                            'deposit/history': 1,
                            'history-order': 1,
                            'open-order': 1,
                            'order': 1,
                            'order/{orderId}': 1,
                            'trade': 1,
                            'withdraw/history': 1,
                        },
                        'post': {
                            'order': 0.2,
                            'withdraw': 10,
                            'balance/transfer': 1,
                            'balance/account/transfer': 1,
                            'ws-token': 1,
                        },
                        'delete': {
                            'batch-order': 1,
                            'open-order': 1,
                            'order/{orderId}': 1,
                        },
                        'put': {
                            'order/{orderId}': 1,
                        },
                    },
                    'linear': {
                        'get': {
                            'future/trade/v1/entrust/plan-detail': 1,
                            'future/trade/v1/entrust/plan-list': 1,
                            'future/trade/v1/entrust/plan-list-history': 1,
                            'future/trade/v1/entrust/profit-detail': 1,
                            'future/trade/v1/entrust/profit-list': 1,
                            'future/trade/v1/order/detail': 1,
                            'future/trade/v1/order/list': 1,
                            'future/trade/v1/order/list-history': 1,
                            'future/trade/v1/order/trade-list': 1,
                            'future/user/v1/account/info': 1,
                            'future/user/v1/balance/bills': 1,
                            'future/user/v1/balance/detail': 1,
                            'future/user/v1/balance/funding-rate-list': 1,
                            'future/user/v1/balance/list': 1,
                            'future/user/v1/position/adl': 1,
                            'future/user/v1/position/list': 1,
                            'future/user/v1/user/collection/list': 1,
                            'future/user/v1/user/listen-key': 1,
                        },
                        'post': {
                            'future/trade/v1/entrust/cancel-all-plan': 1,
                            'future/trade/v1/entrust/cancel-all-profit-stop': 1,
                            'future/trade/v1/entrust/cancel-plan': 1,
                            'future/trade/v1/entrust/cancel-profit-stop': 1,
                            'future/trade/v1/entrust/create-plan': 1,
                            'future/trade/v1/entrust/create-profit': 1,
                            'future/trade/v1/entrust/update-profit-stop': 1,
                            'future/trade/v1/order/cancel': 1,
                            'future/trade/v1/order/cancel-all': 1,
                            'future/trade/v1/order/create': 1,
                            'future/trade/v1/order/create-batch': 1,
                            'future/trade/v1/order/update': 1,
                            'future/user/v1/account/open': 1,
                            'future/user/v1/position/adjust-leverage': 1,
                            'future/user/v1/position/auto-margin': 1,
                            'future/user/v1/position/close-all': 1,
                            'future/user/v1/position/margin': 1,
                            'future/user/v1/user/collection/add': 1,
                            'future/user/v1/user/collection/cancel': 1,
                            'future/user/v1/position/change-type': 1,
                        },
                    },
                    'inverse': {
                        'get': {
                            'future/trade/v1/entrust/plan-detail': 1,
                            'future/trade/v1/entrust/plan-list': 1,
                            'future/trade/v1/entrust/plan-list-history': 1,
                            'future/trade/v1/entrust/profit-detail': 1,
                            'future/trade/v1/entrust/profit-list': 1,
                            'future/trade/v1/order/detail': 1,
                            'future/trade/v1/order/list': 1,
                            'future/trade/v1/order/list-history': 1,
                            'future/trade/v1/order/trade-list': 1,
                            'future/user/v1/account/info': 1,
                            'future/user/v1/balance/bills': 1,
                            'future/user/v1/balance/detail': 1,
                            'future/user/v1/balance/funding-rate-list': 1,
                            'future/user/v1/balance/list': 1,
                            'future/user/v1/position/adl': 1,
                            'future/user/v1/position/list': 1,
                            'future/user/v1/user/collection/list': 1,
                            'future/user/v1/user/listen-key': 1,
                        },
                        'post': {
                            'future/trade/v1/entrust/cancel-all-plan': 1,
                            'future/trade/v1/entrust/cancel-all-profit-stop': 1,
                            'future/trade/v1/entrust/cancel-plan': 1,
                            'future/trade/v1/entrust/cancel-profit-stop': 1,
                            'future/trade/v1/entrust/create-plan': 1,
                            'future/trade/v1/entrust/create-profit': 1,
                            'future/trade/v1/entrust/update-profit-stop': 1,
                            'future/trade/v1/order/cancel': 1,
                            'future/trade/v1/order/cancel-all': 1,
                            'future/trade/v1/order/create': 1,
                            'future/trade/v1/order/create-batch': 1,
                            'future/trade/v1/order/update': 1,
                            'future/user/v1/account/open': 1,
                            'future/user/v1/position/adjust-leverage': 1,
                            'future/user/v1/position/auto-margin': 1,
                            'future/user/v1/position/close-all': 1,
                            'future/user/v1/position/margin': 1,
                            'future/user/v1/user/collection/add': 1,
                            'future/user/v1/user/collection/cancel': 1,
                        },
                    },
                    'user': {
                        'get': {
                            'user/account': 1,
                            'user/account/api-key': 1,
                        },
                        'post': {
                            'user/account': 1,
                            'user/account/api-key': 1,
                        },
                        'put': {
                            'user/account/api-key': 1,
                        },
                        'delete': {
                            'user/account/{apiKeyId}': 1,
                        },
                    },
                },
            },
            'fees': {
                'spot': {
                    'tierBased': True,
                    'percentage': True,
                    'maker': self.parse_number('0.002'),
                    'taker': self.parse_number('0.002'),
                    'tiers': {
                        'maker': [
                            [self.parse_number('0'), self.parse_number('0.002')],
                            [self.parse_number('5000'), self.parse_number('0.0018')],
                            [self.parse_number('10000'), self.parse_number('0.0016')],
                            [self.parse_number('20000'), self.parse_number('0.0014')],
                            [self.parse_number('50000'), self.parse_number('0.0012')],
                            [self.parse_number('150000'), self.parse_number('0.0010')],
                            [self.parse_number('300000'), self.parse_number('0.0008')],
                            [self.parse_number('600000'), self.parse_number('0.0007')],
                            [self.parse_number('1200000'), self.parse_number('0.0006')],
                            [self.parse_number('2500000'), self.parse_number('0.0005')],
                            [self.parse_number('6000000'), self.parse_number('0.0004')],
                            [self.parse_number('15000000'), self.parse_number('0.0003')],
                            [self.parse_number('30000000'), self.parse_number('0.0002')],
                        ],
                        'taker': [
                            [self.parse_number('0'), self.parse_number('0.002')],
                            [self.parse_number('5000'), self.parse_number('0.0018')],
                            [self.parse_number('10000'), self.parse_number('0.0016')],
                            [self.parse_number('20000'), self.parse_number('0.0014')],
                            [self.parse_number('50000'), self.parse_number('0.0012')],
                            [self.parse_number('150000'), self.parse_number('0.0010')],
                            [self.parse_number('300000'), self.parse_number('0.0008')],
                            [self.parse_number('600000'), self.parse_number('0.0007')],
                            [self.parse_number('1200000'), self.parse_number('0.0006')],
                            [self.parse_number('2500000'), self.parse_number('0.0005')],
                            [self.parse_number('6000000'), self.parse_number('0.0004')],
                            [self.parse_number('15000000'), self.parse_number('0.0003')],
                            [self.parse_number('30000000'), self.parse_number('0.0002')],
                        ],
                    },
                },
                'contract': {
                    'tierBased': True,
                    'percentage': True,
                    'maker': self.parse_number('0.0004'),
                    'taker': self.parse_number('0.0006'),
                    'tiers': {
                        'maker': [
                            [self.parse_number('0'), self.parse_number('0.0004')],
                            [self.parse_number('200000'), self.parse_number('0.00038')],
                            [self.parse_number('1000000'), self.parse_number('0.00036')],
                            [self.parse_number('5000000'), self.parse_number('0.00034')],
                            [self.parse_number('10000000'), self.parse_number('0.00032')],
                            [self.parse_number('15000000'), self.parse_number('0.00028')],
                            [self.parse_number('30000000'), self.parse_number('0.00024')],
                            [self.parse_number('50000000'), self.parse_number('0.0002')],
                            [self.parse_number('100000000'), self.parse_number('0.00016')],
                            [self.parse_number('300000000'), self.parse_number('0.00012')],
                            [self.parse_number('500000000'), self.parse_number('0.00008')],
                        ],
                        'taker': [
                            [self.parse_number('0'), self.parse_number('0.0006')],
                            [self.parse_number('200000'), self.parse_number('0.000588')],
                            [self.parse_number('1000000'), self.parse_number('0.00057')],
                            [self.parse_number('5000000'), self.parse_number('0.00054')],
                            [self.parse_number('10000000'), self.parse_number('0.00051')],
                            [self.parse_number('15000000'), self.parse_number('0.00048')],
                            [self.parse_number('30000000'), self.parse_number('0.00045')],
                            [self.parse_number('50000000'), self.parse_number('0.00045')],
                            [self.parse_number('100000000'), self.parse_number('0.00036')],
                            [self.parse_number('300000000'), self.parse_number('0.00033')],
                            [self.parse_number('500000000'), self.parse_number('0.0003')],
                        ],
                    },
                },
            },
            'exceptions': {
                'exact': {
                    '400': NetworkError,  # {"returnCode":1,"msgInfo":"failure","error":{"code":"400","msg":"Connection refused: /10.0.26.71:8080"},"result":null}
                    '404': ExchangeError,  # interface does not exist
                    '429': RateLimitExceeded,  # The request is too frequent, please control the request rate according to the speed limit requirement
                    '500': ExchangeError,  # Service exception
                    '502': ExchangeError,  # Gateway exception
                    '503': OnMaintenance,  # Service unavailable, please try again later
                    'AUTH_001': AuthenticationError,  # missing request header xt-validate-appkey
                    'AUTH_002': AuthenticationError,  # missing request header xt-validate-timestamp
                    'AUTH_003': AuthenticationError,  # missing request header xt-validate-recvwindow
                    'AUTH_004': AuthenticationError,  # bad request header xt-validate-recvwindow
                    'AUTH_005': AuthenticationError,  # missing request header xt-validate-algorithms
                    'AUTH_006': AuthenticationError,  # bad request header xt-validate-algorithms
                    'AUTH_007': AuthenticationError,  # missing request header xt-validate-signature
                    'AUTH_101': AuthenticationError,  # ApiKey does not exist
                    'AUTH_102': AuthenticationError,  # ApiKey is not activated
                    'AUTH_103': AuthenticationError,  # Signature error, {"rc":1,"mc":"AUTH_103","ma":[],"result":null}
                    'AUTH_104': AuthenticationError,  # Unbound IP request
                    'AUTH_105': AuthenticationError,  # outdated message
                    'AUTH_106': PermissionDenied,  # Exceeded apikey permission
                    'SYMBOL_001': BadSymbol,  # Symbol not exist
                    'SYMBOL_002': BadSymbol,  # Symbol offline
                    'SYMBOL_003': BadSymbol,  # Symbol suspend trading
                    'SYMBOL_004': BadSymbol,  # Symbol country disallow trading
                    'SYMBOL_005': BadSymbol,  # The symbol does not support trading via API
                    'ORDER_001': InvalidOrder,  # Platform rejection
                    'ORDER_002': InsufficientFunds,  # insufficient funds
                    'ORDER_003': InvalidOrder,  # Trading Pair Suspended
                    'ORDER_004': InvalidOrder,  # no transaction
                    'ORDER_005': InvalidOrder,  # Order not exist
                    'ORDER_006': InvalidOrder,  # Too many open orders
                    'ORDER_007': PermissionDenied,  # The sub-account has no transaction authority
                    'ORDER_F0101': InvalidOrder,  # Trigger Price Filter - Min
                    'ORDER_F0102': InvalidOrder,  # Trigger Price Filter - Max
                    'ORDER_F0103': InvalidOrder,  # Trigger Price Filter - Step Value
                    'ORDER_F0201': InvalidOrder,  # Trigger Quantity Filter - Min
                    'ORDER_F0202': InvalidOrder,  # Trigger Quantity Filter - Max
                    'ORDER_F0203': InvalidOrder,  # Trigger Quantity Filter - Step Value
                    'ORDER_F0301': InvalidOrder,  # Trigger QUOTE_QTY Filter - Min Value
                    'ORDER_F0401': InvalidOrder,  # Trigger PROTECTION_ONLINE Filter
                    'ORDER_F0501': InvalidOrder,  # Trigger PROTECTION_LIMIT Filter - Buy Max Deviation
                    'ORDER_F0502': InvalidOrder,  # Trigger PROTECTION_LIMIT Filter - Sell Max Deviation
                    'ORDER_F0601': InvalidOrder,  # Trigger PROTECTION_MARKET Filter
                    'COMMON_001': ExchangeError,  # The user does not exist
                    'COMMON_002': ExchangeError,  # System busy, please try it later
                    'COMMON_003': BadRequest,  # Operation failed, please try it later
                    'CURRENCY_001': BadRequest,  # Information of currency is abnormal
                    'DEPOSIT_001': BadRequest,  # Deposit is not open
                    'DEPOSIT_002': PermissionDenied,  # The current account security level is low, please bind any two security verifications in mobile phone/email/Google Authenticator before deposit
                    'DEPOSIT_003': BadRequest,  # The format of address is incorrect, please enter again
                    'DEPOSIT_004': BadRequest,  # The address is already exists, please enter again
                    'DEPOSIT_005': BadRequest,  # Can not find the address of offline wallet
                    'DEPOSIT_006': BadRequest,  # No deposit address, please try it later
                    'DEPOSIT_007': BadRequest,  # Address is being generated, please try it later
                    'DEPOSIT_008': BadRequest,  # Deposit is not available
                    'WITHDRAW_001': BadRequest,  # Withdraw is not open
                    'WITHDRAW_002': BadRequest,  # The withdrawal address is invalid
                    'WITHDRAW_003': PermissionDenied,  # The current account security level is low, please bind any two security verifications in mobile phone/email/Google Authenticator before withdraw
                    'WITHDRAW_004': BadRequest,  # The withdrawal address is not added
                    'WITHDRAW_005': BadRequest,  # The withdrawal address cannot be empty
                    'WITHDRAW_006': BadRequest,  # Memo cannot be empty
                    'WITHDRAW_008': PermissionDenied,  # Risk control is triggered, withdraw of self currency is not currently supported
                    'WITHDRAW_009': PermissionDenied,  # Withdraw failed, some hasattr(self, assets) withdraw are restricted by T+1 withdraw
                    'WITHDRAW_010': BadRequest,  # The precision of withdrawal is invalid
                    'WITHDRAW_011': InsufficientFunds,  # free balance is not enough
                    'WITHDRAW_012': PermissionDenied,  # Withdraw failed, your remaining withdrawal limit today is not enough
                    'WITHDRAW_013': PermissionDenied,  # Withdraw failed, your remaining withdrawal limit today is not enough, the withdrawal amount can be increased by completing a higher level of real-name authentication
                    'WITHDRAW_014': BadRequest,  # This withdrawal address cannot be used in the internal transfer function, please cancel the internal transfer function before submitting
                    'WITHDRAW_015': BadRequest,  # The withdrawal amount is not enough to deduct the handling fee
                    'WITHDRAW_016': BadRequest,  # This withdrawal address is already exists
                    'WITHDRAW_017': BadRequest,  # This withdrawal has been processed and cannot be canceled
                    'WITHDRAW_018': BadRequest,  # Memo must be a number
                    'WITHDRAW_019': BadRequest,  # Memo is incorrect, please enter again
                    'WITHDRAW_020': PermissionDenied,  # Your withdrawal amount has reached the upper limit for today, please try it tomorrow
                    'WITHDRAW_021': PermissionDenied,  # Your withdrawal amount has reached the upper limit for today, you can only withdraw up to {0} self time
                    'WITHDRAW_022': BadRequest,  # Withdrawal amount must be greater than {0}
                    'WITHDRAW_023': BadRequest,  # Withdrawal amount must be less than {0}
                    'WITHDRAW_024': BadRequest,  # Withdraw is not supported
                    'WITHDRAW_025': BadRequest,  # Please create a FIO address in the deposit page
                    'FUND_001': BadRequest,  # Duplicate request(a bizId can only be requested once)
                    'FUND_002': InsufficientFunds,  # Insufficient account balance
                    'FUND_003': BadRequest,  # Transfer operations are not supported(for example, sub-accounts do not support financial transfers)
                    'FUND_004': ExchangeError,  # Unfreeze failed
                    'FUND_005': PermissionDenied,  # Transfer prohibited
                    'FUND_014': BadRequest,  # The transfer-in account id and transfer-out account ID cannot be the same
                    'FUND_015': BadRequest,  # From and to business types cannot be the same
                    'FUND_016': BadRequest,  # Leverage transfer, symbol cannot be empty
                    'FUND_017': BadRequest,  # Parameter error
                    'FUND_018': BadRequest,  # Invalid freeze record
                    'FUND_019': BadRequest,  # Freeze users not equal
                    'FUND_020': BadRequest,  # Freeze currency are not equal
                    'FUND_021': BadRequest,  # Operation not supported
                    'FUND_022': BadRequest,  # Freeze record does not exist
                    'FUND_044': BadRequest,  # The maximum length of the amount is 113 and cannot exceed the limit
                    'TRANSFER_001': BadRequest,  # Duplicate request(a bizId can only be requested once)
                    'TRANSFER_002': InsufficientFunds,  # Insufficient account balance
                    'TRANSFER_003': BadRequest,  # User not registered
                    'TRANSFER_004': PermissionDenied,  # The currency is not allowed to be transferred
                    'TRANSFER_005': PermissionDenied,  # The user’s currency is not allowed to be transferred
                    'TRANSFER_006': PermissionDenied,  # Transfer prohibited
                    'TRANSFER_007': RequestTimeout,  # Request timed out
                    'TRANSFER_008': BadRequest,  # Transferring to a leveraged account is abnormal
                    'TRANSFER_009': BadRequest,  # Departing from a leveraged account is abnormal
                    'TRANSFER_010': PermissionDenied,  # Leverage cleared, transfer prohibited
                    'TRANSFER_011': PermissionDenied,  # Leverage with borrowing, transfer prohibited
                    'TRANSFER_012': PermissionDenied,  # Currency transfer prohibited
                    'symbol_not_support_trading_via_api': BadSymbol,  # {"returnCode":1,"msgInfo":"failure","error":{"code":"symbol_not_support_trading_via_api","msg":"The symbol does not support trading via API"},"result":null}
                    'open_order_min_nominal_value_limit': InvalidOrder,  # {"returnCode":1,"msgInfo":"failure","error":{"code":"open_order_min_nominal_value_limit","msg":"Exceeds the minimum notional value of a single order"},"result":null}
                    'insufficient_balance': InsufficientFunds,
                },
                'broad': {
                    'The symbol does not support trading via API': BadSymbol,  # {"returnCode":1,"msgInfo":"failure","error":{"code":"symbol_not_support_trading_via_api","msg":"The symbol does not support trading via API"},"result":null}
                    'Exceeds the minimum notional value of a single order': InvalidOrder,  # {"returnCode":1,"msgInfo":"failure","error":{"code":"open_order_min_nominal_value_limit","msg":"Exceeds the minimum notional value of a single order"},"result":null}
                    'insufficient balance': InsufficientFunds,
                },
            },
            'timeframes': {
                '1m': '1m',
                '5m': '5m',
                '15m': '15m',
                '30m': '30m',
                '1h': '1h',  # spot only
                '2h': '2h',  # spot only
                '4h': '4h',
                '6h': '6h',  # spot only
                '8h': '8h',  # spot only
                '1d': '1d',
                '3d': '3d',  # spot only
                '1w': '1w',
                '1M': '1M',  # spot only
            },
            'commonCurrencies': {},
            'options': {
                'adjustForTimeDifference': False,
                'timeDifference': 0,
                'accountsById': {
                    'spot': 'SPOT',
                    'leverage': 'LEVER',
                    'finance': 'FINANCE',
                    'swap': 'FUTURES_U',
                    'future': 'FUTURES_U',
                    'linear': 'FUTURES_U',
                    'inverse': 'FUTURES_C',
                },
                'networks': {
                    'ERC20': 'Ethereum',
                    'TRC20': 'Tron',
                    'BEP20': 'BNB Smart Chain',
                    'BEP2': 'BNB-BEP2',
                    'ETH': 'Ethereum',
                    'TRON': 'Tron',
                    'BNB': 'BNB Smart Chain',
                    'AVAX': 'AVAX C-Chain',
                    'GAL': 'GAL(FT)',
                    'ALEO': 'ALEO(IOU)',
                    'BTC': 'Bitcoin',
                    'XT': 'XT Smart Chain',
                    'ETC': 'Ethereum Classic',
                    'MATIC': 'Polygon',
                    'LTC': 'Litecoin',
                    'BTS': 'BitShares',
                    'XRP': 'Ripple',
                    'XLM': 'Stellar Network',
                    'ADA': 'Cardano',
                    'XWC': 'XWC-XWC',
                    'DOGE': 'dogecoin',
                    'DCR': 'Decred',
                    'SC': 'Siacoin',
                    'XTZ': 'Tezos',
                    'ZEC': 'Zcash',
                    'XMR': 'Monero',
                    'LSK': 'Lisk',
                    'ATOM': 'Cosmos',
                    'ONT': 'Ontology',
                    'ALGO': 'Algorand',
                    'SOL': 'SOL-SOL',
                    'DOT': 'Polkadot',
                    'ZEN': 'Horizen',
                    'FIL': 'Filecoin',
                    'CHZ': 'chz',
                    'ICP': 'Internet Computer',
                    'KSM': 'Kusama',
                    'LUNA': 'Terra',
                    'THETA': 'Theta Token',
                    'FTM': 'Fantom',
                    'VET': 'VeChain',
                    'NEAR': 'NEAR Protocol',
                    'ONE': 'Harmony',
                    'KLAY': 'Klaytn',
                    'AR': 'Arweave',
                    'CELT': 'OKT',
                    'EGLD': 'Elrond eGold',
                    'CRO': 'CRO-CRONOS',
                    'BCH': 'Bitcoin Cash',
                    'GLMR': 'Moonbeam',
                    'LOOP': 'LOOP-LRC',
                    'REI': 'REI Network',
                    'ASTR': 'Astar Network',
                    'OP': 'OPT',
                    'MMT': 'MMT-MMT',
                    'TBC': 'TBC-TBC',
                    'OMAX': 'OMAX-OMAX CHAIN',
                    'GMMT': 'GMMT chain',
                    'ZIL': 'Zilliqa',
                },
                'networksById': {
                    'Ethereum': 'ERC20',
                    'Tron': 'TRC20',
                    'BNB Smart Chain': 'BEP20',
                    'BNB-BEP2': 'BEP2',
                    'Bitcoin': 'BTC',
                    'XT Smart Chain': 'XT',
                    'Ethereum Classic': 'ETC',
                    'Polygon': 'MATIC',
                    'Litecoin': 'LTC',
                    'BitShares': 'BTS',
                    'Ripple': 'XRP',
                    'Stellar Network': 'XLM',
                    'Cardano': 'ADA',
                    'XWC-XWC': 'XWC',
                    'dogecoin': 'DOGE',
                    'Decred': 'DCR',
                    'Siacoin': 'SC',
                    'Tezos': 'XTZ',
                    'Zcash': 'ZEC',
                    'Monero': 'XMR',
                    'Lisk': 'LSK',
                    'Cosmos': 'ATOM',
                    'Ontology': 'ONT',
                    'Algorand': 'ALGO',
                    'SOL-SOL': 'SOL',
                    'Polkadot': 'DOT',
                    'Horizen': 'ZEN',
                    'Filecoin': 'FIL',
                    'chz': 'CHZ',
                    'Internet Computer': 'ICP',
                    'Kusama': 'KSM',
                    'Terra': 'LUNA',
                    'Theta Token': 'THETA',
                    'Fantom': 'FTM',
                    'VeChain': 'VET',
                    'AVAX C-Chain': 'AVAX',
                    'NEAR Protocol': 'NEAR',
                    'Harmony': 'ONE',
                    'Klaytn': 'KLAY',
                    'Arweave': 'AR',
                    'OKT': 'CELT',
                    'Elrond eGold': 'EGLD',
                    'CRO-CRONOS': 'CRO',
                    'Bitcoin Cash': 'BCH',
                    'Moonbeam': 'GLMR',
                    'LOOP-LRC': 'LOOP',
                    'REI Network': 'REI',
                    'Astar Network': 'ASTR',
                    'GAL(FT)': 'GAL',
                    'ALEO(IOU)': 'ALEO',
                    'OPT': 'OP',
                    'MMT-MMT': 'MMT',
                    'TBC-TBC': 'TBC',
                    'OMAX-OMAX CHAIN': 'OMAX',
                    'GMMT chain': 'GMMT',
                    'Zilliqa': 'ZIL',
                },
                'createMarketBuyOrderRequiresPrice': True,
                'recvWindow': '5000',  # in milliseconds, spot only
            },
            'features': {
                'default': {
                    'sandbox': False,
                    'createOrder': {
                        'marginMode': False,
                        'triggerPrice': False,
                        'triggerDirection': False,
                        'triggerPriceType': None,
                        'stopLossPrice': False,
                        'takeProfitPrice': False,
                        'attachedStopLossTakeProfit': None,
                        'timeInForce': {
                            'IOC': True,
                            'FOK': True,
                            'PO': True,
                            'GTD': False,
                        },
                        'hedged': False,
                        'trailing': False,
                        'leverage': False,
                        'marketBuyByCost': True,
                        'marketBuyRequiresPrice': False,
                        'selfTradePrevention': False,
                        'iceberg': False,
                    },
                    'createOrders': None,
                    'fetchMyTrades': {
                        'marginMode': True,
                        'limit': 100,
                        'daysBack': 100000,  # todo
                        'untilDays': 100000,  # todo
                        'marketType': True,
                        'subType': True,
                        'symbolRequired': False,
                    },
                    'fetchOrder': {
                        'marginMode': False,
                        'trigger': True,  # todo TPSL kind
                        'trailing': False,
                        'marketType': True,
                        'subType': True,
                        'symbolRequired': False,
                    },
                    'fetchOpenOrders': {
                        'marginMode': True,
                        'limit': 100,
                        'trigger': True,  # todo TPSL
                        'trailing': False,
                        'marketType': True,
                        'subType': True,
                        'symbolRequired': False,
                    },
                    'fetchOrders': {
                        'marginMode': True,
                        'limit': 100,
                        'daysBack': 100000,  # todo
                        'untilDays': 100000,  # todo
                        'trigger': True,  # todo TPSL
                        'trailing': False,
                        'marketType': True,
                        'subType': True,
                        'symbolRequired': False,
                    },
                    'fetchClosedOrders': {
                        'marginMode': True,
                        'limit': 100,
                        'daysBack': 100000,  # todo
                        'daysBackCanceled': 1,  # todo
                        'untilDays': 100000,  # todo
                        'trigger': True,  # todo TPSL
                        'trailing': False,
                        'marketType': True,
                        'subType': True,
                        'symbolRequired': False,
                    },
                    'fetchOHLCV': {
                        'limit': 1000,  # todo for derivatives
                    },
                },
                'spot': {
                    'extends': 'default',
                },
                'forDerivatives': {
                    'extends': 'default',
                    'createOrder': {
                        'triggerPrice': True,
                        # todo
                        'triggerPriceType': {
                            'last': True,
                            'mark': True,
                            'index': True,
                        },
                        'stopLossPrice': True,
                        'takeProfitPrice': True,
                    },
                    'fetchMyTrades': {
                        'daysBack': None,
                        'untilDays': None,
                    },
                },
                'swap': {
                    'linear': {
                        'extends': 'forDerivatives',
                    },
                    'inverse': {
                        'extends': 'forDerivatives',
                    },
                },
                'future': {
                    'linear': {
                        'extends': 'forDerivatives',
                    },
                    'inverse': {
                        'extends': 'forDerivatives',
                    },
                },
            },
        })

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

    def fetch_time(self, params={}) -> Int:
        """
        fetches the current integer timestamp in milliseconds from the xt server

        https://doc.xt.com/#market1serverInfo

        :param dict params: extra parameters specific to the xt api endpoint
        :returns int: the current integer timestamp in milliseconds from the xt server
        """
        response = self.publicSpotGetTime(params)
        #
        #     {
        #         "rc": 0,
        #         "mc": "SUCCESS",
        #         "ma": [],
        #         "result": {
        #             "serverTime": 1677823301643
        #         }
        #     }
        #
        data = self.safe_value(response, 'result')
        return self.safe_integer(data, 'serverTime')

    def fetch_currencies(self, params={}) -> Currencies:
        """
        fetches all available currencies on an exchange

        https://doc.xt.com/#deposit_withdrawalsupportedCurrenciesGet

        :param dict params: extra parameters specific to the xt api endpoint
        :returns dict: an associative dictionary of currencies
        """
        promisesRaw = [self.publicSpotGetWalletSupportCurrency(params), self.publicSpotGetCurrencies(params)]
        chainsResponse, currenciesResponse = promisesRaw
        #
        # currencies
        #
        #    {
        #        "time": "1686626116145",
        #        "version": "5dbbb2f2527c22b2b2e3b47187ef13d1",
        #        "currencies": [
        #            {
        #                "id": "2",
        #                "currency": "btc",
        #                "fullName": "Bitcoin",
        #                "logo": "https://a.static-global.com/1/currency/btc.png",
        #                "cmcLink": "https://coinmarketcap.com/currencies/bitcoin/",
        #                "weight": "99999",
        #                "maxPrecision": "10",
        #                "depositStatus": "1",
        #                "withdrawStatus": "1",
        #                "convertEnabled": "1",
        #                "transferEnabled": "1",
        #                "isChainExist": "1",
        #                "plates": [152]
        #            },
        #        ],
        #    }
        #
        #
        # chains
        #
        #     {
        #         "rc": 0,
        #         "mc": "SUCCESS",
        #         "ma": [],
        #         "result": [
        #             {
        #                 "currency": "btc",
        #                 "supportChains": [
        #                     {
        #                         "chain": "Bitcoin",
        #                         "depositEnabled": True,
        #                         "withdrawEnabled": True,
        #                         "withdrawFeeAmount": 0.0009,
        #                         "withdrawMinAmount": 0.0005,
        #                         "depositFeeRate": 0
        #                     },
        #                 ]
        #             },
        #         ]
        #     }
        #
        # note: individual network's full data is available on per-currency endpoint: https://www.xt.com/sapi/v4/balance/public/currency/11
        #
        chainsData = self.safe_value(chainsResponse, 'result', [])
        currenciesResult = self.safe_value(currenciesResponse, 'result', [])
        currenciesData = self.safe_value(currenciesResult, 'currencies', [])
        chainsDataIndexed = self.index_by(chainsData, 'currency')
        result = {}
        for i in range(0, len(currenciesData)):
            entry = currenciesData[i]
            currencyId = self.safe_string(entry, 'currency')
            code = self.safe_currency_code(currencyId)
            networkEntry = self.safe_value(chainsDataIndexed, currencyId, {})
            rawNetworks = self.safe_value(networkEntry, 'supportChains', [])
            networks = {}
            for j in range(0, len(rawNetworks)):
                rawNetwork = rawNetworks[j]
                networkId = self.safe_string(rawNetwork, 'chain')
                networkCode = self.network_id_to_code(networkId, code)
                networks[networkCode] = {
                    'info': rawNetwork,
                    'id': networkId,
                    'network': networkCode,
                    'name': None,
                    'active': None,
                    'fee': self.safe_number(rawNetwork, 'withdrawFeeAmount'),
                    'precision': None,
                    'deposit': self.safe_bool(rawNetwork, 'depositEnabled'),
                    'withdraw': self.safe_bool(rawNetwork, 'withdrawEnabled'),
                    'limits': {
                        'amount': {
                            'min': None,
                            'max': None,
                        },
                        'withdraw': {
                            'min': self.safe_number(rawNetwork, 'withdrawMinAmount'),
                            'max': None,
                        },
                        'deposit': {
                            'min': None,
                            'max': None,
                        },
                    },
                }
            typeRaw = self.safe_string(entry, 'type')
            type: Str = None
            if typeRaw == 'FT':
                type = 'crypto'
            else:
                type = 'other'
            result[code] = self.safe_currency_structure({
                'info': entry,
                'id': currencyId,
                'code': code,
                'name': self.safe_string(entry, 'fullName'),
                'active': None,
                'fee': None,
                'precision': self.parse_number(self.parse_precision(self.safe_string(entry, 'maxPrecision'))),
                'deposit': self.safe_string(entry, 'depositStatus') == '1',
                'withdraw': self.safe_string(entry, 'withdrawStatus') == '1',
                'networks': networks,
                'type': type,
                'limits': {
                    'amount': {
                        'min': None,
                        'max': None,
                    },
                    'withdraw': {
                        'min': None,
                        'max': None,
                    },
                    'deposit': {
                        'min': None,
                        'max': None,
                    },
                },
            })
        return result

    def fetch_markets(self, params={}) -> List[Market]:
        """
        retrieves data on all markets for xt

        https://doc.xt.com/#market2symbol
        https://doc.xt.com/#futures_quotesgetSymbols

        :param dict params: extra parameters specific to the xt api endpoint
        :returns dict[]: an array of objects representing market data
        """
        if self.options['adjustForTimeDifference']:
            self.load_time_difference()
        promisesUnresolved = [
            self.fetch_spot_markets(params),
            self.fetch_swap_and_future_markets(params),
        ]
        promises = promisesUnresolved
        spotMarkets = promises[0]
        swapAndFutureMarkets = promises[1]
        return self.array_concat(spotMarkets, swapAndFutureMarkets)

    def fetch_spot_markets(self, params={}):
        response = self.publicSpotGetSymbol(params)
        #
        #     {
        #         "rc": 0,
        #         "mc": "SUCCESS",
        #         "ma": [],
        #         "result": {
        #             "time": 1677881368812,
        #             "version": "abb101d1543e54bee40687b135411ba0",
        #             "symbols": [
        #                 {
        #                     "id": 640,
        #                     "symbol": "xt_usdt",
        #                     "state": "ONLINE",
        #                     "stateTime": 1554048000000,
        #                     "tradingEnabled": True,
        #                     "openapiEnabled": True,
        #                     "nextStateTime": null,
        #                     "nextState": null,
        #                     "depthMergePrecision": 5,
        #                     "baseCurrency": "xt",
        #                     "baseCurrencyPrecision": 8,
        #                     "baseCurrencyId": 128,
        #                     "quoteCurrency": "usdt",
        #                     "quoteCurrencyPrecision": 8,
        #                     "quoteCurrencyId": 11,
        #                     "pricePrecision": 4,
        #                     "quantityPrecision": 2,
        #                     "orderTypes": ["LIMIT","MARKET"],
        #                     "timeInForces": ["GTC","IOC"],
        #                     "displayWeight": 10002,
        #                     "displayLevel": "FULL",
        #                     "plates": [],
        #                     "filters":[
        #                         {
        #                             "filter": "QUOTE_QTY",
        #                             "min": "1"
        #                         },
        #                         {
        #                             "filter": "PROTECTION_LIMIT",
        #                             "buyMaxDeviation": "0.8",
        #                             "sellMaxDeviation": "4"
        #                         },
        #                         {
        #                             "filter": "PROTECTION_MARKET",
        #                             "maxDeviation": "0.02"
        #                         }
        #                     ]
        #                 },
        #             ]
        #         }
        #     }
        #
        data = self.safe_value(response, 'result', {})
        symbols = self.safe_value(data, 'symbols', [])
        return self.parse_markets(symbols)

    def fetch_swap_and_future_markets(self, params={}):
        markets = [self.publicLinearGetFutureMarketV1PublicSymbolList(params), self.publicInverseGetFutureMarketV1PublicSymbolList(params)]
        #
        #     {
        #         "returnCode": 0,
        #         "msgInfo": "success",
        #         "error": null,
        #         "result": [
        #             {
        #                 "id": 52,
        #                 "symbolGroupId": 71,
        #                 "symbol": "xt_usdt",
        #                 "pair": "xt_usdt",
        #                 "contractType": "PERPETUAL",
        #                 "productType": "perpetual",
        #                 "predictEventType": null,
        #                 "underlyingType": "U_BASED",
        #                 "contractSize": "1",
        #                 "tradeSwitch": True,
        #                 "isDisplay": True,
        #                 "isOpenApi": False,
        #                 "state": 0,
        #                 "initLeverage": 20,
        #                 "initPositionType": "CROSSED",
        #                 "baseCoin": "xt",
        #                 "quoteCoin": "usdt",
        #                 "baseCoinPrecision": 8,
        #                 "baseCoinDisplayPrecision": 4,
        #                 "quoteCoinPrecision": 8,
        #                 "quoteCoinDisplayPrecision": 4,
        #                 "quantityPrecision": 0,
        #                 "pricePrecision": 4,
        #                 "supportOrderType": "LIMIT,MARKET",
        #                 "supportTimeInForce": "GTC,FOK,IOC,GTX",
        #                 "supportEntrustType": "TAKE_PROFIT,STOP,TAKE_PROFIT_MARKET,STOP_MARKET,TRAILING_STOP_MARKET",
        #                 "supportPositionType": "CROSSED,ISOLATED",
        #                 "minQty": "1",
        #                 "minNotional": "5",
        #                 "maxNotional": "20000000",
        #                 "multiplierDown": "0.1",
        #                 "multiplierUp": "0.1",
        #                 "maxOpenOrders": 200,
        #                 "maxEntrusts": 200,
        #                 "makerFee": "0.0004",
        #                 "takerFee": "0.0006",
        #                 "liquidationFee": "0.01",
        #                 "marketTakeBound": "0.1",
        #                 "depthPrecisionMerge": 5,
        #                 "labels": ["HOT"],
        #                 "onboardDate": 1657101601000,
        #                 "enName": "XTUSDT ",
        #                 "cnName": "XTUSDT",
        #                 "minStepPrice": "0.0001",
        #                 "minPrice": null,
        #                 "maxPrice": null,
        #                 "deliveryDate": 1669879634000,
        #                 "deliveryPrice": null,
        #                 "deliveryCompletion": False,
        #                 "cnDesc": null,
        #                 "enDesc": null
        #             },
        #         ]
        #     }
        #
        swapAndFutureMarkets = self.array_concat(self.safe_value(markets[0], 'result', []), self.safe_value(markets[1], 'result', []))
        return self.parse_markets(swapAndFutureMarkets)

    def parse_markets(self, markets):
        result = []
        for i in range(0, len(markets)):
            result.append(self.parse_market(markets[i]))
        return result

    def parse_market(self, market: dict) -> Market:
        #
        # spot
        #
        #     {
        #         "id": 640,
        #         "symbol": "xt_usdt",
        #         "state": "ONLINE",
        #         "stateTime": 1554048000000,
        #         "tradingEnabled": True,
        #         "openapiEnabled": True,
        #         "nextStateTime": null,
        #         "nextState": null,
        #         "depthMergePrecision": 5,
        #         "baseCurrency": "xt",
        #         "baseCurrencyPrecision": 8,
        #         "baseCurrencyId": 128,
        #         "quoteCurrency": "usdt",
        #         "quoteCurrencyPrecision": 8,
        #         "quoteCurrencyId": 11,
        #         "pricePrecision": 4,
        #         "quantityPrecision": 2,
        #         "orderTypes": ["LIMIT","MARKET"],
        #         "timeInForces": ["GTC","IOC"],
        #         "displayWeight": 10002,
        #         "displayLevel": "FULL",
        #         "plates": [],
        #         "filters":[
        #             {
        #                 "filter": "QUOTE_QTY",
        #                 "min": "1"
        #             },
        #             {
        #                 "filter": "PRICE",
        #                 "min": null,
        #                 "max": null,
        #                 "tickSize": null
        #             },
        #             {
        #                 "filter": "QUANTITY",
        #                 "min": null,
        #                 "max": null,
        #                 "tickSize": null
        #             },
        #             {
        #                 "filter": "PROTECTION_LIMIT",
        #                 "buyMaxDeviation": "0.8",
        #                 "sellMaxDeviation": "4"
        #             },
        #             {
        #                 "filter": "PROTECTION_MARKET",
        #                 "maxDeviation": "0.02"
        #             },
        #             {
        #                  "filter": "PROTECTION_ONLINE",
        #                  "durationSeconds": "300",
        #                  "maxPriceMultiple": "5"
        #             },
        #         ]
        #     }
        #
        # swap and future
        #
        #     {
        #         "id": 52,
        #         "symbolGroupId": 71,
        #         "symbol": "xt_usdt",
        #         "pair": "xt_usdt",
        #         "contractType": "PERPETUAL",
        #         "productType": "perpetual",
        #         "predictEventType": null,
        #         "underlyingType": "U_BASED",
        #         "contractSize": "1",
        #         "tradeSwitch": True,
        #         "isDisplay": True,
        #         "isOpenApi": False,
        #         "state": 0,
        #         "initLeverage": 20,
        #         "initPositionType": "CROSSED",
        #         "baseCoin": "xt",
        #         "quoteCoin": "usdt",
        #         "baseCoinPrecision": 8,
        #         "baseCoinDisplayPrecision": 4,
        #         "quoteCoinPrecision": 8,
        #         "quoteCoinDisplayPrecision": 4,
        #         "quantityPrecision": 0,
        #         "pricePrecision": 4,
        #         "supportOrderType": "LIMIT,MARKET",
        #         "supportTimeInForce": "GTC,FOK,IOC,GTX",
        #         "supportEntrustType": "TAKE_PROFIT,STOP,TAKE_PROFIT_MARKET,STOP_MARKET,TRAILING_STOP_MARKET",
        #         "supportPositionType": "CROSSED,ISOLATED",
        #         "minQty": "1",
        #         "minNotional": "5",
        #         "maxNotional": "20000000",
        #         "multiplierDown": "0.1",
        #         "multiplierUp": "0.1",
        #         "maxOpenOrders": 200,
        #         "maxEntrusts": 200,
        #         "makerFee": "0.0004",
        #         "takerFee": "0.0006",
        #         "liquidationFee": "0.01",
        #         "marketTakeBound": "0.1",
        #         "depthPrecisionMerge": 5,
        #         "labels": ["HOT"],
        #         "onboardDate": 1657101601000,
        #         "enName": "XTUSDT ",
        #         "cnName": "XTUSDT",
        #         "minStepPrice": "0.0001",
        #         "minPrice": null,
        #         "maxPrice": null,
        #         "deliveryDate": 1669879634000,
        #         "deliveryPrice": null,
        #         "deliveryCompletion": False,
        #         "cnDesc": null,
        #         "enDesc": null
        #     }
        #
        id = self.safe_string(market, 'symbol')
        baseId = self.safe_string_2(market, 'baseCurrency', 'baseCoin')
        quoteId = self.safe_string_2(market, 'quoteCurrency', 'quoteCoin')
        base = self.safe_currency_code(baseId)
        quote = self.safe_currency_code(quoteId)
        state = self.safe_string(market, 'state')
        symbol = base + '/' + quote
        filters = self.safe_value(market, 'filters', [])
        minAmount = None
        maxAmount = None
        minCost = None
        maxCost = None
        minPrice = None
        maxPrice = None
        amountPrecision = None
        for i in range(0, len(filters)):
            entry = filters[i]
            filter = self.safe_string(entry, 'filter')
            if filter == 'QUANTITY':
                minAmount = self.safe_number(entry, 'min')
                maxAmount = self.safe_number(entry, 'max')
                amountPrecision = self.safe_number(entry, 'tickSize')
            if filter == 'QUOTE_QTY':
                minCost = self.safe_number(entry, 'min')
            if filter == 'PRICE':
                minPrice = self.safe_number(entry, 'min')
                maxPrice = self.safe_number(entry, 'max')
        if amountPrecision is None:
            amountPrecision = self.parse_number(self.parse_precision(self.safe_string(market, 'quantityPrecision')))
        underlyingType = self.safe_string(market, 'underlyingType')
        linear = None
        inverse = None
        settleId = None
        settle = None
        expiry = None
        future = False
        swap = False
        contract = False
        spot = True
        type = 'spot'
        if underlyingType == 'U_BASED':
            symbol = symbol + ':' + quote
            settleId = baseId
            settle = quote
            linear = True
            inverse = False
        elif underlyingType == 'COIN_BASED':
            symbol = symbol + ':' + base
            settleId = baseId
            settle = base
            linear = False
            inverse = True
        if underlyingType is not None:
            expiry = self.safe_integer(market, 'deliveryDate')
            productType = self.safe_string(market, 'productType')
            if productType != 'perpetual':
                symbol = symbol + '-' + self.yymmdd(expiry)
                type = 'future'
                future = True
            else:
                type = 'swap'
                swap = True
            minAmount = self.safe_number(market, 'minQty')
            minCost = self.safe_number(market, 'minNotional')
            maxCost = self.safe_number(market, 'maxNotional')
            minPrice = self.safe_number(market, 'minPrice')
            maxPrice = self.safe_number(market, 'maxPrice')
            contract = True
            spot = False
        isActive = False
        if contract:
            isActive = self.safe_value(market, 'isOpenApi', False)
        else:
            if (state == 'ONLINE') and (self.safe_value(market, 'tradingEnabled')) and (self.safe_value(market, 'openapiEnabled')):
                isActive = True
        return self.safe_market_structure({
            'id': id,
            'symbol': symbol,
            'base': base,
            'quote': quote,
            'settle': settle,
            'baseId': baseId,
            'quoteId': quoteId,
            'settleId': settleId,
            'type': type,
            'spot': spot,
            'margin': None,
            'swap': swap,
            'future': future,
            'option': False,
            'active': isActive,
            'contract': contract,
            'linear': linear,
            'inverse': inverse,
            'taker': self.safe_number(market, 'takerFee'),
            'maker': self.safe_number(market, 'makerFee'),
            'contractSize': self.safe_number(market, 'contractSize'),
            'expiry': expiry,
            'expiryDatetime': self.iso8601(expiry),
            'strike': None,
            'optionType': None,
            'precision': {
                'price': self.parse_number(self.parse_precision(self.safe_string(market, 'pricePrecision'))),
                'amount': amountPrecision,
                'base': self.parse_number(self.parse_precision(self.safe_string(market, 'baseCoinPrecision'))),
                'quote': self.parse_number(self.parse_precision(self.safe_string(market, 'quoteCoinPrecision'))),
            },
            'limits': {
                'leverage': {
                    'min': self.parse_number('1'),
                    'max': None,
                },
                'amount': {
                    'min': minAmount,
                    'max': maxAmount,
                },
                'price': {
                    'min': minPrice,
                    'max': maxPrice,
                },
                'cost': {
                    'min': minCost,
                    'max': maxCost,
                },
            },
            'info': market,
        })

    def fetch_ohlcv(self, symbol: str, timeframe: str = '1m', since: Int = None, limit: Int = None, params={}):
        """
        fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market

        https://doc.xt.com/#market4kline
        https://doc.xt.com/#futures_quotesgetKLine

        :param str symbol: unified symbol of the market to fetch OHLCV data for
        :param str timeframe: the length of time each candle represents
        :param int [since]: timestamp in ms of the earliest candle to fetch
        :param int [limit]: the maximum amount of candles to fetch
        :param dict params: extra parameters specific to the xt api endpoint
        :param int [params.until]: timestamp in ms of the latest candle to fetch
        :param boolean [params.paginate]: default False, when True will automatically paginate by calling self endpoint multiple times. See in the docs all the [available parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
        :returns int[][]: A list of candles ordered, open, high, low, close, volume
        """
        self.load_markets()
        paginate = False
        paginate, params = self.handle_option_and_params(params, 'fetchOHLCV', 'paginate', False)
        if paginate:
            return self.fetch_paginated_call_deterministic('fetchOHLCV', symbol, since, limit, timeframe, params, 1000)
        market = self.market(symbol)
        request = {
            'symbol': market['id'],
            'interval': self.safe_string(self.timeframes, timeframe, timeframe),
        }
        if since is not None:
            request['startTime'] = since
        if limit is not None:
            if market['spot']:
                limit = min(limit, 1000)  # spot max limit
            else:
                limit = min(limit, 1500)  # derivatives max limit
            request['limit'] = limit
        else:
            request['limit'] = 1000
        until = self.safe_integer(params, 'until')
        params = self.omit(params, ['until'])
        if until is not None:
            request['endTime'] = until
        response = None
        if market['linear']:
            response = self.publicLinearGetFutureMarketV1PublicQKline(self.extend(request, params))
        elif market['inverse']:
            response = self.publicInverseGetFutureMarketV1PublicQKline(self.extend(request, params))
        else:
            response = self.publicSpotGetKline(self.extend(request, params))
        #
        # spot
        #
        #     {
        #         "rc": 0,
        #         "mc": "SUCCESS",
        #         "ma": [],
        #         "result": [
        #             {
        #                 "t": 1678167720000,
        #                 "o": "22467.85",
        #                 "c": "22465.87",
        #                 "h": "22468.86",
        #                 "l": "22465.21",
        #                 "q": "1.316656",
        #                 "v": "29582.73018498"
        #             },
        #         ]
        #     }
        #
        # swap and future
        #
        #     {
        #         "returnCode": 0,
        #         "msgInfo": "success",
        #         "error": null,
        #         "result": [
        #             {
        #                 "s": "btc_usdt",
        #                 "p": "btc_usdt",
        #                 "t": 1678168020000,
        #                 "o": "22450.0",
        #                 "c": "22441.5",
        #                 "h": "22450.0",
        #                 "l": "22441.5",
        #                 "a": "312931",
        #                 "v": "702461.58895"
        #             },
        #         ]
        #     }
        #
        ohlcvs = self.safe_value(response, 'result', [])
        return self.parse_ohlcvs(ohlcvs, market, timeframe, since, limit)

    def parse_ohlcv(self, ohlcv, market: Market = None) -> list:
        #
        # spot
        #
        #     {
        #         "t": 1678167720000,
        #         "o": "22467.85",
        #         "c": "22465.87",
        #         "h": "22468.86",
        #         "l": "22465.21",
        #         "q": "1.316656",
        #         "v": "29582.73018498"
        #     }
        #
        # swap and future
        #
        #     {
        #         "s": "btc_usdt",
        #         "p": "btc_usdt",
        #         "t": 1678168020000,
        #         "o": "22450.0",
        #         "c": "22441.5",
        #         "h": "22450.0",
        #         "l": "22441.5",
        #         "a": "312931",
        #         "v": "702461.58895"
        #     }
        #
        volumeIndex = 'v' if (market['inverse']) else 'a'
        return [
            self.safe_integer(ohlcv, 't'),
            self.safe_number(ohlcv, 'o'),
            self.safe_number(ohlcv, 'h'),
            self.safe_number(ohlcv, 'l'),
            self.safe_number(ohlcv, 'c'),
            self.safe_number_2(ohlcv, 'q', volumeIndex),
        ]

    def fetch_order_book(self, symbol: str, limit: Int = None, params={}):
        """

        https://doc.xt.com/#market3depth
        https://doc.xt.com/#futures_quotesgetDepth

        fetches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
        :param str symbol: unified market symbol to fetch the order book for
        :param int [limit]: the maximum amount of order book entries to return
        :param dict params: extra parameters specific to the xt 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
        """
        self.load_markets()
        market = self.market(symbol)
        request = {
            'symbol': market['id'],
        }
        response = None
        if market['spot']:
            if limit is not None:
                request['limit'] = min(limit, 500)
            response = self.publicSpotGetDepth(self.extend(request, params))
        else:
            if limit is not None:
                request['level'] = min(limit, 50)
            else:
                request['level'] = 50
            if market['linear']:
                response = self.publicLinearGetFutureMarketV1PublicQDepth(self.extend(request, params))
            elif market['inverse']:
                response = self.publicInverseGetFutureMarketV1PublicQDepth(self.extend(request, params))
        #
        # spot
        #
        #     {
        #         "rc": 0,
        #         "mc": "SUCCESS",
        #         "ma": [],
        #         "result": {
        #             "timestamp": 1678169975184,
        #             "lastUpdateId": 1675333221812,
        #             "bids": [
        #                 ["22444.51", "0.129887"],
        #                 ["22444.49", "0.114245"],
        #                 ["22444.30", "0.225956"]
        #             ],
        #             "asks": [
        #                 ["22446.19", "0.095330"],
        #                 ["22446.24", "0.224413"],
        #                 ["22446.28", "0.329095"]
        #             ]
        #         }
        #     }
        #
        # swap and future
        #
        #     {
        #         "returnCode": 0,
        #         "msgInfo": "success",
        #         "error": null,
        #         "result": {
        #             "t": 1678170311005,
        #             "s": "btc_usdt",
        #             "u": 471694545627,
        #             "b": [
        #                 ["22426", "198623"],
        #                 ["22423.5", "80295"],
        #                 ["22423", "163580"]
        #             ],
        #             "a": [
        #                 ["22427", "3417"],
        #                 ["22428.5", "43532"],
        #                 ["22429", "119"]
        #             ]
        #         }
        #     }
        #
        orderBook = self.safe_value(response, 'result', {})
        timestamp = self.safe_integer_2(orderBook, 'timestamp', 't')
        if market['spot']:
            ob = self.parse_order_book(orderBook, symbol, timestamp)
            ob['nonce'] = self.safe_integer(orderBook, 'lastUpdateId')
            return ob
        swapOb = self.parse_order_book(orderBook, symbol, timestamp, 'b', 'a')
        swapOb['nonce'] = self.safe_integer_2(orderBook, 'u', 'lastUpdateId')
        return swapOb

    def fetch_ticker(self, symbol: str, params={}):
        """
        fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market

        https://doc.xt.com/#market10ticker24h
        https://doc.xt.com/#futures_quotesgetAggTicker

        :param str symbol: unified market symbol to fetch the ticker for
        :param dict params: extra parameters specific to the xt api endpoint
        :returns dict: a `ticker structure <https://docs.ccxt.com/en/latest/manual.html#ticker-structure>`
        """
        self.load_markets()
        market = self.market(symbol)
        request = {
            'symbol': market['id'],
        }
        response = None
        if market['linear']:
            response = self.publicLinearGetFutureMarketV1PublicQAggTicker(self.extend(request, params))
        elif market['inverse']:
            response = self.publicInverseGetFutureMarketV1PublicQAggTicker(self.extend(request, params))
        else:
            response = self.publicSpotGetTicker24h(self.extend(request, params))
        #
        # spot
        #
        #     {
        #         "rc": 0,
        #         "mc": "SUCCESS",
        #         "ma": [],
        #         "result": [
        #             {
        #                 "s": "btc_usdt",
        #                 "t": 1678172693931,
        #                 "cv": "34.00",
        #                 "cr": "0.0015",
        #                 "o": "22398.05",
        #                 "l": "22323.72",
        #                 "h": "22600.50",
        #                 "c": "22432.05",
        #                 "q": "7962.256931",
        #                 "v": "178675209.47416856"
        #             }
        #         ]
        #     }
        #
        # swap and future
        #
        #     {
        #         "returnCode": 0,
        #         "msgInfo": "success",
        #         "error": null,
        #         "result": {
        #             "t": 1678172848572,
        #             "s": "btc_usdt",
        #             "c": "22415.5",
        #             "h": "22590.0",
        #             "l": "22310.0",
        #             "a": "623654031",
        #             "v": "1399166074.31675",
        #             "o": "22381.5",
        #             "r": "0.0015",
        #             "i": "22424.5",
        #             "m": "22416.5",
        #             "bp": "22415",
        #             "ap": "22415.5"
        #         }
        #     }
        #
        ticker = self.safe_value(response, 'result')
        if market['spot']:
            return self.parse_ticker(ticker[0], market)
        return self.parse_ticker(ticker, market)

    def fetch_tickers(self, symbols: List[str] = None, params={}) -> Tickers:
        """
        fetches price tickers for multiple markets, statistical calculations with the information calculated over the past 24 hours each market

        https://doc.xt.com/#market10ticker24h
        https://doc.xt.com/#futures_quotesgetAggTickers

        :param str [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 xt api endpoint
        :returns dict: an array of `ticker structures <https://docs.ccxt.com/en/latest/manual.html#ticker-structure>`
        """
        self.load_markets()
        market = None
        if symbols is not None:
            symbols = self.market_symbols(symbols)
            market = self.market(symbols[0])
        request = {}
        type = None
        subType = None
        response = None
        type, params = self.handle_market_type_and_params('fetchTickers', market, params)
        subType, params = self.handle_sub_type_and_params('fetchTickers', market, params)
        if subType == 'inverse':
            response = self.publicInverseGetFutureMarketV1PublicQAggTickers(self.extend(request, params))
        elif (subType == 'linear') or (type == 'swap') or (type == 'future'):
            response = self.publicLinearGetFutureMarketV1PublicQAggTickers(self.extend(request, params))
        else:
            response = self.publicSpotGetTicker24h(self.extend(request, params))
        #
        # spot
        #
        #     {
        #         "rc": 0,
        #         "mc": "SUCCESS",
        #         "ma": [],
        #         "result": [
        #             {
        #                 "s": "btc_usdt",
        #                 "t": 1678172693931,
        #                 "cv": "34.00",
        #                 "cr": "0.0015",
        #                 "o": "22398.05",
        #                 "l": "22323.72",
        #                 "h": "22600.50",
        #                 "c": "22432.05",
        #                 "q": "7962.256931",
        #                 "v": "178675209.47416856"
        #             }
        #         ]
        #     }
        #
        # swap and future
        #
        #     {
        #         "returnCode": 0,
        #         "msgInfo": "success",
        #         "error": null,
        #         "result": [
        #             {
        #                 "t": 1680738775108,
        #                 "s": "badger_usdt",
        #                 "c": "2.7176",
        #                 "h": "2.7917",
        #                 "l": "2.6818",
        #                 "a": "88332",
        #                 "v": "242286.3520",
        #                 "o": "2.7422",
        #                 "r": "-0.0089",
        #                 "i": "2.7155",
        #                 "m": "2.7161",
        #                 "bp": "2.7152",
        #                 "ap": "2.7176"
        #             },
        #         ]
        #     }
        #
        tickers = self.safe_value(response, 'result', [])
        result = {}
        for i in range(0, len(tickers)):
            ticker = self.parse_ticker(tickers[i], market)
            symbol = ticker['symbol']
            result[symbol] = ticker
        return self.filter_by_array(result, 'symbol', symbols)

    def fetch_bids_asks(self, symbols: List[str] = None, params={}):
        """
        fetches the bid and ask price and volume for multiple markets

        https://doc.xt.com/#market9tickerBook

        :param str [symbols]: unified symbols of the markets to fetch the bids and asks for, all markets are returned if not assigned
        :param dict params: extra parameters specific to the xt api endpoint
        :returns dict: a dictionary of `ticker structures <https://docs.ccxt.com/en/latest/manual.html#ticker-structure>`
        """
        self.load_markets()
        symbols = self.market_symbols(symbols)
        request = {}
        market = None
        if symbols is not None:
            market = self.market(symbols[0])
        subType = None
        subType, params = self.handle_sub_type_and_params('fetchBidsAsks', market, params)
        if subType is not None:
            raise NotSupported(self.id + ' fetchBidsAsks() is not available for swap and future markets, only spot markets are supported')
        response = self.publicSpotGetTickerBook(self.extend(request, params))
        #
        #     {
        #         "rc": 0,
        #         "mc": "SUCCESS",
        #         "ma": [],
        #         "result": [
        #             {
        #                 "s": "kas_usdt",
        #                 "t": 1679539891853,
        #                 "ap": "0.016298",
        #                 "aq": "5119.09",
        #                 "bp": "0.016290",
        #                 "bq": "135.37"
        #             },
        #         ]
        #     }
        #
        tickers = self.safe_value(response, 'result', [])
        return self.parse_tickers(tickers, symbols)

    def parse_ticker(self, ticker, market=None):
        #
        # spot: fetchTicker, fetchTickers
        #
        #     {
        #         "s": "btc_usdt",
        #         "t": 1678172693931,
        #         "cv": "34.00",
        #         "cr": "0.0015",
        #         "o": "22398.05",
        #         "l": "22323.72",
        #         "h": "22600.50",
        #         "c": "22432.05",
        #         "q": "7962.256931",
        #         "v": "178675209.47416856"
        #     }
        #
        # swap and future: fetchTicker, fetchTickers
        #
        #     {
        #         "t": 1678172848572,
        #         "s": "btc_usdt",
        #         "c": "22415.5",
        #         "h": "22590.0",
        #         "l": "22310.0",
        #         "a": "623654031",
        #         "v": "1399166074.31675",
        #         "o": "22381.5",
        #         "r": "0.0015",
        #         "i": "22424.5",
        #         "m": "22416.5",
        #         "bp": "22415",
        #         "ap": "22415.5"
        #     }
        #
        # fetchBidsAsks
        #
        #     {
        #         "s": "kas_usdt",
        #         "t": 1679539891853,
        #         "ap": "0.016298",
        #         "aq": "5119.09",
        #         "bp": "0.016290",
        #         "bq": "135.37"
        #     }
        #
        marketId = self.safe_string(ticker, 's')
        marketType = market['type'] if (market is not None) else None
        hasSpotKeys = ('cv' in ticker) or ('aq' in ticker)
        if marketType is None:
            marketType = 'spot' if hasSpotKeys else 'contract'
        market = self.safe_market(marketId, market, '_', marketType)
        symbol = market['symbol']
        timestamp = self.safe_integer(ticker, 't')
        percentage = self.safe_string_2(ticker, 'cr', 'r')
        if percentage is not None:
            percentage = Precise.string_mul(percentage, '100')
        return self.safe_ticker({
            'symbol': symbol,
            'timestamp': timestamp,
            'datetime': self.iso8601(timestamp),
            'high': self.safe_number(ticker, 'h'),
            'low': self.safe_number(ticker, 'l'),
            'bid': self.safe_number(ticker, 'bp'),
            'bidVolume': self.safe_number(ticker, 'bq'),
            'ask': self.safe_number(ticker, 'ap'),
            'askVolume': self.safe_number(ticker, 'aq'),
            'vwap': None,
            'open': self.safe_string(ticker, 'o'),
            'close': self.safe_string(ticker, 'c'),
            'last': self.safe_string(ticker, 'c'),
            'previousClose': None,
            'change': self.safe_number(ticker, 'cv'),
            'percentage': self.parse_number(percentage),
            'average': None,
            'baseVolume': self.safe_number(ticker, 'a'),
            'quoteVolume': self.safe_number(ticker, 'v'),
            'info': ticker,
        }, market)

    def fetch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}):
        """
        get the list of most recent trades for a particular symbol

        https://doc.xt.com/#market5tradeRecent
        https://doc.xt.com/#futures_quotesgetDeal

        :param str symbol: unified market symbol to fetch trades for
        :param int [since]: timestamp in ms of the earliest trade to fetch
        :param int [limit]: the maximum amount of trades to fetch
        :param dict params: extra parameters specific to the xt api endpoint
        :returns dict[]: a list of `trade structures <https://docs.ccxt.com/en/latest/manual.html?#public-trades>`
        """
        self.load_markets()
        market = self.market(symbol)
        request = {
            'symbol': market['id'],
        }
        response = None
        if market['spot']:
            if limit is not None:
                request['limit'] = min(limit, 1000)
            response = self.publicSpotGetTradeRecent(self.extend(request, params))
        else:
            if limit is not None:
                request['num'] = min(limit, 1000)
            if market['linear']:
                response = self.publicLinearGetFutureMarketV1PublicQDeal(self.extend(request, params))
            elif market['inverse']:
                response = self.publicInverseGetFutureMarketV1PublicQDeal(self.extend(request, params))
        #
        # spot
        #
        #     {
        #         "rc": 0,
        #         "mc": "SUCCESS",
        #         "ma": [],
        #         "result": [
        #             {
        #                 "i": 203530723141917063,
        #                 "t": 1678227505815,
        #                 "p": "22038.81",
        #                 "q": "0.000978",
        #                 "v": "21.55395618",
        #                 "b": True
        #             },
        #         ]
        #     }
        #
        # swap and future
        #
        #     {
        #         "returnCode": 0,
        #         "msgInfo": "success",
        #         "error": null,
        #         "result": [
        #             {
        #                 "t": 1678227683897,
        #                 "s": "btc_usdt",
        #                 "p": "22031",
        #                 "a": "1067",
        #                 "m": "BID"
        #             },
        #         ]
        #     }
        #
        trades = self.safe_value(response, 'result', [])
        return self.parse_trades(trades, market)

    def fetch_my_trades(self, symbol: str = None, since: Int = None, limit: Int = None, params={}):
        """
        fetch all trades made by the user

        https://doc.xt.com/#tradetradeGet
        https://doc.xt.com/#futures_ordergetTrades

        :param str [symbol]: unified market symbol to fetch trades for
        :param int [since]: timestamp in ms of the earliest trade to fetch
        :param int [limit]: the maximum amount of trades to fetch
        :param dict params: extra parameters specific to the xt api endpoint
        :returns dict[]: a list of `trade structures <https://docs.ccxt.com/en/latest/manual.html?#public-trades>`
        """
        self.load_markets()
        request = {}
        market = None
        if symbol is not None:
            market = self.market(symbol)
            request['symbol'] = market['id']
        if since is not None:
            request['startTime'] = since
        type = None
        subType = None
        response = None
        type, params = self.handle_market_type_and_params('fetchMyTrades', market, params)
        subType, params = self.handle_sub_type_and_params('fetchMyTrades', market, params)
        if (subType is not None) or (type == 'swap') or (type == 'future'):
            if limit is not None:
                request['size'] = limit
            if subType == 'inverse':
                response = self.privateInverseGetFutureTradeV1OrderTradeList(self.extend(request, params))
            else:
                response = self.privateLinearGetFutureTradeV1OrderTradeList(self.extend(request, params))
        else:
            marginMode = None
            marginMode, params = self.handle_margin_mode_and_params('fetchMyTrades', params)
            marginOrSpotRequest = 'LEVER' if (marginMode is not None) else 'SPOT'
            request['bizType'] = marginOrSpotRequest
            if limit is not None:
                request['limit'] = limit
            response = self.privateSpotGetTrade(self.extend(request, params))
        #
        # spot and margin
        #
        #     {
        #         "rc": 0,
        #         "mc": "SUCCESS",
        #         "ma": [],
        #         "result": {
        #             "hasPrev": False,
        #             "hasNext": False,
        #             "items": [
        #                 {
        #                     "symbol": "btc_usdt",
        #                     "tradeId": "206906233569974658",
        #                     "orderId": "206906233178463488",
        #                     "orderSide": "SELL",
        #                     "orderType": "MARKET",
        #                     "bizType": "SPOT",
        #                     "time": 1679032290215,
        #                     "price": "25703.46",
        #                     "quantity": "0.000099",
        #                     "quoteQty": "2.54464254",
        #                     "baseCurrency": "btc",
        #                     "quoteCurrency": "usdt",
        #                     "fee": "0.00508929",
        #                     "feeCurrency": "usdt",
        #                     "takerMaker": "TAKER"
        #                 },
        #             ]
        #         }
        #     }
        #
        # swap and future
        #
        #     {
        #         "returnCode": 0,
        #         "msgInfo": "success",
        #         "error": null,
        #         "result": {
        #             "page": 1,
        #             "ps": 10,
        #             "total": 2,
        #             "items": [
        #                 {
        #                     "orderId": "207260566170987200",
        #                     "execId": "207260566790603265",
        #                     "symbol": "btc_usdt",
        #                     "quantity": "13",
        #                     "price": "27368",
        #                     "fee": "0.02134704",
        #                     "feeCoin": "usdt",
        #                     "timestamp": 1679116769838,
        #                     "takerMaker": "TAKER"
        #                 },
        #             ]
        #         }
        #     }
        #
        data = self.safe_value(response, 'result', {})
        trades = self.safe_value(data, 'items', [])
        return self.parse_trades(trades, market, since, limit)

    def parse_trade(self, trade, market=None):
        #
        # spot: fetchTrades
        #
        #     {
        #         "i": 203530723141917063,
        #         "t": 1678227505815,
        #         "p": "22038.81",
        #         "q": "0.000978",
        #         "v": "21.55395618",
        #         "b": True
        #     }
        #
        # spot: watchTrades
        #
        #    {
        #        s: 'btc_usdt',
        #        i: '228825383103928709',
        #        t: 1684258222702,
        #        p: '27003.65',
        #        q: '0.000796',
        #        b: True
        #    }
        #
        # spot: watchMyTrades
        #
        #    {
        #        "s": "btc_usdt",                # symbol
        #        "t": 1656043204763,             # time
        #        "i": "6316559590087251233",     # tradeId
        #        "oi": "6216559590087220004",    # orderId
        #        "p": "30000",                   # trade price
        #        "q": "3",                       # qty quantity
        #        "v": "90000"                    # volume trade amount
        #    }
        #
        # swap and future: fetchTrades
        #
        #     {
        #         "t": 1678227683897,
        #         "s": "btc_usdt",
        #         "p": "22031",
        #         "a": "1067",
        #         "m": "BID"
        #     }
        #
        # spot: fetchMyTrades
        #
        #     {
        #         "symbol": "btc_usdt",
        #         "tradeId": "206906233569974658",
        #         "orderId": "206906233178463488",
        #         "orderSide": "SELL",
        #         "orderType": "MARKET",
        #         "bizType": "SPOT",
        #         "time": 1679032290215,
        #         "price": "25703.46",
        #         "quantity": "0.000099",
        #         "quoteQty": "2.54464254",
        #         "baseCurrency": "btc",
        #         "quoteCurrency": "usdt",
        #         "fee": "0.00508929",
        #         "feeCurrency": "usdt",
        #         "takerMaker": "TAKER"
        #     }
        #
        # swap and future: fetchMyTrades
        #
        #     {
        #         "orderId": "207260566170987200",
        #         "execId": "207260566790603265",
        #         "symbol": "btc_usdt",
        #         "quantity": "13",
        #         "price": "27368",
        #         "fee": "0.02134704",
        #         "feeCoin": "usdt",
        #         "timestamp": 1679116769838,
        #         "takerMaker": "TAKER"
        #     }
        #
        # contract watchMyTrades
        #
        #    {
        #        "symbol": 'btc_usdt',
        #        "orderSide": 'SELL',
        #        "positionSide": 'LONG',
        #        "orderId": '231485367663419328',
        #        "price": '27152.7',
        #        "quantity": '33',
        #        "marginUnfrozen": '2.85318000',
        #        "timestamp": 1684892412565
        #    }
        #
        # watchMyTrades(ws, swap)
        #
        #    {
        #        'fee': '0.04080840',
        #        'isMaker': False,
        #        'marginUnfrozen': '0.75711984',
        #        'orderId': '376172779053188416',
        #        'orderSide': 'BUY',
        #        'positionSide': 'LONG',
        #        'price': '3400.70',
        #        'quantity': '2',
        #        'symbol': 'eth_usdt',
        #        'timestamp': 1719388579622
        #    }
        #
        marketId = self.safe_string_2(trade, 's', 'symbol')
        marketType = market['type'] if (market is not None) else None
        hasSpotKeys = ('b' in trade) or ('bizType' in trade) or ('oi' in trade)
        if marketType is None:
            marketType = 'spot' if hasSpotKeys else 'contract'
        market = self.safe_market(marketId, market, '_', marketType)
        side = None
        takerOrMaker = None
        isBuyerMaker = self.safe_bool(trade, 'b')
        if isBuyerMaker is not None:
            side = 'sell' if isBuyerMaker else 'buy'
            takerOrMaker = 'taker'  # public trades always taker
        else:
            takerMaker = self.safe_string_lower(trade, 'takerMaker')
            if takerMaker is not None:
                takerOrMaker = takerMaker
            else:
                isMaker = self.safe_bool(trade, 'isMaker')
                if isMaker is not None:
                    takerOrMaker = 'maker' if isMaker else 'taker'
            orderSide = self.safe_string_lower(trade, 'orderSide')
            if orderSide is not None:
                side = orderSide
            else:
                bidOrAsk = self.safe_string(trade, 'm')
                if bidOrAsk is not None:
                    side = 'buy' if (bidOrAsk == 'BID') else 'sell'
        timestamp = self.safe_integer_n(trade, ['t', 'time', 'timestamp'])
        quantity = self.safe_string_2(trade, 'q', 'quantity')
        amount = None
        if marketType == 'spot':
            amount = quantity
        else:
            if quantity is None:
                amount = Precise.string_mul(self.safe_string(trade, 'a'), self.number_to_string(market['contractSize']))
            else:
                amount = Precise.string_mul(quantity, self.number_to_string(market['contractSize']))
        return self.safe_trade({
            'info': trade,
            'id': self.safe_string_n(trade, ['i', 'tradeId', 'execId']),
            'timestamp': timestamp,
            'datetime': self.iso8601(timestamp),
            'symbol': market['symbol'],
            'order': self.safe_string_2(trade, 'orderId', 'oi'),
            'type': self.safe_string_lower(trade, 'orderType'),
            'side': side,
            'takerOrMaker': takerOrMaker,
            'price': self.safe_string_2(trade, 'p', 'price'),
            'amount': amount,
            'cost': None,
            'fee': {
                'currency': self.safe_currency_code(self.safe_string_2(trade, 'feeCurrency', 'feeCoin')),
                'cost': self.safe_string(trade, 'fee'),
            },
        }, market)

    def fetch_balance(self, params={}):
        """
        query for balance and get the amount of funds available for trading or funds locked in orders

        https://doc.xt.com/#balancebalancesGet
        https://doc.xt.com/#futures_usergetBalances

        :param dict params: extra parameters specific to the xt api endpoint
        :returns dict: a `balance structure <https://docs.ccxt.com/en/latest/manual.html?#balance-structure>`
        """
        self.load_markets()
        type = None
        subType = None
        response = None
        type, params = self.handle_market_type_and_params('fetchBalance', None, params)
        subType, params = self.handle_sub_type_and_params('fetchBalance', None, params)
        isContractWallet = ((type == 'swap') or (type == 'future'))
        if subType == 'inverse':
            response = self.privateInverseGetFutureUserV1BalanceList(params)
        elif (subType == 'linear') or isContractWallet:
            response = self.privateLinearGetFutureUserV1BalanceList(params)
        else:
            response = self.privateSpotGetBalances(params)
        #
        # spot
        #
        #     {
        #         "rc": 0,
        #         "mc": "SUCCESS",
        #         "ma": [],
        #         "result": {
        #             "totalUsdtAmount": "31.75931133",
        #             "totalBtcAmount": "0.00115951",
        #             "assets": [
        #                 {
        #                     "currency": "usdt",
        #                     "currencyId": 11,
        #                     "frozenAmount": "0.03834082",
        #                     "availableAmount": "31.70995965",
        #                     "totalAmount": "31.74830047",
        #                     "convertBtcAmount": "0.00115911",
        #                     "convertUsdtAmount": "31.74830047"
        #                 },
        #             ]
        #         }
        #     }
        #
        # swap and future
        #
        #     {
        #         "returnCode": 0,
        #         "msgInfo": "success",
        #         "error": null,
        #         "result": [
        #             {
        #                 "coin": "usdt",
        #                 "walletBalance": "19.29849875",
        #                 "openOrderMarginFrozen": "0",
        #                 "isolatedMargin": "0.709475",
        #                 "crossedMargin": "0",
        #                 "availableBalance": "18.58902375",
        #                 "bonus": "0",
        #                 "coupon":"0"
        #             }
        #         ]
        #     }
        #
        balances = None
        if (subType is not None) or isContractWallet:
            balances = self.safe_value(response, 'result', [])
        else:
            data = self.safe_value(response, 'result', {})
            balances = self.safe_value(data, 'assets', [])
        return self.parse_balance(balances)

    def parse_balance(self, response):
        #
        # spot
        #
        #     {
        #         "currency": "usdt",
        #         "currencyId": 11,
        #         "frozenAmount": "0.03834082",
        #         "availableAmount": "31.70995965",
        #         "totalAmount": "31.74830047",
        #         "convertBtcAmount": "0.00115911",
        #         "convertUsdtAmount": "31.74830047"
        #     }
        #
        # swap and future
        #
        #     {
        #         "coin": "usdt",
        #         "walletBalance": "19.29849875",
        #         "openOrderMarginFrozen": "0",
        #         "isolatedMargin": "0.709475",
        #         "crossedMargin": "0",
        #         "availableBalance": "18.58902375",
        #         "bonus": "0",
        #         "coupon":"0"
        #     }
        #
        result = {'info': response}
        for i in range(0, len(response)):
            balance = response[i]
            currencyId = self.safe_string_2(balance, 'currency', 'coin')
            code = self.safe_currency_code(currencyId)
            account = self.account()
            free = self.safe_string_2(balance, 'availableAmount', 'availableBalance')
            used = self.safe_string(balance, 'frozenAmount')
            total = self.safe_string_2(balance, 'totalAmount', 'walletBalance')
            if used is None:
                crossedAndIsolatedMargin = Precise.string_add(self.safe_string(balance, 'crossedMargin'), self.safe_string(balance, 'isolatedMargin'))
                used = Precise.string_add(self.safe_string(balance, 'openOrderMarginFrozen'), crossedAndIsolatedMargin)
            account['free'] = free
            account['used'] = used
            account['total'] = total
            result[code] = account
        return self.safe_balance(result)

    def create_market_buy_order_with_cost(self, symbol: str, cost: float, params={}):
        """

        https://doc.xt.com/#orderorderPost

        create a market buy order by providing the symbol and cost
        :param str symbol: unified symbol of the market to create an order in
        :param float cost: how much you want to trade in units of the quote currency
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: an `order structure <https://docs.ccxt.com/?id=order-structure>`
        """
        self.load_markets()
        market = self.market(symbol)
        if not market['spot']:
            raise NotSupported(self.id + ' createMarketBuyOrderWithCost() supports spot orders only')
        return self.create_order(symbol, 'market', 'buy', cost, 1, params)

    def create_order(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
        """
        create a trade order

        https://doc.xt.com/#orderorderPost
        https://doc.xt.com/#futures_ordercreate
        https://doc.xt.com/#futures_entrustcreatePlan
        https://doc.xt.com/#futures_entrustcreateProfit

        :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 you want to trade in units of the base currency
        :param float [price]: the price to fulfill the order, in units of the quote currency, can be ignored in market orders
        :param dict params: extra parameters specific to the xt api endpoint
        :param str [params.timeInForce]: 'GTC', 'IOC', 'FOK' or 'GTX'
        :param str [params.entrustType]: 'TAKE_PROFIT', 'STOP', 'TAKE_PROFIT_MARKET', 'STOP_MARKET', 'TRAILING_STOP_MARKET', required if stopPrice is defined, currently isn't functioning on xt's side
        :param str [params.triggerPriceType]: 'INDEX_PRICE', 'MARK_PRICE', 'LATEST_PRICE', required if stopPrice is defined
        :param float [params.triggerPrice]: price to trigger a stop order
        :param float [params.stopPrice]: alias for triggerPrice
        :param float [params.stopLoss]: price to set a stop-loss on an open position
        :param float [params.takeProfit]: price to set a take-profit on an open position
        :returns dict: an `order structure <https://docs.ccxt.com/en/latest/manual.html#order-structure>`
        """
        self.load_markets()
        market = self.market(symbol)
        symbol = market['symbol']
        if market['spot']:
            return self.create_spot_order(symbol, type, side, amount, price, params)
        else:
            return self.create_contract_order(symbol, type, side, amount, price, params)

    def create_spot_order(self, symbol: str, type, side, amount, price=None, params={}):
        self.load_markets()
        market = self.market(symbol)
        request = {
            'symbol': market['id'],
            'side': side.upper(),
            'type': type.upper(),
        }
        timeInForce = None
        marginMode = None
        marginMode, params = self.handle_margin_mode_and_params('createOrder', params)
        marginOrSpotRequest = 'LEVER' if (marginMode is not None) else 'SPOT'
        request['bizType'] = marginOrSpotRequest
        if type == 'market':
            timeInForce = self.safe_string_upper(params, 'timeInForce', 'FOK')
            if side == 'buy':
                cost = self.safe_string(params, 'cost')
                params = self.omit(params, 'cost')
                createMarketBuyOrderRequiresPrice = self.safe_bool(self.options, 'createMarketBuyOrderRequiresPrice', True)
                if createMarketBuyOrderRequiresPrice:
                    if price is None and (cost is None):
                        raise InvalidOrder(self.id + ' createOrder() requires a price argument or cost in params for market buy orders on spot markets to calculate the total amount to spend(amount * price), alternatively set the createMarketBuyOrderRequiresPrice option to False and pass in the cost to spend into the amount parameter')
                    else:
                        amountString = self.number_to_string(amount)
                        priceString = self.number_to_string(price)
                        costCalculated: Str = None
                        if price is not None:
                            costCalculated = Precise.string_mul(amountString, priceString)
                        else:
                            costCalculated = cost
                        request['quoteQty'] = self.cost_to_precision(symbol, costCalculated)
                else:
                    amountCost = cost if (cost is not None) else amount
                    request['quoteQty'] = self.cost_to_precision(symbol, amountCost)
        else:
            timeInForce = self.safe_string_upper(params, 'timeInForce', 'GTC')
            request['price'] = self.price_to_precision(symbol, price)
        if (side == 'sell') or (type == 'limit'):
            request['quantity'] = self.amount_to_precision(symbol, amount)
        request['timeInForce'] = timeInForce
        response = self.privateSpotPostOrder(self.extend(request, params))
        #
        #     {
        #         "rc": 0,
        #         "mc": "SUCCESS",
        #         "ma": [],
        #         "result": {
        #             "orderId": "204371980095156544"
        #         }
        #     }
        #
        order = self.safe_value(response, 'result', {})
        return self.parse_order(order, market)

    def create_contract_order(self, symbol: str, type, side, amount, price=None, params={}):
        self.load_markets()
        market = self.market(symbol)
        request = {
            'symbol': market['id'],
            'origQty': self.amount_to_precision(symbol, amount),
        }
        timeInForce = self.safe_string_upper(params, 'timeInForce')
        if timeInForce is not None:
            request['timeInForce'] = timeInForce
        reduceOnly = self.safe_value(params, 'reduceOnly', False)
        if side == 'buy':
            requestType = 'SHORT' if (reduceOnly) else 'LONG'
            request['positionSide'] = requestType
        else:
            requestType = 'LONG' if (reduceOnly) else 'SHORT'
            request['positionSide'] = requestType
        response = None
        triggerPrice = self.safe_number_2(params, 'triggerPrice', 'stopPrice')
        stopLoss = self.safe_number_2(params, 'stopLoss', 'triggerStopPrice')
        takeProfit = self.safe_number_2(params, 'takeProfit', 'triggerProfitPrice')
        isTrigger = (triggerPrice is not None)
        isStopLoss = (stopLoss is not None)
        isTakeProfit = (takeProfit is not None)
        if price is not None:
            if not (isStopLoss) and not (isTakeProfit):
                request['price'] = self.price_to_precision(symbol, price)
        if isTrigger:
            request['timeInForce'] = self.safe_string_upper(params, 'timeInForce', 'GTC')
            request['triggerPriceType'] = self.safe_string(params, 'triggerPriceType', 'LATEST_PRICE')
            request['orderSide'] = side.upper()
            request['stopPrice'] = self.price_to_precision(symbol, triggerPrice)
            entrustType = 'STOP_MARKET' if (type == 'market') else 'STOP'
            request['entrustType'] = entrustType
            params = self.omit(params, 'triggerPrice')
            if market['linear']:
                response = self.privateLinearPostFutureTradeV1EntrustCreatePlan(self.extend(request, params))
            elif market['inverse']:
                response = self.privateInversePostFutureTradeV1EntrustCreatePlan(self.extend(request, params))
        elif isStopLoss or isTakeProfit:
            if isStopLoss:
                request['triggerStopPrice'] = self.price_to_precision(symbol, stopLoss)
            else:
                request['triggerProfitPrice'] = self.price_to_precision(symbol, takeProfit)
            params = self.omit(params, ['stopLoss', 'takeProfit'])
            if market['linear']:
                response = self.privateLinearPostFutureTradeV1EntrustCreateProfit(self.extend(request, params))
            elif market['inverse']:
                response = self.privateInversePostFutureTradeV1EntrustCreateProfit(self.extend(request, params))
        else:
            request['orderSide'] = side.upper()
            request['orderType'] = type.upper()
            if market['linear']:
                response = self.privateLinearPostFutureTradeV1OrderCreate(self.extend(request, params))
            elif market['inverse']:
                response = self.privateInversePostFutureTradeV1OrderCreate(self.extend(request, params))
        #
        #     {
        #         "returnCode": 0,
        #         "msgInfo": "success",
        #         "error": null,
        #         "result": "206410760006650176"
        #     }
        #
        return self.parse_order(response, market)

    def fetch_order(self, id: str, symbol: str = None, params={}):
        """
        fetches information on an order made by the user

        https://doc.xt.com/#orderorderGet
        https://doc.xt.com/#futures_ordergetById
        https://doc.xt.com/#futures_entrustgetPlanById
        https://doc.xt.com/#futures_entrustgetProfitById

        :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 xt api endpoint
        :param bool [params.trigger]: if the order is a trigger order or not
        :param bool [params.stopLossTakeProfit]: if the order is a stop-loss or take-profit order
        :returns dict: An `order structure <https://docs.ccxt.com/en/latest/manual.html#order-structure>`
        """
        self.load_markets()
        market = None
        if symbol is not None:
            market = self.market(symbol)
        request = {}
        type = None
        subType = None
        response = None
        type, params = self.handle_market_type_and_params('fetchOrder', market, params)
        subType, params = self.handle_sub_type_and_params('fetchOrder', market, params)
        trigger = self.safe_value(params, 'stop')
        stopLossTakeProfit = self.safe_value(params, 'stopLossTakeProfit')
        if trigger:
            request['entrustId'] = id
        elif stopLossTakeProfit:
            request['profitId'] = id
        else:
            request['orderId'] = id
        if trigger:
            params = self.omit(params, 'stop')
            if subType == 'inverse':
                response = self.privateInverseGetFutureTradeV1EntrustPlanDetail(self.extend(request, params))
            else:
                response = self.privateLinearGetFutureTradeV1EntrustPlanDetail(self.extend(request, params))
        elif stopLossTakeProfit:
            params = self.omit(params, 'stopLossTakeProfit')
            if subType == 'inverse':
                response = self.privateInverseGetFutureTradeV1EntrustProfitDetail(self.extend(request, params))
            else:
                response = self.privateLinearGetFutureTradeV1EntrustProfitDetail(self.extend(request, params))
        elif subType == 'inverse':
            response = self.privateInverseGetFutureTradeV1OrderDetail(self.extend(request, params))
        elif (subType == 'linear') or (type == 'swap') or (type == 'future'):
            response = self.privateLinearGetFutureTradeV1OrderDetail(self.extend(request, params))
        else:
            response = self.privateSpotGetOrderOrderId(self.extend(request, params))
        #
        # spot
        #
        #     {
        #         "rc": 0,
        #         "mc": "SUCCESS",
        #         "ma": [],
        #         "result": {
        #             "symbol": "btc_usdt",
        #             "orderId": "207505997850909952",
        #             "clientOrderId": null,
        #             "baseCurrency": "btc",
        #             "quoteCurrency": "usdt",
        #             "side": "BUY",
        #             "type": "LIMIT",
        #             "timeInForce": "GTC",
        #             "price": "20000.00",
        #             "origQty": "0.001000",
        #             "origQuoteQty": "20.00",
        #             "executedQty": "0.000000",
        #             "leavingQty": "0.001000",
        #             "tradeBase": "0.000000",
        #             "tradeQuote": "0.00",
        #             "avgPrice": null,
        #             "fee": null,
        #             "feeCurrency": null,
        #             "closed": False,
        #             "state": "NEW",
        #             "time": 1679175285162,
        #             "updatedTime": 1679175285255
        #         }
        #     }
        #
        # swap and future
        #
        #     {
        #         "returnCode": 0,
        #         "msgInfo": "success",
        #         "error": null,
        #         "result": {
        #             "orderId": "211451874783183936",
        #             "clientOrderId": null,
        #             "symbol": "btc_usdt",
        #             "orderType": "LIMIT",
        #             "orderSide": "BUY",
        #             "positionSide": "LONG",
        #             "timeInForce": "GTC",
        #             "closePosition": False,
        #             "price": "20000",
        #             "origQty": "10",
        #             "avgPrice": "0",
        #             "executedQty": "0",
        #             "marginFrozen": "1.34533334",
        #             "remark": null,
        #             "triggerProfitPrice": null,
        #             "triggerStopPrice": null,
        #             "sourceId": null,
        #             "sourceType": "DEFAULT",
        #             "forceClose": False,
        #             "closeProfit": null,
        #             "state": "NEW",
        #             "createdTime": 1680116055693,
        #             "updatedTime": 1680116055693
        #         }
        #     }
        #
        # trigger
        #
        #     {
        #         "returnCode": 0,
        #         "msgInfo": "success",
        #         "error": null,
        #         "result": {
        #             "entrustId": "216300248132756992",
        #             "symbol": "btc_usdt",
        #             "entrustType": "STOP",
        #             "orderSide": "SELL",
        #             "positionSide": "SHORT",
        #             "timeInForce": "GTC",
        #             "closePosition": null,
        #             "price": "20000",
        #             "origQty": "1",
        #             "stopPrice": "19000",
        #             "triggerPriceType": "LATEST_PRICE",
        #             "state": "NOT_TRIGGERED",
        #             "marketOrderLevel": null,
        #             "createdTime": 1681271998064,
        #             "updatedTime": 1681271998064,
        #             "ordinary": False
        #         }
        #     }
        #
        # stop-loss and take-profit
        #
        #     {
        #         "returnCode": 0,
        #         "msgInfo": "success",
        #         "error": null,
        #         "result": {
        #             "profitId": "216306213226230400",
        #             "symbol": "btc_usdt",
        #             "positionSide": "LONG",
        #             "origQty": "1",
        #             "triggerPriceType": "LATEST_PRICE",
        #             "triggerProfitPrice": null,
        #             "triggerStopPrice": "20000",
        #             "entryPrice": null,
        #             "positionSize": null,
        #             "isolatedMargin": null,
        #             "executedQty": null,
        #             "avgPrice": null,
        #             "positionType": "ISOLATED",
        #             "state": "NOT_TRIGGERED",
        #             "createdTime": 1681273420039
        #         }
        #     }
        #
        order = self.safe_value(response, 'result', {})
        return self.parse_order(order, market)

    def fetch_orders(self, symbol: str = None, since: Int = None, limit: Int = None, params={}):
        """
        fetches information on multiple orders made by the user

        https://doc.xt.com/#orderhistoryOrderGet
        https://doc.xt.com/#futures_ordergetHistory
        https://doc.xt.com/#futures_entrustgetPlanHistory

        :param str [symbol]: unified market symbol of the market the orders were made in
        :param int [since]: timestamp in ms of the earliest order
        :param int [limit]: the maximum number of order structures to retrieve
        :param dict params: extra parameters specific to the xt api endpoint
        :param bool [params.trigger]: if the order is a trigger order or not
        :returns dict[]: a list of `order structures <https://docs.ccxt.com/en/latest/manual.html#order-structure>`
        """
        self.load_markets()
        request = {}
        market = None
        if symbol is not None:
            market = self.market(symbol)
            request['symbol'] = market['id']
        if since is not None:
            request['startTime'] = since
        if limit is not None:
            request['limit'] = limit
        type = None
        subType = None
        response = None
        type, params = self.handle_market_type_and_params('fetchOrders', market, params)
        subType, params = self.handle_sub_type_and_params('fetchOrders', market, params)
        trigger = self.safe_value_2(params, 'trigger', 'stop')
        if trigger:
            params = self.omit(params, ['trigger', 'stop'])
            if subType == 'inverse':
                response = self.privateInverseGetFutureTradeV1EntrustPlanListHistory(self.extend(request, params))
            else:
                response = self.privateLinearGetFutureTradeV1EntrustPlanListHistory(self.extend(request, params))
        elif subType == 'inverse':
            response = self.privateInverseGetFutureTradeV1OrderListHistory(self.extend(request, params))
        elif (subType == 'linear') or (type == 'swap') or (type == 'future'):
            response = self.privateLinearGetFutureTradeV1OrderListHistory(self.extend(request, params))
        else:
            marginMode = None
            marginMode, params = self.handle_margin_mode_and_params('fetchOrders', params)
            marginOrSpotRequest = 'LEVER' if (marginMode is not None) else 'SPOT'
            request['bizType'] = marginOrSpotRequest
            response = self.privateSpotGetHistoryOrder(self.extend(request, params))
        #
        #  spot and margin
        #
        #     {
        #         "rc": 0,
        #         "mc": "SUCCESS",
        #         "ma": [],
        #         "result": {
        #             "hasPrev": False,
        #             "hasNext": True,
        #             "items": [
        #                 {
        #                     "symbol": "btc_usdt",
        #                     "orderId": "207505997850909952",
        #                     "clientOrderId": null,
        #                     "baseCurrency": "btc",
        #                     "quoteCurrency": "usdt",
        #                     "side": "BUY",
        #                     "type": "LIMIT",
        #                     "timeInForce": "GTC",
        #                     "price": "20000.00",
        #                     "origQty": "0.001000",
        #                     "origQuoteQty": "20.00",
        #                     "executedQty": "0.000000",
        #                     "leavingQty": "0.000000",
        #                     "tradeBase": "0.000000",
        #                     "tradeQuote": "0.00",
        #                     "avgPrice": null,
        #                     "fee": null,
        #                     "feeCurrency": null,
        #                     "closed": True,
        #                     "state": "CANCELED",
        #                     "time": 1679175285162,
        #                     "updatedTime": 1679175488492
        #                 },
        #             ]
        #         }
        #     }
        #
        # swap and future
        #
        #     {
        #         "returnCode": 0,
        #         "msgInfo": "success",
        #         "error": null,
        #         "result": {
        #             "hasPrev": False,
        #             "hasNext": True,
        #             "items": [
        #                 {
        #                     "orderId": "207519546930995456",
        #                     "clientOrderId": null,
        #                     "symbol": "btc_usdt",
        #                     "orderType": "LIMIT",
        #                     "orderSide": "BUY",
        #                     "positionSide": "LONG",
        #                     "timeInForce": "GTC",
        #                     "closePosition": False,
        #                     "price": "20000",
        #                     "origQty": "100",
        #                     "avgPrice": "0",
        #                     "executedQty": "0",
        #                     "marginFrozen": "4.12",
        #                     "remark": null,
        #                     "triggerProfitPrice": null,
        #                     "triggerStopPrice": null,
        #                     "sourceId": null,
        #                     "sourceType": "DEFAULT",
        #                     "forceClose": False,
        #                     "closeProfit": null,
        #                     "state": "CANCELED",
        #                     "createdTime": 1679178515689,
        #                     "updatedTime": 1679180096172
        #                 },
        #             ]
        #         }
        #     }
        #
        # stop
        #
        #     {
        #         "returnCode": 0,
        #         "msgInfo": "success",
        #         "error": null,
        #         "result": {
        #             "hasPrev": False,
        #             "hasNext": False,
        #             "items": [
        #                 {
        #                     "entrustId": "216300248132756992",
        #                     "symbol": "btc_usdt",
        #                     "entrustType": "STOP",
        #                     "orderSide": "SELL",
        #                     "positionSide": "SHORT",
        #                     "timeInForce": "GTC",
        #                     "closePosition": null,
        #                     "price": "20000",
        #                     "origQty": "1",
        #                     "stopPrice": "19000",
        #                     "triggerPriceType": "LATEST_PRICE",
        #                     "state": "USER_REVOCATION",
        #                     "marketOrderLevel": null,
        #                     "createdTime": 1681271998064,
        #                     "updatedTime": 1681273188674,
        #                     "ordinary": False
        #                 },
        #             ]
        #         }
        #     }
        #
        data = self.safe_value(response, 'result', {})
        orders = self.safe_value(data, 'items', [])
        return self.parse_orders(orders, market, since, limit)

    def fetch_orders_by_status(self, status, symbol: str = None, since: Int = None, limit: Int = None, params={}):
        self.load_markets()
        request = {}
        market = None
        if symbol is not None:
            market = self.market(symbol)
            request['symbol'] = market['id']
        if limit is not None:
            request['size'] = limit
        if since is not None:
            request['startTime'] = since
        type = None
        subType = None
        response = None
        type, params = self.handle_market_type_and_params('fetchOrdersByStatus', market, params)
        subType, params = self.handle_sub_type_and_params('fetchOrdersByStatus', market, params)
        trigger = self.safe_bool_2(params, 'stop', 'trigger')
        stopLossTakeProfit = self.safe_value(params, 'stopLossTakeProfit')
        if status == 'open':
            if trigger or stopLossTakeProfit:
                request['state'] = 'NOT_TRIGGERED'
            elif type == 'swap':
                request['state'] = 'UNFINISHED'  # NEW & PARTIALLY_FILLED
        elif status == 'closed':
            if trigger or stopLossTakeProfit:
                request['state'] = 'TRIGGERED'
            else:
                request['state'] = 'FILLED'
        elif status == 'canceled':
            if trigger or stopLossTakeProfit:
                request['state'] = 'USER_REVOCATION'
            else:
                request['state'] = 'CANCELED'
        else:
            request['state'] = status
        if trigger or stopLossTakeProfit or (subType is not None) or (type == 'swap') or (type == 'future'):
            if since is not None:
                request['startTime'] = since
            if limit is not None:
                request['size'] = limit
        if trigger:
            params = self.omit(params, ['stop', 'trigger'])
            if subType == 'inverse':
                response = self.privateInverseGetFutureTradeV1EntrustPlanList(self.extend(request, params))
            else:
                response = self.privateLinearGetFutureTradeV1EntrustPlanList(self.extend(request, params))
        elif stopLossTakeProfit:
            params = self.omit(params, 'stopLossTakeProfit')
            if subType == 'inverse':
                response = self.privateInverseGetFutureTradeV1EntrustProfitList(self.extend(request, params))
            else:
                response = self.privateLinearGetFutureTradeV1EntrustProfitList(self.extend(request, params))
        elif (subType is not None) or (type == 'swap') or (type == 'future'):
            if subType == 'inverse':
                response = self.privateInverseGetFutureTradeV1OrderList(self.extend(request, params))
            else:
                response = self.privateLinearGetFutureTradeV1OrderList(self.extend(request, params))
        else:
            marginMode = None
            marginMode, params = self.handle_margin_mode_and_params('fetchOrdersByStatus', params)
            marginOrSpotRequest = 'LEVER' if (marginMode is not None) else 'SPOT'
            request['bizType'] = marginOrSpotRequest
            if status != 'open':
                if since is not None:
                    request['startTime'] = since
                if limit is not None:
                    request = self.omit(request, 'size')
                    request['limit'] = limit
                response = self.privateSpotGetHistoryOrder(self.extend(request, params))
            else:
                response = self.privateSpotGetOpenOrder(self.extend(request, params))
        #
        # spot and margin
        #
        #     {
        #         "rc": 0,
        #         "mc": "SUCCESS",
        #         "ma": [],
        #         "result": {
        #             "hasPrev": False,
        #             "hasNext": True,
        #             "items": [
        #                 {
        #                     "symbol": "btc_usdt",
        #                     "orderId": "207505997850909952",
        #                     "clientOrderId": null,
        #                     "baseCurrency": "btc",
        #                     "quoteCurrency": "usdt",
        #                     "side": "BUY",
        #                     "type": "LIMIT",
        #                     "timeInForce": "GTC",
        #                     "price": "20000.00",
        #                     "origQty": "0.001000",
        #                     "origQuoteQty": "20.00",
        #                     "executedQty": "0.000000",
        #                     "leavingQty": "0.000000",
        #                     "tradeBase": "0.000000",
        #                     "tradeQuote": "0.00",
        #                     "avgPrice": null,
        #                     "fee": null,
        #                     "feeCurrency": null,
        #                     "closed": True,
        #                     "state": "CANCELED",
        #                     "time": 1679175285162,
        #                     "updatedTime": 1679175488492
        #                 },
        #             ]
        #         }
        #     }
        #
        # spot and margin: fetchOpenOrders
        #
        #     {
        #         "rc": 0,
        #         "mc": "SUCCESS",
        #         "ma": [],
        #         "result": [
        #             {
        #                 "symbol": "eth_usdt",
        #                 "orderId": "208249323222264320",
        #                 "clientOrderId": null,
        #                 "baseCurrency": "eth",
        #                 "quoteCurrency": "usdt",
        #                 "side": "BUY",
        #                 "type": "LIMIT",
        #                 "timeInForce": "GTC",
        #                 "price": "1300.00",
        #                 "origQty": "0.0032",
        #                 "origQuoteQty": "4.16",
        #                 "executedQty": "0.0000",
        #                 "leavingQty": "0.0032",
        #                 "tradeBase": "0.0000",
        #                 "tradeQuote": "0.00",
        #                 "avgPrice": null,
        #                 "fee": null,
        #                 "feeCurrency": null,
        #                 "closed": False,
        #                 "state": "NEW",
        #                 "time": 1679352507741,
        #                 "updatedTime": 1679352507869
        #             },
        #         ]
        #     }
        #
        # swap and future
        #
        #     {
        #         "returnCode": 0,
        #         "msgInfo": "success",
        #         "error": null,
        #         "result": {
        #             "page": 1,
        #             "ps": 10,
        #             "total": 25,
        #             "items": [
        #                 {
        #                     "orderId": "207519546930995456",
        #                     "clientOrderId": null,
        #                     "symbol": "btc_usdt",
        #                     "orderType": "LIMIT",
        #                     "orderSide": "BUY",
        #                     "positionSide": "LONG",
        #                     "timeInForce": "GTC",
        #                     "closePosition": False,
        #                     "price": "20000",
        #                     "origQty": "100",
        #                     "avgPrice": "0",
        #                     "executedQty": "0",
        #                     "marginFrozen": "4.12",
        #                     "remark": null,
        #                     "triggerProfitPrice": null,
        #                     "triggerStopPrice": null,
        #                     "sourceId": null,
        #                     "sourceType": "DEFAULT",
        #                     "forceClose": False,
        #                     "closeProfit": null,
        #                     "state": "CANCELED",
        #                     "createdTime": 1679178515689,
        #                     "updatedTime": 1679180096172
        #                 },
        #             ]
        #         }
        #     }
        #
        # stop
        #
        #     {
        #         "returnCode": 0,
        #         "msgInfo": "success",
        #         "error": null,
        #         "result": {
        #             "page": 1,
        #             "ps": 3,
        #             "total": 8,
        #             "items": [
        #                 {
        #                     "entrustId": "216300248132756992",
        #                     "symbol": "btc_usdt",
        #                     "entrustType": "STOP",
        #                     "orderSide": "SELL",
        #                     "positionSide": "SHORT",
        #                     "timeInForce": "GTC",
        #                     "closePosition": null,
        #                     "price": "20000",
        #                     "origQty": "1",
        #                     "stopPrice": "19000",
        #                     "triggerPriceType": "LATEST_PRICE",
        #                     "state": "USER_REVOCATION",
        #                     "marketOrderLevel": null,
        #                     "createdTime": 1681271998064,
        #                     "updatedTime": 1681273188674,
        #                     "ordinary": False
        #                 },
        #             ]
        #         }
        #     }
        #
        # stop-loss and take-profit
        #
        #     {
        #         "returnCode": 0,
        #         "msgInfo": "success",
        #         "error": null,
        #         "result": {
        #             "page": 1,
        #             "ps": 3,
        #             "total": 2,
        #             "items": [
        #                 {
        #                     "profitId": "216306213226230400",
        #                     "symbol": "btc_usdt",
        #                     "positionSide": "LONG",
        #                     "origQty": "1",
        #                     "triggerPriceType": "LATEST_PRICE",
        #                     "triggerProfitPrice": null,
        #                     "triggerStopPrice": "20000",
        #                     "entryPrice": "0",
        #                     "positionSize": "0",
        #                     "isolatedMargin": "0",
        #                     "executedQty": "0",
        #                     "avgPrice": null,
        #                     "positionType": "ISOLATED",
        #                     "state": "USER_REVOCATION",
        #                     "createdTime": 1681273420039
        #                 },
        #             ]
        #         }
        #     }
        #
        orders = []
        resultDict = self.safe_dict(response, 'result')
        if resultDict is not None:
            orders = self.safe_list(resultDict, 'items', [])
        else:
            orders = self.safe_list(response, 'result')
        return self.parse_orders(orders, market, since, limit)

    def fetch_open_orders(self, symbol: str = None, since: Int = None, limit: Int = None, params={}):
        """
        fetch all unfilled currently open orders

        https://doc.xt.com/#orderopenOrderGet
        https://doc.xt.com/#futures_ordergetOrders
        https://doc.xt.com/#futures_entrustgetPlan
        https://doc.xt.com/#futures_entrustgetProfit

        :param str [symbol]: unified market symbol of the market the orders were made in
        :param int [since]: timestamp in ms of the earliest order
        :param int [limit]: the maximum number of open order structures to retrieve
        :param dict params: extra parameters specific to the xt api endpoint
        :param bool [params.trigger]: if the order is a trigger order or not
        :param bool [params.stopLossTakeProfit]: if the order is a stop-loss or take-profit order
        :returns dict[]: a list of `order structures <https://docs.ccxt.com/en/latest/manual.html#order-structure>`
        """
        return self.fetch_orders_by_status('open', symbol, since, limit, params)

    def fetch_closed_orders(self, symbol: str = None, since: Int = None, limit: Int = None, params={}):
        """
        fetches information on multiple closed orders made by the user

        https://doc.xt.com/#orderhistoryOrderGet
        https://doc.xt.com/#futures_ordergetOrders
        https://doc.xt.com/#futures_entrustgetPlan
        https://doc.xt.com/#futures_entrustgetProfit

        :param str [symbol]: unified market symbol of the market the orders were made in
        :param int [since]: timestamp in ms of the earliest order
        :param int [limit]: the maximum number of order structures to retrieve
        :param dict params: extra parameters specific to the xt api endpoint
        :param bool [params.trigger]: if the order is a trigger order or not
        :param bool [params.stopLossTakeProfit]: if the order is a stop-loss or take-profit order
        :returns dict[]: a list of `order structures <https://docs.ccxt.com/en/latest/manual.html#order-structure>`
        """
        return self.fetch_orders_by_status('closed', symbol, since, limit, params)

    def fetch_canceled_orders(self, symbol: str = None, since: Int = None, limit: Int = None, params={}):
        """
        fetches information on multiple canceled orders made by the user

        https://doc.xt.com/#orderhistoryOrderGet
        https://doc.xt.com/#futures_ordergetOrders
        https://doc.xt.com/#futures_entrustgetPlan
        https://doc.xt.com/#futures_entrustgetProfit

        :param str [symbol]: unified market symbol of the market the orders were made in
        :param int [since]: timestamp in ms of the earliest order
        :param int [limit]: the maximum number of order structures to retrieve
        :param dict params: extra parameters specific to the xt api endpoint
        :param bool [params.trigger]: if the order is a trigger order or not
        :param bool [params.stopLossTakeProfit]: if the order is a stop-loss or take-profit order
        :returns dict: a list of `order structures <https://docs.ccxt.com/en/latest/manual.html#order-structure>`
        """
        return self.fetch_orders_by_status('canceled', symbol, since, limit, params)

    def cancel_order(self, id: str, symbol: str = None, params={}):
        """
        cancels an open order

        https://doc.xt.com/#orderorderDel
        https://doc.xt.com/#futures_ordercancel
        https://doc.xt.com/#futures_entrustcancelPlan
        https://doc.xt.com/#futures_entrustcancelProfit

        :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 xt api endpoint
        :param bool [params.trigger]: if the order is a trigger order or not
        :param bool [params.stopLossTakeProfit]: if the order is a stop-loss or take-profit order
        :returns dict: An `order structure <https://docs.ccxt.com/en/latest/manual.html#order-structure>`
        """
        self.load_markets()
        market = None
        if symbol is not None:
            market = self.market(symbol)
        request = {}
        type = None
        subType = None
        response = None
        type, params = self.handle_market_type_and_params('cancelOrder', market, params)
        subType, params = self.handle_sub_type_and_params('cancelOrder', market, params)
        trigger = self.safe_value_2(params, 'trigger', 'stop')
        stopLossTakeProfit = self.safe_value(params, 'stopLossTakeProfit')
        if trigger:
            request['entrustId'] = id
        elif stopLossTakeProfit:
            request['profitId'] = id
        else:
            request['orderId'] = id
        if trigger:
            params = self.omit(params, ['trigger', 'stop'])
            if subType == 'inverse':
                response = self.privateInversePostFutureTradeV1EntrustCancelPlan(self.extend(request, params))
            else:
                response = self.privateLinearPostFutureTradeV1EntrustCancelPlan(self.extend(request, params))
        elif stopLossTakeProfit:
            params = self.omit(params, 'stopLossTakeProfit')
            if subType == 'inverse':
                response = self.privateInversePostFutureTradeV1EntrustCancelProfitStop(self.extend(request, params))
            else:
                response = self.privateLinearPostFutureTradeV1EntrustCancelProfitStop(self.extend(request, params))
        elif subType == 'inverse':
            response = self.privateInversePostFutureTradeV1OrderCancel(self.extend(request, params))
        elif (subType == 'linear') or (type == 'swap') or (type == 'future'):
            response = self.privateLinearPostFutureTradeV1OrderCancel(self.extend(request, params))
        else:
            response = self.privateSpotDeleteOrderOrderId(self.extend(request, params))
        #
        # spot
        #
        #     {
        #         "rc": 0,
        #         "mc": "SUCCESS",
        #         "ma": [],
        #         "result": {
        #             "cancelId": "208322474307982720"
        #         }
        #     }
        #
        # swap and future
        #
        #     {
        #         "returnCode": 0,
        #         "msgInfo": "success",
        #         "error": null,
        #         "result": "208319789679471616"
        #     }
        #
        isContractResponse = ((subType is not None) or (type == 'swap') or (type == 'future'))
        order = response if isContractResponse else self.safe_value(response, 'result', {})
        return self.parse_order(order, market)

    def cancel_all_orders(self, symbol: str = None, params={}):
        """
        cancel all open orders in a market

        https://doc.xt.com/#orderopenOrderDel
        https://doc.xt.com/#futures_ordercancelBatch
        https://doc.xt.com/#futures_entrustcancelPlanBatch
        https://doc.xt.com/#futures_entrustcancelProfitBatch

        :param str [symbol]: unified market symbol of the market to cancel orders in
        :param dict params: extra parameters specific to the xt api endpoint
        :param bool [params.trigger]: if the order is a trigger order or not
        :param bool [params.stopLossTakeProfit]: if the order is a stop-loss or take-profit order
        :returns dict[]: a list of `order structures <https://docs.ccxt.com/en/latest/manual.html#order-structure>`
        """
        self.load_markets()
        request = {}
        market = None
        if symbol is not None:
            market = self.market(symbol)
            request['symbol'] = market['id']
        type = None
        subType = None
        response = None
        type, params = self.handle_market_type_and_params('cancelAllOrders', market, params)
        subType, params = self.handle_sub_type_and_params('cancelAllOrders', market, params)
        trigger = self.safe_value_2(params, 'trigger', 'stop')
        stopLossTakeProfit = self.safe_value(params, 'stopLossTakeProfit')
        if trigger:
            params = self.omit(params, ['trigger', 'stop'])
            if subType == 'inverse':
                response = self.privateInversePostFutureTradeV1EntrustCancelAllPlan(self.extend(request, params))
            else:
                response = self.privateLinearPostFutureTradeV1EntrustCancelAllPlan(self.extend(request, params))
        elif stopLossTakeProfit:
            params = self.omit(params, 'stopLossTakeProfit')
            if subType == 'inverse':
                response = self.privateInversePostFutureTradeV1EntrustCancelAllProfitStop(self.extend(request, params))
            else:
                response = self.privateLinearPostFutureTradeV1EntrustCancelAllProfitStop(self.extend(request, params))
        elif subType == 'inverse':
            response = self.privateInversePostFutureTradeV1OrderCancelAll(self.extend(request, params))
        elif (subType == 'linear') or (type == 'swap') or (type == 'future'):
            response = self.privateLinearPostFutureTradeV1OrderCancelAll(self.extend(request, params))
        else:
            marginMode = None
            marginMode, params = self.handle_margin_mode_and_params('cancelAllOrders', params)
            marginOrSpotRequest = 'LEVER' if (marginMode is not None) else 'SPOT'
            request['bizType'] = marginOrSpotRequest
            response = self.privateSpotDeleteOpenOrder(self.extend(request, params))
        #
        # spot and margin
        #
        #     {
        #         "rc": 0,
        #         "mc": "SUCCESS",
        #         "ma": [],
        #         "result": null
        #     }
        #
        # swap and future
        #
        #     {
        #         "returnCode": 0,
        #         "msgInfo": "success",
        #         "error": null,
        #         "result": True
        #     }
        #
        return [
            self.safe_order(response),
        ]

    def cancel_orders(self, ids: List[str], symbol: str = None, params={}) -> List[Order]:
        """
        cancel multiple orders

        https://doc.xt.com/#orderbatchOrderDel

        :param str[] ids: order ids
        :param str [symbol]: unified market symbol of the market to cancel orders in
        :param dict params: extra parameters specific to the xt api endpoint
        :returns dict[]: a list of `order structures <https://docs.ccxt.com/en/latest/manual.html#order-structure>`
        """
        self.load_markets()
        request = {
            'orderIds': ids,
        }
        market = None
        if symbol is not None:
            market = self.market(symbol)
        subType = None
        subType, params = self.handle_sub_type_and_params('cancelOrders', market, params)
        if subType is not None:
            raise NotSupported(self.id + ' cancelOrders() does not support swap and future orders, only spot orders are accepted')
        response = self.privateSpotDeleteBatchOrder(self.extend(request, params))
        #
        # spot
        #
        #     {
        #         "rc": 0,
        #         "mc": "SUCCESS",
        #         "ma": [],
        #         "result": null
        #     }
        #
        return [
            self.safe_order(response),
        ]

    def parse_order(self, order, market=None):
        #
        # spot: createOrder
        #
        #     {
        #         "orderId": "204371980095156544"
        #     }
        #
        # spot: cancelOrder
        #
        #     {
        #         "cancelId": "208322474307982720"
        #     }
        #
        # swap and future: createOrder, cancelOrder, editOrder
        #
        #     {
        #         "returnCode": 0,
        #         "msgInfo": "success",
        #         "error": null,
        #         "result": "206410760006650176"
        #     }
        #
        # spot: fetchOrder, fetchOrders, fetchOpenOrders, fetchClosedOrders, fetchCanceledOrders, fetchOrdersByStatus
        #
        #     {
        #         "symbol": "btc_usdt",
        #         "orderId": "207505997850909952",
        #         "clientOrderId": null,
        #         "baseCurrency": "btc",
        #         "quoteCurrency": "usdt",
        #         "side": "BUY",
        #         "type": "LIMIT",
        #         "timeInForce": "GTC",
        #         "price": "20000.00",
        #         "origQty": "0.001000",
        #         "origQuoteQty": "20.00",
        #         "executedQty": "0.000000",
        #         "leavingQty": "0.001000",
        #         "tradeBase": "0.000000",
        #         "tradeQuote": "0.00",
        #         "avgPrice": null,
        #         "fee": null,
        #         "feeCurrency": null,
        #         "closed": False,
        #         "state": "NEW",
        #         "time": 1679175285162,
        #         "updatedTime": 1679175285255
        #     }
        #
        # swap and future: fetchOrder, fetchOrders, fetchOpenOrders, fetchClosedOrders, fetchCanceledOrders, fetchOrdersByStatus
        #
        #     {
        #         "orderId": "207519546930995456",
        #         "clientOrderId": null,
        #         "symbol": "btc_usdt",
        #         "orderType": "LIMIT",
        #         "orderSide": "BUY",
        #         "positionSide": "LONG",
        #         "timeInForce": "GTC",
        #         "closePosition": False,
        #         "price": "20000",
        #         "origQty": "100",
        #         "avgPrice": "0",
        #         "executedQty": "0",
        #         "marginFrozen": "4.12",
        #         "remark": null,
        #         "triggerProfitPrice": null,
        #         "triggerStopPrice": null,
        #         "sourceId": null,
        #         "sourceType": "DEFAULT",
        #         "forceClose": False,
        #         "closeProfit": null,
        #         "state": "CANCELED",
        #         "createdTime": 1679178515689,
        #         "updatedTime": 1679180096172
        #     }
        #
        # trigger: fetchOrder, fetchOrders, fetchOpenOrders, fetchClosedOrders, fetchCanceledOrders, fetchOrdersByStatus
        #
        #     {
        #         "entrustId": "216300248132756992",
        #         "symbol": "btc_usdt",
        #         "entrustType": "STOP",
        #         "orderSide": "SELL",
        #         "positionSide": "SHORT",
        #         "timeInForce": "GTC",
        #         "closePosition": null,
        #         "price": "20000",
        #         "origQty": "1",
        #         "stopPrice": "19000",
        #         "triggerPriceType": "LATEST_PRICE",
        #         "state": "NOT_TRIGGERED",
        #         "marketOrderLevel": null,
        #         "createdTime": 1681271998064,
        #         "updatedTime": 1681271998064,
        #         "ordinary": False
        #     }
        #
        # stop-loss and take-profit: fetchOrder, fetchOpenOrders, fetchClosedOrders, fetchCanceledOrders, fetchOrdersByStatus
        #
        #     {
        #         "profitId": "216306213226230400",
        #         "symbol": "btc_usdt",
        #         "positionSide": "LONG",
        #         "origQty": "1",
        #         "triggerPriceType": "LATEST_PRICE",
        #         "triggerProfitPrice": null,
        #         "triggerStopPrice": "20000",
        #         "entryPrice": null,
        #         "positionSize": null,
        #         "isolatedMargin": null,
        #         "executedQty": null,
        #         "avgPrice": null,
        #         "positionType": "ISOLATED",
        #         "state": "NOT_TRIGGERED",
        #         "createdTime": 1681273420039
        #     }
        #
        # spot editOrder
        #
        #     {
        #         "orderId": "484203027161892224",
        #         "modifyId": "484203544105344000",
        #         "clientModifyId": null
        #     }
        #
        marketId = self.safe_string(order, 'symbol')
        marketType = ('result' in order) or 'contract' if ('positionSide' in order) else 'spot'
        market = self.safe_market(marketId, market, None, marketType)
        symbol = self.safe_symbol(marketId, market, None, marketType)
        timestamp = self.safe_integer_2(order, 'time', 'createdTime')
        quantity = self.safe_number(order, 'origQty')
        amount = quantity if (marketType == 'spot') else Precise.string_mul(self.number_to_string(quantity), self.number_to_string(market['contractSize']))
        filledQuantity = self.safe_number(order, 'executedQty')
        filled = filledQuantity if (marketType == 'spot') else Precise.string_mul(self.number_to_string(filledQuantity), self.number_to_string(market['contractSize']))
        lastUpdatedTimestamp = self.safe_integer(order, 'updatedTime')
        return self.safe_order({
            'info': order,
            'id': self.safe_string_n(order, ['orderId', 'result', 'cancelId', 'entrustId', 'profitId']),
            'clientOrderId': self.safe_string_2(order, 'clientOrderId', 'clientModifyId'),
            'timestamp': timestamp,
            'datetime': self.iso8601(timestamp),
            'lastTradeTimestamp': lastUpdatedTimestamp,
            'lastUpdateTimestamp': lastUpdatedTimestamp,
            'symbol': symbol,
            'type': self.safe_string_lower_2(order, 'type', 'orderType'),
            'timeInForce': self.safe_string(order, 'timeInForce'),
            'postOnly': None,
            'side': self.safe_string_lower_2(order, 'side', 'orderSide'),
            'price': self.safe_number(order, 'price'),
            'triggerPrice': self.safe_number(order, 'stopPrice'),
            'stopLoss': self.safe_number(order, 'triggerStopPrice'),
            'takeProfit': self.safe_number(order, 'triggerProfitPrice'),
            'amount': amount,
            'filled': filled,
            'remaining': self.safe_number(order, 'leavingQty'),
            'cost': None,
            'average': self.safe_number(order, 'avgPrice'),
            'status': self.parse_order_status(self.safe_string(order, 'state')),
            'fee': {
                'currency': self.safe_currency_code(self.safe_string(order, 'feeCurrency')),
                'cost': self.safe_number(order, 'fee'),
            },
            'trades': None,
        }, market)

    def parse_order_status(self, status):
        statuses = {
            'NEW': 'open',
            'PARTIALLY_FILLED': 'open',
            'FILLED': 'closed',
            'CANCELED': 'canceled',
            'REJECTED': 'rejected',
            'EXPIRED': 'expired',
            'UNFINISHED': 'open',
            'NOT_TRIGGERED': 'open',
            'TRIGGERING': 'open',
            'TRIGGERED': 'closed',
            'USER_REVOCATION': 'canceled',
            'PLATFORM_REVOCATION': 'rejected',
            'HISTORY': 'expired',
        }
        return self.safe_string(statuses, status, status)

    def fetch_ledger(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[LedgerEntry]:
        """
        fetch the history of changes, actions done by the user or operations that altered the balance of the user

        https://doc.xt.com/#futures_usergetBalanceBill

        :param str [code]: unified currency code
        :param int [since]: timestamp in ms of the earliest ledger entry
        :param int [limit]: max number of ledger entries to return
        :param dict params: extra parameters specific to the xt api endpoint
        :returns dict: a `ledger structure <https://docs.ccxt.com/en/latest/manual.html#ledger-structure>`
        """
        self.load_markets()
        request = {}
        currency = None
        if code is not None:
            currency = self.currency(code)
        if since is not None:
            request['startTime'] = since
        if limit is not None:
            request['limit'] = limit
        type = None
        subType = None
        response = None
        type, params = self.handle_market_type_and_params('fetchLedger', None, params)
        subType, params = self.handle_sub_type_and_params('fetchLedger', None, params)
        if subType == 'inverse':
            response = self.privateInverseGetFutureUserV1BalanceBills(self.extend(request, params))
        elif (subType == 'linear') or (type == 'swap') or (type == 'future'):
            response = self.privateLinearGetFutureUserV1BalanceBills(self.extend(request, params))
        else:
            raise NotSupported(self.id + ' fetchLedger() does not support spot transactions, only swap and future wallet transactions are supported')
        #
        #     {
        #         "returnCode": 0,
        #         "msgInfo": "success",
        #         "error": null,
        #         "result": {
        #             "hasPrev": False,
        #             "hasNext": False,
        #             "items": [
        #                 {
        #                     "id": "207260567109387525",
        #                     "coin": "usdt",
        #                     "symbol": "btc_usdt",
        #                     "type": "FEE",
        #                     "amount": "-0.0213",
        #                     "side": "SUB",
        #                     "afterAmount": null,
        #                     "createdTime": 1679116769914
        #                 },
        #             ]
        #         }
        #     }
        #
        data = self.safe_value(response, 'result', {})
        ledger = self.safe_value(data, 'items', [])
        return self.parse_ledger(ledger, currency, since, limit)

    def parse_ledger_entry(self, item, currency=None) -> LedgerEntry:
        #
        #     {
        #         "id": "207260567109387524",
        #         "coin": "usdt",
        #         "symbol": "btc_usdt",
        #         "type": "FEE",
        #         "amount": "-0.0213",
        #         "side": "SUB",
        #         "afterAmount": null,
        #         "createdTime": 1679116769914
        #     }
        #
        side = self.safe_string(item, 'side')
        direction = 'in' if (side == 'ADD') else 'out'
        currencyId = self.safe_string(item, 'coin')
        currency = self.safe_currency(currencyId, currency)
        timestamp = self.safe_integer(item, 'createdTime')
        return self.safe_ledger_entry({
            'info': item,
            'id': self.safe_string(item, 'id'),
            'direction': direction,
            'account': None,
            'referenceId': None,
            'referenceAccount': None,
            'type': self.parse_ledger_entry_type(self.safe_string(item, 'type')),
            'currency': self.safe_currency_code(currencyId, currency),
            'amount': self.safe_number(item, 'amount'),
            'timestamp': timestamp,
            'datetime': self.iso8601(timestamp),
            'before': None,
            'after': self.safe_number(item, 'afterAmount'),
            'status': None,
            'fee': {
                'currency': None,
                'cost': None,
            },
        }, currency)

    def parse_ledger_entry_type(self, type):
        ledgerType = {
            'EXCHANGE': 'transfer',
            'CLOSE_POSITION': 'trade',
            'TAKE_OVER': 'trade',
            'MERGE': 'trade',
            'QIANG_PING_MANAGER': 'fee',
            'FUND': 'fee',
            'FEE': 'fee',
            'ADL': 'auto-deleveraging',
        }
        return self.safe_string(ledgerType, type, type)

    def fetch_deposit_address(self, code: str, params={}) -> DepositAddress:
        """
        fetch the deposit address for a currency associated with self account

        https://doc.xt.com/#deposit_withdrawaldepositAddressGet

        :param str code: unified currency code
        :param dict params: extra parameters specific to the xt api endpoint
        :param str params['network']: required network id
        :returns dict: an `address structure <https://docs.ccxt.com/en/latest/manual.html#address-structure>`
        """
        self.load_markets()
        networkCode = None
        networkCode, params = self.handle_network_code_and_params(params)
        currency = self.currency(code)
        networkId = self.network_code_to_id(networkCode, code)
        self.check_required_argument('fetchDepositAddress', networkId, 'network')
        request = {
            'currency': currency['id'],
            'chain': networkId,
        }
        response = self.privateSpotGetDepositAddress(self.extend(request, params))
        #
        #     {
        #         "rc": 0,
        #         "mc": "SUCCESS",
        #         "ma": [],
        #         "result": {
        #             "address": "0x7f7173cf29d3846d20ca5a3aec1120b93dbd157a",
        #             "memo": ""
        #         }
        #     }
        #
        result = self.safe_value(response, 'result', {})
        return self.parse_deposit_address(result, currency)

    def parse_deposit_address(self, depositAddress, currency=None) -> DepositAddress:
        #
        #     {
        #         "address": "0x7f7173cf29d3846d20ca5a3aec1120b93dbd157a",
        #         "memo": ""
        #     }
        #
        address = self.safe_string(depositAddress, 'address')
        self.check_address(address)
        return {
            'info': depositAddress,
            'currency': self.safe_currency_code(None, currency),
            'network': None,
            'address': address,
            'tag': self.safe_string(depositAddress, 'memo'),
        }

    def fetch_deposits(self, code: Str = None, since: Int = None, limit: Int = None, params={}):
        """
        fetch all deposits made to an account

        https://doc.xt.com/#deposit_withdrawalhistoryDepositGet

        :param str [code]: unified currency code
        :param int [since]: the earliest time in ms to fetch deposits for
        :param int [limit]: the maximum number of transaction structures to retrieve
        :param dict params: extra parameters specific to the xt api endpoint
        :returns dict[]: a list of `transaction structures <https://docs.ccxt.com/en/latest/manual.html#transaction-structure>`
        """
        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['startTime'] = since
        if limit is not None:
            request['limit'] = limit  # default 10, max 200
        response = self.privateSpotGetDepositHistory(self.extend(request, params))
        #
        #     {
        #         "rc": 0,
        #         "mc": "SUCCESS",
        #         "ma": [],
        #         "result": {
        #             "hasPrev": False,
        #             "hasNext": False,
        #             "items": [
        #                 {
        #                     "id": 170368702,
        #                     "currency": "usdt",
        #                     "chain": "Ethereum",
        #                     "memo": "",
        #                     "status": "SUCCESS",
        #                     "amount": "31.792528",
        #                     "confirmations": 12,
        #                     "transactionId": "0x90b8487c258b81b85e15e461b1839c49d4d8e6e9de4c1adb658cd47d4f5c5321",
        #                     "address": "0x7f7172cf29d3846d30ca5a3aec1120b92dbd150b",
        #                     "fromAddr": "0x7830c87c02e56aff27fa9ab1241711331fa86f58",
        #                     "createdTime": 1678491442000
        #                 },
        #             ]
        #         }
        #     }
        #
        data = self.safe_value(response, 'result', {})
        deposits = self.safe_value(data, 'items', [])
        return self.parse_transactions(deposits, currency, since, limit, params)

    def fetch_withdrawals(self, code: Str = None, since: Int = None, limit: Int = None, params={}):
        """
        fetch all withdrawals made from an account

        https://doc.xt.com/#deposit_withdrawalwithdrawHistory

        :param str [code]: unified currency code
        :param int [since]: the earliest time in ms to fetch withdrawals for
        :param int [limit]: the maximum number of transaction structures to retrieve
        :param dict params: extra parameters specific to the xt api endpoint
        :returns dict[]: a list of `transaction structures <https://docs.ccxt.com/en/latest/manual.html#transaction-structure>`
        """
        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['startTime'] = since
        if limit is not None:
            request['limit'] = limit  # default 10, max 200
        response = self.privateSpotGetWithdrawHistory(self.extend(request, params))
        #
        #     {
        #         "rc": 0,
        #         "mc": "SUCCESS",
        #         "ma": [],
        #         "result": {
        #             "hasPrev": False,
        #             "hasNext": False,
        #             "items": [
        #                 {
        #                     "id": 950898,
        #                     "currency": "usdt",
        #                     "chain": "Tron",
        #                     "address": "TGB2vxTjiqraVZBy7YHXF8V3CSMVhQKcaf",
        #                     "memo": "",
        #                     "status": "SUCCESS",
        #                     "amount": "5",
        #                     "fee": "2",
        #                     "confirmations": 6,
        #                     "transactionId": "c36e230b879842b1d7afd19d15ee1a866e26eaa0626e367d6f545d2932a15156",
        #                     "createdTime": 1680049062000
        #                 }
        #             ]
        #         }
        #     }
        #
        data = self.safe_value(response, 'result', {})
        withdrawals = self.safe_value(data, 'items', [])
        return self.parse_transactions(withdrawals, currency, since, limit, params)

    def withdraw(self, code: str, amount: float, address: str, tag: Str = None, params={}) -> Transaction:
        """
        make a withdrawal

        https://doc.xt.com/#deposit_withdrawalwithdraw

        :param str code: unified currency code
        :param float amount: the amount to withdraw
        :param str address: the address to withdraw to
        :param str [tag]:
        :param dict params: extra parameters specific to the xt api endpoint
        :returns dict: a `transaction structure <https://docs.ccxt.com/en/latest/manual.html#transaction-structure>`
        """
        self.check_address(address)
        self.load_markets()
        currency = self.currency(code)
        tag, params = self.handle_withdraw_tag_and_params(tag, params)
        networkCode = None
        networkCode, params = self.handle_network_code_and_params(params)
        networkIdsByCodes = self.safe_value(self.options, 'networks', {})
        networkId = self.safe_string_2(networkIdsByCodes, networkCode, code, code)
        request = {
            'currency': currency['id'],
            'chain': networkId,
            'amount': self.currency_to_precision(code, amount),
            'address': address,
        }
        if tag is not None:
            request['memo'] = tag
        response = self.privateSpotPostWithdraw(self.extend(request, params))
        #
        #     {
        #         "rc": 0,
        #         "mc": "SUCCESS",
        #         "ma": [],
        #         "result": {
        #             "id": 950898
        #         }
        #     }
        #
        result = self.safe_value(response, 'result', {})
        return self.parse_transaction(result, currency)

    def parse_transaction(self, transaction: dict, currency: Currency = None) -> Transaction:
        #
        # fetchDeposits
        #
        #     {
        #         "id": 170368702,
        #         "currency": "usdt",
        #         "chain": "Ethereum",
        #         "memo": "",
        #         "status": "SUCCESS",
        #         "amount": "31.792528",
        #         "confirmations": 12,
        #         "transactionId": "0x90b8487c258b81b85e15e461b1839c49d4d8e6e9de4c1adb658cd47d4f5c5321",
        #         "address": "0x7f7172cf29d3846d30ca5a3aec1120b92dbd150b",
        #         "fromAddr": "0x7830c87c02e56aff27fa9ab1241711331fa86f58",
        #         "createdTime": 1678491442000
        #     }
        #
        # fetchWithdrawals
        #
        #     {
        #         "id": 950898,
        #         "currency": "usdt",
        #         "chain": "Tron",
        #         "address": "TGB2vxTjiqraVZBy7YHXF8V3CSMVhQKcaf",
        #         "memo": "",
        #         "status": "SUCCESS",
        #         "amount": "5",
        #         "fee": "2",
        #         "confirmations": 6,
        #         "transactionId": "c36e230b879842b1d7afd19d15ee1a866e26eaa0626e367d6f545d2932a15156",
        #         "createdTime": 1680049062000
        #     }
        #
        # withdraw
        #
        #     {
        #         "id": 950898
        #     }
        #
        type = 'deposit' if ('fromAddr' in transaction) else 'withdraw'
        timestamp = self.safe_integer(transaction, 'createdTime')
        address = self.safe_string(transaction, 'address')
        memo = self.safe_string(transaction, 'memo')
        currencyCode = self.safe_currency_code(self.safe_string(transaction, 'currency'), currency)
        fee = self.safe_number(transaction, 'fee')
        feeCurrency = currencyCode if (fee is not None) else None
        networkId = self.safe_string(transaction, 'chain')
        return {
            'info': transaction,
            'id': self.safe_string(transaction, 'id'),
            'txid': self.safe_string(transaction, 'transactionId'),
            'timestamp': timestamp,
            'datetime': self.iso8601(timestamp),
            'updated': None,
            'addressFrom': self.safe_string(transaction, 'fromAddr'),
            'addressTo': address,
            'address': address,
            'tagFrom': None,
            'tagTo': None,
            'tag': memo,
            'type': type,
            'amount': self.safe_number(transaction, 'amount'),
            'currency': currencyCode,
            'network': self.network_id_to_code(networkId, currencyCode),
            'status': self.parse_transaction_status(self.safe_string(transaction, 'status')),
            'comment': memo,
            'fee': {
                'currency': feeCurrency,
                'cost': fee,
                'rate': None,
            },
            'internal': None,
        }

    def parse_transaction_status(self, status):
        statuses = {
            'SUBMIT': 'pending',
            'REVIEW': 'pending',
            'AUDITED': 'pending',
            'PENDING': 'pending',
            'CANCEL': 'canceled',
            'FAIL': 'failed',
            'SUCCESS': 'ok',
        }
        return self.safe_string(statuses, status, status)

    def set_leverage(self, leverage: int, symbol: str = None, params={}):
        """
        set the level of leverage for a market

        https://doc.xt.com/#futures_useradjustLeverage

        :param float leverage: the rate of leverage
        :param str symbol: unified market symbol
        :param dict params: extra parameters specific to the xt api endpoint
        :param str params['positionSide']: 'LONG' or 'SHORT'
        :returns dict: response from the exchange
        """
        if symbol is None:
            raise ArgumentsRequired(self.id + ' setLeverage() requires a symbol argument')
        positionSide = self.safe_string(params, 'positionSide')
        self.check_required_argument('setLeverage', positionSide, 'positionSide', ['LONG', 'SHORT'])
        if (leverage < 1) or (leverage > 125):
            raise BadRequest(self.id + ' setLeverage() leverage should be between 1 and 125')
        self.load_markets()
        market = self.market(symbol)
        if not (market['contract']):
            raise BadSymbol(self.id + ' setLeverage() supports contract markets only')
        request = {
            'symbol': market['id'],
            'positionSide': positionSide,
            'leverage': leverage,
        }
        subType = None
        subType, params = self.handle_sub_type_and_params('setLeverage', market, params)
        response = None
        if subType == 'inverse':
            response = self.privateInversePostFutureUserV1PositionAdjustLeverage(self.extend(request, params))
        else:
            response = self.privateLinearPostFutureUserV1PositionAdjustLeverage(self.extend(request, params))
        #
        #     {
        #         "returnCode": 0,
        #         "msgInfo": "success",
        #         "error": null,
        #         "result": null
        #     }
        #
        return response

    def add_margin(self, symbol: str, amount: float, params={}):
        """
        add margin to a position

        https://doc.xt.com/#futures_useradjustMargin

        :param str symbol: unified market symbol
        :param float amount: amount of margin to add
        :param dict params: extra parameters specific to the xt api endpoint
        :param str params['positionSide']: 'LONG' or 'SHORT'
        :returns dict: a `margin structure <https://docs.ccxt.com/?id=margin-structure>`
        """
        return self.modify_margin_helper(symbol, amount, 'ADD', params)

    def reduce_margin(self, symbol: str, amount: float, params={}):
        """
        remove margin from a position

        https://doc.xt.com/#futures_useradjustMargin

        :param str symbol: unified market symbol
        :param float amount: the amount of margin to remove
        :param dict params: extra parameters specific to the xt api endpoint
        :param str params['positionSide']: 'LONG' or 'SHORT'
        :returns dict: a `margin structure <https://docs.ccxt.com/?id=margin-structure>`
        """
        return self.modify_margin_helper(symbol, amount, 'SUB', params)

    def modify_margin_helper(self, symbol: str, amount, addOrReduce, params={}) -> MarginModification:
        positionSide = self.safe_string(params, 'positionSide')
        self.check_required_argument('setLeverage', positionSide, 'positionSide', ['LONG', 'SHORT'])
        self.load_markets()
        market = self.market(symbol)
        request = {
            'symbol': market['id'],
            'margin': amount,
            'type': addOrReduce,
            'positionSide': positionSide,
        }
        subType = None
        subType, params = self.handle_sub_type_and_params('modifyMarginHelper', market, params)
        response = None
        if subType == 'inverse':
            response = self.privateInversePostFutureUserV1PositionMargin(self.extend(request, params))
        else:
            response = self.privateLinearPostFutureUserV1PositionMargin(self.extend(request, params))
        #
        #     {
        #         "returnCode": 0,
        #         "msgInfo": "success",
        #         "error": null,
        #         "result": null
        #     }
        #
        return self.parse_margin_modification(response, market)

    def parse_margin_modification(self, data, market=None) -> MarginModification:
        return {
            'info': data,
            'type': None,
            'amount': None,
            'code': None,
            'symbol': self.safe_symbol(None, market),
            'status': None,
            'marginMode': None,
            'total': None,
            'timestamp': None,
            'datetime': None,
        }

    def fetch_leverage_tiers(self, symbols: List[str] = None, params={}) -> LeverageTiers:
        """
        retrieve information on the maximum leverage for different trade sizes

        https://doc.xt.com/#futures_quotesgetLeverageBrackets

        :param str [symbols]: a list of unified market symbols
        :param dict params: extra parameters specific to the xt api endpoint
        :returns dict: a dictionary of `leverage tiers structures <https://docs.ccxt.com/?id=leverage-tiers-structure>`
        """
        self.load_markets()
        subType = None
        subType, params = self.handle_sub_type_and_params('fetchLeverageTiers', None, params)
        response = None
        if subType == 'inverse':
            response = self.publicInverseGetFutureMarketV1PublicLeverageBracketList(params)
        else:
            response = self.publicLinearGetFutureMarketV1PublicLeverageBracketList(params)
        #
        #     {
        #         "returnCode": 0,
        #         "msgInfo": "success",
        #         "error": null,
        #         "result": [
        #             {
        #                 "symbol": "rad_usdt",
        #                 "leverageBrackets": [
        #                     {
        #                         "symbol": "rad_usdt",
        #                         "bracket": 1,
        #                         "maxNominalValue": "5000",
        #                         "maintMarginRate": "0.025",
        #                         "startMarginRate": "0.05",
        #                         "maxStartMarginRate": null,
        #                         "maxLeverage": "20",
        #                         "minLeverage": "1"
        #                     },
        #                 ]
        #             },
        #         ]
        #     }
        #
        data = self.safe_value(response, 'result', [])
        symbols = self.market_symbols(symbols)
        return self.parse_leverage_tiers(data, symbols, 'symbol')

    def parse_leverage_tiers(self, response, symbols=None, marketIdKey=None) -> LeverageTiers:
        #
        #     {
        #         "symbol": "rad_usdt",
        #         "leverageBrackets": [
        #             {
        #                 "symbol": "rad_usdt",
        #                 "bracket": 1,
        #                 "maxNominalValue": "5000",
        #                 "maintMarginRate": "0.025",
        #                 "startMarginRate": "0.05",
        #                 "maxStartMarginRate": null,
        #                 "maxLeverage": "20",
        #                 "minLeverage": "1"
        #             },
        #         ]
        #     }
        #
        result = {}
        for i in range(0, len(response)):
            entry = response[i]
            marketId = self.safe_string(entry, 'symbol')
            market = self.safe_market(marketId, None, '_', 'contract')
            symbol = self.safe_symbol(marketId, market)
            if symbols is not None:
                if self.in_array(symbol, symbols):
                    result[symbol] = self.parse_market_leverage_tiers(entry, market)
            else:
                result[symbol] = self.parse_market_leverage_tiers(response[i], market)
        return result

    def fetch_market_leverage_tiers(self, symbol: str, params={}) -> List[LeverageTier]:
        """
        retrieve information on the maximum leverage for different trade sizes of a single market

        https://doc.xt.com/#futures_quotesgetLeverageBracket

        :param str symbol: unified market symbol
        :param dict params: extra parameters specific to the xt api endpoint
        :returns dict: a `leverage tiers structure <https://docs.ccxt.com/?id=leverage-tiers-structure>`
        """
        self.load_markets()
        market = self.market(symbol)
        request = {
            'symbol': market['id'],
        }
        subType = None
        subType, params = self.handle_sub_type_and_params('fetchMarketLeverageTiers', market, params)
        response = None
        if subType == 'inverse':
            response = self.publicInverseGetFutureMarketV1PublicLeverageBracketDetail(self.extend(request, params))
        else:
            response = self.publicLinearGetFutureMarketV1PublicLeverageBracketDetail(self.extend(request, params))
        #
        #     {
        #         "returnCode": 0,
        #         "msgInfo": "success",
        #         "error": null,
        #         "result": {
        #             "symbol": "btc_usdt",
        #             "leverageBrackets": [
        #                 {
        #                     "symbol": "btc_usdt",
        #                     "bracket": 1,
        #                     "maxNominalValue": "500000",
        #                     "maintMarginRate": "0.004",
        #                     "startMarginRate": "0.008",
        #                     "maxStartMarginRate": null,
        #                     "maxLeverage": "125",
        #                     "minLeverage": "1"
        #                 },
        #             ]
        #         }
        #     }
        #
        data = self.safe_value(response, 'result', {})
        return self.parse_market_leverage_tiers(data, market)

    def parse_market_leverage_tiers(self, info, market=None) -> List[LeverageTier]:
        #
        #     {
        #         "symbol": "rad_usdt",
        #         "leverageBrackets": [
        #             {
        #                 "symbol": "rad_usdt",
        #                 "bracket": 1,
        #                 "maxNominalValue": "5000",
        #                 "maintMarginRate": "0.025",
        #                 "startMarginRate": "0.05",
        #                 "maxStartMarginRate": null,
        #                 "maxLeverage": "20",
        #                 "minLeverage": "1"
        #             },
        #         ]
        #     }
        #
        tiers = []
        brackets = self.safe_value(info, 'leverageBrackets', [])
        for i in range(0, len(brackets)):
            tier = brackets[i]
            marketId = self.safe_string(info, 'symbol')
            market = self.safe_market(marketId, market, '_', 'contract')
            minNotional = self.safe_number(brackets[i - 1], 'maxNominalValue', 0)
            tiers.append({
                'tier': self.safe_integer(tier, 'bracket'),
                'symbol': self.safe_symbol(marketId, market, '_', 'contract'),
                'currency': market['settle'],
                'minNotional': minNotional,
                'maxNotional': self.safe_number(tier, 'maxNominalValue'),
                'maintenanceMarginRate': self.safe_number(tier, 'maintMarginRate'),
                'maxLeverage': self.safe_number(tier, 'maxLeverage'),
                'info': tier,
            })
        return tiers

    def fetch_funding_rate_history(self, symbol: str = None, since: Int = None, limit: Int = None, params={}):
        """
        fetches historical funding rates

        https://doc.xt.com/#futures_quotesgetFundingRateRecord

        :param str [symbol]: unified symbol of the market to fetch the funding rate history for
        :param int [since]: timestamp in ms of the earliest funding rate to fetch
        :param int [limit]: the maximum amount of [funding rate structures] to fetch
        :param dict params: extra parameters specific to the xt api endpoint
        :param bool params['paginate']: True/false whether to use the pagination helper to aumatically paginate through the results
        :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')
        self.load_markets()
        paginate = False
        paginate, params = self.handle_option_and_params(params, 'fetchFundingRateHistory', 'paginate')
        if paginate:
            return self.fetch_paginated_call_cursor('fetchFundingRateHistory', symbol, since, limit, params, 'id', 'id', 1, 200)
        market = self.market(symbol)
        if not market['swap']:
            raise BadSymbol(self.id + ' fetchFundingRateHistory() supports swap contracts only')
        request = {
            'symbol': market['id'],
        }
        if limit is not None:
            request['limit'] = limit
        else:
            request['limit'] = 200  # max
        subType = None
        subType, params = self.handle_sub_type_and_params('fetchFundingRateHistory', market, params)
        response = None
        if subType == 'inverse':
            response = self.publicInverseGetFutureMarketV1PublicQFundingRateRecord(self.extend(request, params))
        else:
            response = self.publicLinearGetFutureMarketV1PublicQFundingRateRecord(self.extend(request, params))
        #
        #     {
        #         "returnCode": 0,
        #         "msgInfo": "success",
        #         "error": null,
        #         "result": {
        #             "hasPrev": False,
        #             "hasNext": True,
        #             "items": [
        #                 {
        #                     "id": "210441653482221888",
        #                     "symbol": "btc_usdt",
        #                     "fundingRate": "0.000057",
        #                     "createdTime": 1679875200000,
        #                     "collectionInternal": 28800
        #                 },
        #             ]
        #         }
        #     }
        #
        result = self.safe_value(response, 'result', {})
        items = self.safe_value(result, 'items', [])
        rates = []
        for i in range(0, len(items)):
            entry = items[i]
            marketId = self.safe_string(entry, 'symbol')
            symbolInner = self.safe_symbol(marketId, market)
            timestamp = self.safe_integer(entry, 'createdTime')
            rates.append({
                'info': entry,
                'symbol': symbolInner,
                '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)

    def fetch_funding_interval(self, symbol: str, params={}) -> FundingRate:
        """
        fetch the current funding rate interval

        https://doc.xt.com/#futures_quotesgetFundingRate

        :param str symbol: unified market symbol
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: a `funding rate structure <https://docs.ccxt.com/?id=funding-rate-structure>`
        """
        return self.fetch_funding_rate(symbol, params)

    def fetch_funding_rate(self, symbol: str, params={}) -> FundingRate:
        """
        fetch the current funding rate

        https://doc.xt.com/#futures_quotesgetFundingRate

        :param str symbol: unified market symbol
        :param dict params: extra parameters specific to the xt api endpoint
        :returns dict: a `funding rate structure <https://docs.ccxt.com/?id=funding-rate-structure>`
        """
        self.load_markets()
        market = self.market(symbol)
        if not market['swap']:
            raise BadSymbol(self.id + ' fetchFundingRate() supports swap contracts only')
        request = {
            'symbol': market['id'],
        }
        subType = None
        subType, params = self.handle_sub_type_and_params('fetchFundingRate', market, params)
        response = None
        if subType == 'inverse':
            response = self.publicInverseGetFutureMarketV1PublicQFundingRate(self.extend(request, params))
        else:
            response = self.publicLinearGetFutureMarketV1PublicQFundingRate(self.extend(request, params))
        #
        #     {
        #         "returnCode": 0,
        #         "msgInfo": "success",
        #         "error": null,
        #         "result": {
        #             "symbol": "btc_usdt",
        #             "fundingRate": "0.000086",
        #             "nextCollectionTime": 1680307200000,
        #             "collectionInternal": 8
        #         }
        #     }
        #
        result = self.safe_value(response, 'result', {})
        return self.parse_funding_rate(result, market)

    def parse_funding_rate(self, contract, market=None) -> FundingRate:
        #
        #     {
        #         "symbol": "btc_usdt",
        #         "fundingRate": "0.000086",
        #         "nextCollectionTime": 1680307200000,
        #         "collectionInternal": 8
        #     }
        #
        marketId = self.safe_string(contract, 'symbol')
        symbol = self.safe_symbol(marketId, market, '_', 'swap')
        timestamp = self.safe_integer(contract, 'nextCollectionTime')
        interval = self.safe_string(contract, 'collectionInternal')
        if interval is not None:
            interval = interval + 'h'
        return {
            'info': contract,
            'symbol': symbol,
            'markPrice': None,
            'indexPrice': None,
            'interestRate': None,
            'estimatedSettlePrice': None,
            'timestamp': None,
            'datetime': None,
            'fundingRate': self.safe_number(contract, 'fundingRate'),
            'fundingTimestamp': timestamp,
            'fundingDatetime': self.iso8601(timestamp),
            'nextFundingRate': None,
            'nextFundingTimestamp': None,
            'nextFundingDatetime': None,
            'previousFundingRate': None,
            'previousFundingTimestamp': None,
            'previousFundingDatetime': None,
            'interval': interval,
        }

    def fetch_funding_history(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
        """
        fetch the funding history

        https://doc.xt.com/#futures_usergetFunding

        :param str symbol: unified market symbol
        :param int [since]: the starting timestamp in milliseconds
        :param int [limit]: the number of entries to return
        :param dict params: extra parameters specific to the xt api endpoint
        :returns dict[]: a list of `funding history structures <https://docs.ccxt.com/?id=funding-history-structure>`
        """
        self.load_markets()
        market = self.market(symbol)
        if not market['swap']:
            raise BadSymbol(self.id + ' fetchFundingHistory() supports swap contracts only')
        request = {
            'symbol': market['id'],
        }
        if since is not None:
            request['startTime'] = since
        if limit is not None:
            request['limit'] = limit
        subType = None
        subType, params = self.handle_sub_type_and_params('fetchFundingHistory', market, params)
        response = None
        if subType == 'inverse':
            response = self.privateInverseGetFutureUserV1BalanceFundingRateList(self.extend(request, params))
        else:
            response = self.privateLinearGetFutureUserV1BalanceFundingRateList(self.extend(request, params))
        #
        #     {
        #         "returnCode": 0,
        #         "msgInfo": "success",
        #         "error": null,
        #         "result": {
        #             "hasPrev": False,
        #             "hasNext": False,
        #             "items": [
        #                 {
        #                     "id": "210804044057280512",
        #                     "symbol": "btc_usdt",
        #                     "cast": "-0.0013",
        #                     "coin": "usdt",
        #                     "positionSide": "SHORT",
        #                     "createdTime": 1679961600653
        #                 },
        #             ]
        #         }
        #     }
        #
        data = self.safe_value(response, 'result', {})
        items = self.safe_value(data, 'items', [])
        result = []
        for i in range(0, len(items)):
            entry = items[i]
            result.append(self.parse_funding_history(entry, market))
        sorted = self.sort_by(result, 'timestamp')
        return self.filter_by_since_limit(sorted, since, limit)

    def parse_funding_history(self, contract, market=None):
        #
        #     {
        #         "id": "210804044057280512",
        #         "symbol": "btc_usdt",
        #         "cast": "-0.0013",
        #         "coin": "usdt",
        #         "positionSide": "SHORT",
        #         "createdTime": 1679961600653
        #     }
        #
        marketId = self.safe_string(contract, 'symbol')
        symbol = self.safe_symbol(marketId, market, '_', 'swap')
        currencyId = self.safe_string(contract, 'coin')
        code = self.safe_currency_code(currencyId)
        timestamp = self.safe_integer(contract, 'createdTime')
        return {
            'info': contract,
            'symbol': symbol,
            'code': code,
            'timestamp': timestamp,
            'datetime': self.iso8601(timestamp),
            'id': self.safe_string(contract, 'id'),
            'amount': self.safe_number(contract, 'cast'),
        }

    def fetch_position(self, symbol: str, params={}):
        """
        fetch data on a single open contract trade position

        https://doc.xt.com/#futures_usergetPosition

        :param str symbol: unified market symbol of the market the position is held in
        :param dict params: extra parameters specific to the xt api endpoint
        :returns dict: a `position structure <https://docs.ccxt.com/?id=position-structure>`
        """
        self.load_markets()
        market = self.market(symbol)
        request = {
            'symbol': market['id'],
        }
        subType = None
        subType, params = self.handle_sub_type_and_params('fetchPosition', market, params)
        response = None
        if subType == 'inverse':
            response = self.privateInverseGetFutureUserV1PositionList(self.extend(request, params))
        else:
            response = self.privateLinearGetFutureUserV1PositionList(self.extend(request, params))
        #
        #     {
        #         "returnCode": 0,
        #         "msgInfo": "success",
        #         "error": null,
        #         "result": [
        #             {
        #                 "symbol": "btc_usdt",
        #                 "positionType": "ISOLATED",
        #                 "positionSide": "SHORT",
        #                 "contractType": "PERPETUAL",
        #                 "positionSize": "10",
        #                 "closeOrderSize": "0",
        #                 "availableCloseSize": "10",
        #                 "entryPrice": "27060",
        #                 "openOrderSize": "0",
        #                 "isolatedMargin": "1.0824",
        #                 "openOrderMarginFrozen": "0",
        #                 "realizedProfit": "-0.00130138",
        #                 "autoMargin": False,
        #                 "leverage": 25
        #             },
        #         ]
        #     }
        #
        positions = self.safe_value(response, 'result', [])
        for i in range(0, len(positions)):
            entry = positions[i]
            marketId = self.safe_string(entry, 'symbol')
            marketInner = self.safe_market(marketId, None, None, 'contract')
            positionSize = self.safe_string(entry, 'positionSize')
            if positionSize != '0':
                return self.parse_position(entry, marketInner)
        return None

    def fetch_positions(self, symbols: List[str] = None, params={}) -> List[Position]:
        """
        fetch all open positions

        https://doc.xt.com/#futures_usergetPosition

        :param str [symbols]: list of unified market symbols, not supported with xt
        :param dict params: extra parameters specific to the xt api endpoint
        :returns dict[]: a list of `position structure <https://docs.ccxt.com/?id=position-structure>`
        """
        self.load_markets()
        subType = None
        subType, params = self.handle_sub_type_and_params('fetchPositions', None, params)
        response = None
        if subType == 'inverse':
            response = self.privateInverseGetFutureUserV1PositionList(params)
        else:
            response = self.privateLinearGetFutureUserV1PositionList(params)
        #
        #     {
        #         "returnCode": 0,
        #         "msgInfo": "success",
        #         "error": null,
        #         "result": [
        #             {
        #                 "symbol": "btc_usdt",
        #                 "positionType": "ISOLATED",
        #                 "positionSide": "SHORT",
        #                 "contractType": "PERPETUAL",
        #                 "positionSize": "10",
        #                 "closeOrderSize": "0",
        #                 "availableCloseSize": "10",
        #                 "entryPrice": "27060",
        #                 "openOrderSize": "0",
        #                 "isolatedMargin": "1.0824",
        #                 "openOrderMarginFrozen": "0",
        #                 "realizedProfit": "-0.00130138",
        #                 "autoMargin": False,
        #                 "leverage": 25
        #             },
        #         ]
        #     }
        #
        positions = self.safe_value(response, 'result', [])
        result = []
        for i in range(0, len(positions)):
            entry = positions[i]
            marketId = self.safe_string(entry, 'symbol')
            marketInner = self.safe_market(marketId, None, None, 'contract')
            result.append(self.parse_position(entry, marketInner))
        return self.filter_by_array_positions(result, 'symbol', symbols, False)

    def parse_position(self, position, market=None):
        #
        #     {
        #         "symbol": "btc_usdt",
        #         "positionType": "ISOLATED",
        #         "positionSide": "SHORT",
        #         "contractType": "PERPETUAL",
        #         "positionSize": "10",
        #         "closeOrderSize": "0",
        #         "availableCloseSize": "10",
        #         "entryPrice": "27060",
        #         "openOrderSize": "0",
        #         "isolatedMargin": "1.0824",
        #         "openOrderMarginFrozen": "0",
        #         "realizedProfit": "-0.00130138",
        #         "autoMargin": False,
        #         "leverage": 25
        #     }
        #
        marketId = self.safe_string(position, 'symbol')
        market = self.safe_market(marketId, market, None, 'contract')
        symbol = self.safe_symbol(marketId, market, None, 'contract')
        positionType = self.safe_string(position, 'positionType')
        marginMode = 'cross' if (positionType == 'CROSSED') else 'isolated'
        collateral = self.safe_number(position, 'isolatedMargin')
        return self.safe_position({
            'info': position,
            'id': None,
            'symbol': symbol,
            'timestamp': None,
            'datetime': None,
            'hedged': None,
            'side': self.safe_string_lower(position, 'positionSide'),
            'contracts': self.safe_number(position, 'positionSize'),
            'contractSize': market['contractSize'],
            'entryPrice': self.safe_number(position, 'entryPrice'),
            'markPrice': None,
            'notional': None,
            'leverage': self.safe_integer(position, 'leverage'),
            'collateral': collateral,
            'initialMargin': collateral,
            'maintenanceMargin': None,
            'initialMarginPercentage': None,
            'maintenanceMarginPercentage': None,
            'unrealizedPnl': None,
            'liquidationPrice': None,
            'marginMode': marginMode,
            'percentage': None,
            'marginRatio': None,
        })

    def transfer(self, code: str, amount: float, fromAccount: str, toAccount: str, params={}) -> TransferEntry:
        """
        transfer currency internally between wallets on the same account

        https://doc.xt.com/#transfersubTransferPost

        :param str code: unified currency code
        :param float amount: amount to transfer
        :param str fromAccount: account to transfer from -  spot, swap, leverage, finance
        :param str toAccount: account to transfer to - spot, swap, leverage, finance
        :param dict params: extra parameters specific to the whitebit api endpoint
        :returns dict: a `transfer structure <https://docs.ccxt.com/?id=transfer-structure>`
        """
        self.load_markets()
        currency = self.currency(code)
        accountsByType = self.safe_value(self.options, 'accountsById')
        fromAccountId = self.safe_string(accountsByType, fromAccount, fromAccount)
        toAccountId = self.safe_string(accountsByType, toAccount, toAccount)
        amountString = self.currency_to_precision(code, amount)
        request = {
            'bizId': self.uuid(),
            'currency': currency['id'],
            'amount': amountString,
            'from': fromAccountId,
            'to': toAccountId,
        }
        response = self.privateSpotPostBalanceTransfer(self.extend(request, params))
        #
        #   {
        #       info: {rc: '0', mc: 'SUCCESS', ma: [], result: '226971333791398656'},
        #       id: '226971333791398656',
        #       timestamp: None,
        #       datetime: None,
        #       currency: None,
        #       amount: None,
        #       fromAccount: None,
        #       toAccount: None,
        #       status: None
        #   }
        #
        return self.parse_transfer(response, currency)

    def parse_transfer(self, transfer, currency=None):
        return {
            'info': transfer,
            'id': self.safe_string(transfer, 'result'),
            'timestamp': None,
            'datetime': None,
            'currency': None,
            'amount': None,
            'fromAccount': None,
            'toAccount': None,
            'status': None,
        }

    def set_margin_mode(self, marginMode: str, symbol: Str = None, params={}):
        """
        set margin mode to 'cross' or 'isolated'

        https://doc.xt.com/#futures_userchangePositionType

        :param str marginMode: 'cross' or 'isolated'
        :param str [symbol]: required
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :param str [params.positionSide]: *required* "long" or "short"
        :returns dict: response from the exchange
        """
        if symbol is None:
            raise ArgumentsRequired(self.id + ' setMarginMode() requires a symbol argument')
        self.load_markets()
        market = self.market(symbol)
        if market['spot']:
            raise BadSymbol(self.id + ' setMarginMode() supports contract markets only')
        marginMode = marginMode.lower()
        if marginMode != 'isolated' and marginMode != 'cross':
            raise BadRequest(self.id + ' setMarginMode() marginMode argument should be isolated or cross')
        if marginMode == 'cross':
            marginMode = 'CROSSED'
        else:
            marginMode = 'ISOLATED'
        posSide = self.safe_string_upper(params, 'positionSide')
        if posSide is None:
            raise ArgumentsRequired(self.id + ' setMarginMode() requires a positionSide parameter, either "LONG" or "SHORT"')
        request: dict = {
            'positionType': marginMode,
            'positionSide': posSide,
            'symbol': market['id'],
        }
        response = self.privateLinearPostFutureUserV1PositionChangeType(self.extend(request, params))
        #
        # {
        #     "error": {
        #       "code": "",
        #       "msg": ""
        #     },
        #     "msgInfo": "",
        #     "result": {},
        #     "returnCode": 0
        # }
        #
        return response  # unify return type

    def edit_order(self, id: str, symbol: str, type: OrderType, side: OrderSide, amount: Num = None, price: Num = None, params={}) -> Order:
        """
        cancels an order and places a new order

        https://doc.xt.com/#orderorderUpdate
        https://doc.xt.com/#futures_orderupdate
        https://doc.xt.com/#futures_entrustupdateProfit

        :param str id: order id
        :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 the currency you want to trade in units of the base currency
        :param float [price]: the price at which the order is to be fulfilled, in units of the quote currency, ignored in market orders
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :param float [params.stopLoss]: price to set a stop-loss on an open position
        :param float [params.takeProfit]: price to set a take-profit on an open position
        :returns dict: an `order structure <https://docs.ccxt.com/?id=order-structure>`
        """
        if amount is None:
            raise ArgumentsRequired(self.id + ' editOrder() requires an amount argument')
        self.load_markets()
        market = self.market(symbol)
        request = {}
        stopLoss = self.safe_number_2(params, 'stopLoss', 'triggerStopPrice')
        takeProfit = self.safe_number_2(params, 'takeProfit', 'triggerProfitPrice')
        params = self.omit(params, ['stopLoss', 'takeProfit'])
        isStopLoss = (stopLoss is not None)
        isTakeProfit = (takeProfit is not None)
        if isStopLoss or isTakeProfit:
            request['profitId'] = id
        else:
            request['orderId'] = id
            request['price'] = self.price_to_precision(symbol, price)
        response = None
        if market['swap']:
            if isStopLoss:
                request['triggerStopPrice'] = self.price_to_precision(symbol, stopLoss)
            elif takeProfit is not None:
                request['triggerProfitPrice'] = self.price_to_precision(symbol, takeProfit)
            else:
                request['origQty'] = self.amount_to_precision(symbol, amount)
            subType = None
            subType, params = self.handle_sub_type_and_params('editOrder', market, params)
            if subType == 'inverse':
                if isStopLoss or isTakeProfit:
                    response = self.privateInversePostFutureTradeV1EntrustUpdateProfitStop(self.extend(request, params))
                else:
                    response = self.privateInversePostFutureTradeV1OrderUpdate(self.extend(request, params))
                    #
                    #     {
                    #         "returnCode": 0,
                    #         "msgInfo": "success",
                    #         "error": null,
                    #         "result": "483869474947826752"
                    #     }
                    #
            else:
                if isStopLoss or isTakeProfit:
                    response = self.privateLinearPostFutureTradeV1EntrustUpdateProfitStop(self.extend(request, params))
                else:
                    response = self.privateLinearPostFutureTradeV1OrderUpdate(self.extend(request, params))
                    #
                    #     {
                    #         "returnCode": 0,
                    #         "msgInfo": "success",
                    #         "error": null,
                    #         "result": "483869474947826752"
                    #     }
                    #
        else:
            request['quantity'] = self.amount_to_precision(symbol, amount)
            response = self.privateSpotPutOrderOrderId(self.extend(request, params))
            #
            #     {
            #         "rc": 0,
            #         "mc": "SUCCESS",
            #         "ma": [],
            #         "result": {
            #             "orderId": "484203027161892224",
            #             "modifyId": "484203544105344000",
            #             "clientModifyId": null
            #         }
            #     }
            #
        result = response if (market['swap']) else self.safe_dict(response, 'result', {})
        return self.parse_order(result, market)

    def handle_errors(self, code, reason, url, method, headers, body, response, requestHeaders, requestBody):
        #
        # spot: error
        #
        #     {
        #         "rc": 1,
        #         "mc": "AUTH_103",
        #         "ma": [],
        #         "result": null
        #     }
        #
        # spot: success
        #
        #     {
        #         "returnCode": 0,
        #         "msgInfo": "success",
        #         "error": null,
        #         "result": []
        #     }
        #
        # swap and future: error
        #
        #     {
        #         "returnCode": 1,
        #         "msgInfo": "failure",
        #         "error": {
        #             "code": "403",
        #             "msg": "invalid signature"
        #         },
        #         "result": null
        #     }
        #
        # swap and future: success
        #
        #     {
        #         "returnCode": 0,
        #         "msgInfo": "success",
        #         "error": null,
        #         "result": null
        #     }
        #
        # other:
        #
        #     {
        #         "rc": 0,
        #         "mc": "SUCCESS",
        #         "ma": [],
        #         "result": {}
        #     }
        #
        # {"returnCode":1,"msgInfo":"failure","error":{"code":"insufficient_balance","msg":"insufficient balance","args":[]},"result":null}
        #
        #
        status = self.safe_string_upper_2(response, 'msgInfo', 'mc')
        if status is not None and status != 'SUCCESS':
            feedback = self.id + ' ' + body
            error = self.safe_value(response, 'error', {})
            spotErrorCode = self.safe_string(response, 'mc')
            errorCode = self.safe_string(error, 'code', spotErrorCode)
            spotMessage = self.safe_string(response, 'msgInfo')
            message = self.safe_string(error, 'msg', spotMessage)
            self.throw_exactly_matched_exception(self.exceptions['exact'], errorCode, feedback)
            self.throw_broadly_matched_exception(self.exceptions['broad'], message, feedback)
            raise ExchangeError(feedback)
        return None

    def sign(self, path, api=[], method='GET', params={}, headers=None, body=None):
        signed = api[0] == 'private'
        endpoint = api[1]
        request = '/' + self.implode_params(path, params)
        payload = None
        if (endpoint == 'spot') or (endpoint == 'user'):
            if signed:
                payload = '/' + self.version + request
            else:
                payload = '/' + self.version + '/public' + request
        else:
            payload = request
        url = self.urls['api'][endpoint] + payload
        query = self.omit(params, self.extract_params(path))
        urlencoded = self.urlencode(self.keysort(query))
        headers = {
            'Content-Type': 'application/json',
        }
        if signed:
            self.check_required_credentials()
            defaultRecvWindow = self.safe_string(self.options, 'recvWindow')
            recvWindow = self.safe_string(query, 'recvWindow', defaultRecvWindow)
            timestamp = self.number_to_string(self.nonce())
            body = query
            if (payload == '/v4/order') or (payload == '/future/trade/v1/order/create') or (payload == '/future/trade/v1/entrust/create-plan') or (payload == '/future/trade/v1/entrust/create-profit') or (payload == '/future/trade/v1/order/create-batch'):
                id = 'CCXT'
                if payload.find('future') > -1:
                    body['clientMedia'] = id
                else:
                    body['media'] = id
            isUndefinedBody = ((method == 'GET') or (path == 'order/{orderId}') or (path == 'ws-token'))
            if (method == 'PUT') and (endpoint == 'spot'):
                isUndefinedBody = False
            body = None if isUndefinedBody else self.json(body)
            payloadString = None
            if (endpoint == 'spot') or (endpoint == 'user'):
                payloadString = 'xt-validate-algorithms=HmacSHA256&xt-validate-appkey=' + self.apiKey + '&xt-validate-recvwindow=' + recvWindow + '&xt-validate-t' + 'imestamp=' + timestamp
                if isUndefinedBody:
                    if urlencoded:
                        url += '?' + urlencoded
                        payloadString += '#' + method + '#' + payload + '#' + self.rawencode(self.keysort(query))
                    else:
                        payloadString += '#' + method + '#' + payload
                else:
                    payloadString += '#' + method + '#' + payload + '#' + body
                headers['xt-validate-algorithms'] = 'HmacSHA256'
                headers['xt-validate-recvwindow'] = recvWindow
            else:
                payloadString = 'xt-validate-appkey=' + self.apiKey + '&xt-validate-t' + 'imestamp=' + timestamp  # we can't glue timestamp, breaks in php
                if method == 'GET':
                    if urlencoded:
                        url += '?' + urlencoded
                        payloadString += '#' + payload + '#' + urlencoded
                    else:
                        payloadString += '#' + payload
                else:
                    payloadString += '#' + payload + '#' + body
            signature = self.hmac(self.encode(payloadString), self.encode(self.secret), hashlib.sha256)
            headers['xt-validate-appkey'] = self.apiKey
            headers['xt-validate-timestamp'] = timestamp
            headers['xt-validate-signature'] = signature
        else:
            if urlencoded:
                url += '?' + urlencoded
        return {'url': url, 'method': method, 'body': body, 'headers': headers}
