# -*- 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.bingx import ImplicitAPI
import hashlib
import numbers
from ccxt.base.types import Balances, Currencies, Currency, Int, Leverage, MarginMode, MarginModification, Market, Num, Order, OrderBook, OrderRequest, OrderSide, OrderType, Position, Str, Strings, Ticker, Tickers, Trade, 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 AccountSuspended
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 OrderNotFound
from ccxt.base.errors import NotSupported
from ccxt.base.errors import DDoSProtection
from ccxt.base.decimal_to_precision import DECIMAL_PLACES
from ccxt.base.precise import Precise


class bingx(Exchange, ImplicitAPI):

    def describe(self):
        return self.deep_extend(super(bingx, self).describe(), {
            'id': 'bingx',
            'name': 'BingX',
            'countries': ['US'],  # North America, Canada, the EU, Hong Kong and Taiwan
            # cheapest is 60 requests a minute = 1 requests per second on average =>( 1000ms / 1) = 1000 ms between requests on average
            'rateLimit': 1000,
            'version': 'v1',
            'certified': True,
            'pro': True,
            'has': {
                'CORS': None,
                'spot': True,
                'margin': False,
                'swap': True,
                'future': False,
                'option': False,
                'addMargin': True,
                'cancelAllOrders': True,
                'cancelOrder': True,
                'cancelOrders': True,
                'closeAllPositions': True,
                'closePosition': True,
                'createMarketBuyOrderWithCost': True,
                'createMarketOrderWithCost': True,
                'createMarketSellOrderWithCost': True,
                'createOrder': True,
                'createOrders': True,
                'createOrderWithTakeProfitAndStopLoss': True,
                'createStopLossOrder': True,
                'createTakeProfitOrder': True,
                'createTrailingAmountOrder': True,
                'createTrailingPercentOrder': True,
                'createTriggerOrder': True,
                'fetchBalance': True,
                'fetchClosedOrders': True,
                'fetchCurrencies': True,
                'fetchDepositAddress': True,
                'fetchDepositAddressesByNetwork': True,
                'fetchDeposits': True,
                'fetchDepositWithdrawFee': 'emulated',
                'fetchDepositWithdrawFees': True,
                'fetchFundingRate': True,
                'fetchFundingRateHistory': True,
                'fetchFundingRates': True,
                'fetchLeverage': True,
                'fetchLiquidations': False,
                'fetchMarginAdjustmentHistory': False,
                'fetchMarginMode': True,
                'fetchMarkets': True,
                'fetchMarkOHLCV': True,
                'fetchMyLiquidations': True,
                'fetchOHLCV': True,
                'fetchOpenInterest': True,
                'fetchOpenOrders': True,
                'fetchOrder': True,
                'fetchOrderBook': True,
                'fetchOrders': True,
                'fetchPositionMode': True,
                'fetchPositions': True,
                'fetchTicker': True,
                'fetchTickers': True,
                'fetchTime': True,
                'fetchTrades': True,
                'fetchTransfers': True,
                'fetchWithdrawals': True,
                'reduceMargin': True,
                'setLeverage': True,
                'setMargin': True,
                'setMarginMode': True,
                'setPositionMode': True,
                'transfer': True,
            },
            'hostname': 'bingx.com',
            'urls': {
                'logo': 'https://github-production-user-asset-6210df.s3.amazonaws.com/1294454/253675376-6983b72e-4999-4549-b177-33b374c195e3.jpg',
                'api': {
                    'spot': 'https://open-api.{hostname}/openApi',
                    'swap': 'https://open-api.{hostname}/openApi',
                    'contract': 'https://open-api.{hostname}/openApi',
                    'wallets': 'https://open-api.{hostname}/openApi',
                    'user': 'https://open-api.{hostname}/openApi',
                    'subAccount': 'https://open-api.{hostname}/openApi',
                    'account': 'https://open-api.{hostname}/openApi',
                    'copyTrading': 'https://open-api.{hostname}/openApi',
                },
                'test': {
                    'swap': 'https://open-api-vst.{hostname}/openApi',  # only swap is really "test" but since the API keys are the same, we want to keep all the functionalities when the user enables the sandboxmode
                },
                'www': 'https://bingx.com/',
                'doc': 'https://bingx-api.github.io/docs/',
                'referral': 'https://bingx.com/invite/OHETOM',
            },
            'fees': {
                'tierBased': True,
                'spot': {
                    'feeSide': 'get',
                    'maker': self.parse_number('0.001'),
                    'taker': self.parse_number('0.001'),
                },
                'swap': {
                    'feeSide': 'quote',
                    'maker': self.parse_number('0.0002'),
                    'taker': self.parse_number('0.0005'),
                },
            },
            'requiredCredentials': {
                'apiKey': True,
                'secret': True,
            },
            'api': {
                'spot': {
                    'v1': {
                        'public': {
                            'get': {
                                'server/time': 3,
                                'common/symbols': 3,
                                'market/trades': 3,
                                'market/depth': 3,
                                'market/kline': 3,
                                'ticker/24hr': 1,
                            },
                        },
                        'private': {
                            'get': {
                                'trade/query': 3,
                                'trade/openOrders': 3,
                                'trade/historyOrders': 3,
                                'trade/myTrades': 3,
                                'user/commissionRate': 3,
                                'account/balance': 3,
                            },
                            'post': {
                                'trade/order': 3,
                                'trade/cancel': 3,
                                'trade/batchOrders': 3,
                                'trade/order/cancelReplace': 3,
                                'trade/cancelOrders': 3,
                                'trade/cancelOpenOrders': 3,
                                'trade/cancelAllAfter': 1,
                            },
                        },
                    },
                    'v3': {
                        'private': {
                            'get': {
                                'get/asset/transfer': 3,
                                'asset/transfer': 3,
                                'capital/deposit/hisrec': 3,
                                'capital/withdraw/history': 3,
                            },
                            'post': {
                                'post/asset/transfer': 3,
                            },
                        },
                    },
                },
                'swap': {
                    'v1': {
                        'public': {
                            'get': {
                                'ticker/price': 1,
                            },
                        },
                        'private': {
                            'get': {
                                'positionSide/dual': 1,
                                'market/markPriceKlines': 1,
                                'trade/batchCancelReplace': 1,
                                'trade/fullOrder': 1,
                            },
                            'post': {
                                'trade/cancelReplace': 1,
                                'positionSide/dual': 1,
                                'trade/closePosition': 1,
                            },
                        },
                    },
                    'v2': {
                        'public': {
                            'get': {
                                'server/time': 3,
                                'quote/contracts': 1,
                                'quote/price': 1,
                                'quote/depth': 1,
                                'quote/trades': 1,
                                'quote/premiumIndex': 1,
                                'quote/fundingRate': 1,
                                'quote/klines': 1,
                                'quote/openInterest': 1,
                                'quote/ticker': 1,
                                'quote/bookTicker': 1,
                            },
                        },
                        'private': {
                            'get': {
                                'user/balance': 3,
                                'user/positions': 3,
                                'user/income': 3,
                                'trade/openOrders': 3,
                                'trade/openOrder': 3,
                                'trade/order': 3,
                                'trade/marginType': 3,
                                'trade/leverage': 3,
                                'trade/forceOrders': 3,
                                'trade/allOrders': 3,
                                'trade/allFillOrders': 3,
                                'user/income/export': 3,
                                'user/commissionRate': 3,
                                'quote/bookTicker': 3,
                            },
                            'post': {
                                'trade/order': 3,
                                'trade/batchOrders': 3,
                                'trade/closeAllPositions': 3,
                                'trade/marginType': 3,
                                'trade/leverage': 3,
                                'trade/positionMargin': 3,
                                'trade/order/test': 3,
                            },
                            'delete': {
                                'trade/order': 3,
                                'trade/batchOrders': 3,
                                'trade/allOpenOrders': 3,
                            },
                        },
                    },
                    'v3': {
                        'public': {
                            'get': {
                                'quote/klines': 1,
                            },
                        },
                    },
                },
                'contract': {
                    'v1': {
                        'private': {
                            'get': {
                                'allPosition': 3,
                                'allOrders': 3,
                                'balance': 3,
                            },
                        },
                    },
                },
                'wallets': {
                    'v1': {
                        'private': {
                            'get': {
                                'capital/config/getall': 3,
                                'capital/deposit/address': 1,
                                'capital/innerTransfer/records': 1,
                                'capital/subAccount/deposit/address': 1,
                                'capital/deposit/subHisrec': 1,
                                'capital/subAccount/innerTransfer/records': 1,
                            },
                            'post': {
                                'capital/withdraw/apply': 3,
                                'capital/innerTransfer/apply': 3,
                                'capital/subAccountInnerTransfer/apply': 3,
                                'capital/deposit/createSubAddress': 1,
                            },
                        },
                    },
                },
                'subAccount': {
                    'v1': {
                        'private': {
                            'get': {
                                'list': 3,
                                'assets': 3,
                                'apiKey/query': 1,
                            },
                            'post': {
                                'create': 3,
                                'apiKey/create': 3,
                                'apiKey/edit': 3,
                                'apiKey/del': 3,
                                'updateStatus': 3,
                            },
                        },
                    },
                },
                'account': {
                    'v1': {
                        'private': {
                            'get': {
                                'uid': 1,
                            },
                            'post': {
                                'innerTransfer/authorizeSubAccount': 3,
                            },
                        },
                    },
                },
                'user': {
                    'auth': {
                        'private': {
                            'post': {
                                'userDataStream': 1,
                            },
                            'put': {
                                'userDataStream': 1,
                            },
                        },
                    },
                },
                'copyTrading': {
                    'v1': {
                        'private': {
                            'get': {
                                'swap/trace/currentTrack': 1,
                            },
                            'post': {
                                'swap/trace/closeTrackOrder': 1,
                                'swap/trace/setTPSL': 1,
                                'spot/trader/sellOrder': 1,
                            },
                        },
                    },
                },
                'api': {
                    'v3': {
                        'private': {
                            'get': {
                                'asset/transfer': 1,
                                'capital/deposit/hisrec': 1,
                                'capital/withdraw/history': 1,
                            },
                            'post': {
                                'post/asset/transfer': 1,
                            },
                        },
                    },
                },
            },
            'timeframes': {
                '1m': '1m',
                '3m': '3m',
                '5m': '5m',
                '15m': '15m',
                '30m': '30m',
                '1h': '1h',
                '2h': '2h',
                '4h': '4h',
                '6h': '6h',
                '12h': '12h',
                '1d': '1d',
                '3d': '3d',
                '1w': '1w',
                '1M': '1M',
            },
            'precisionMode': DECIMAL_PLACES,
            'exceptions': {
                'exact': {
                    '400': BadRequest,
                    '401': AuthenticationError,
                    '403': PermissionDenied,
                    '404': BadRequest,
                    '429': DDoSProtection,
                    '418': PermissionDenied,
                    '500': ExchangeError,
                    '504': ExchangeError,
                    '100001': AuthenticationError,
                    '100412': AuthenticationError,
                    '100202': InsufficientFunds,
                    '100204': BadRequest,
                    '100400': BadRequest,
                    '100421': BadSymbol,  # {"code":100421,"msg":"This pair is currently restricted from API trading","debugMsg":""}
                    '100440': ExchangeError,
                    '100500': ExchangeError,
                    '100503': ExchangeError,
                    '80001': BadRequest,
                    '80012': InsufficientFunds,  # bingx {"code":80012,"msg":"{\"Code\":101253,\"Msg\":\"margin is not enough\"}}
                    '80014': BadRequest,
                    '80016': OrderNotFound,
                    '80017': OrderNotFound,
                    '100414': AccountSuspended,  # {"code":100414,"msg":"Code: 100414, Msg: risk control check fail,code(1)","debugMsg":""}
                    '100419': PermissionDenied,  # {"code":100419,"msg":"IP does not match IP whitelist","success":false,"timestamp":1705274099347}
                    '100437': BadRequest,  # {"code":100437,"msg":"The withdrawal amount is lower than the minimum limit, please re-enter.","timestamp":1689258588845}
                    '101204': InsufficientFunds,  # bingx {"code":101204,"msg":"","data":{}}
                },
                'broad': {},
            },
            'commonCurrencies': {
                'SNOW': 'Snowman',  # Snowman vs SnowSwap conflict
            },
            'options': {
                'defaultType': 'spot',
                'accountsByType': {
                    'spot': 'FUND',
                    'swap': 'PFUTURES',
                    'future': 'SFUTURES',
                },
                'accountsById': {
                    'FUND': 'spot',
                    'PFUTURES': 'swap',
                    'SFUTURES': 'future',
                },
                'recvWindow': 5 * 1000,  # 5 sec
                'broker': 'CCXT',
                'defaultNetworks': {
                    'ETH': 'ETH',
                    'USDT': 'ERC20',
                    'USDC': 'ERC20',
                    'BTC': 'BTC',
                    'LTC': 'LTC',
                },
            },
        })

    def fetch_time(self, params={}):
        """
        fetches the current integer timestamp in milliseconds from the bingx server
        :see: https://bingx-api.github.io/docs/#/swapV2/base-info.html#Get%20Server%20Time
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns int: the current integer timestamp in milliseconds from the bingx server
        """
        response = self.swapV2PublicGetServerTime(params)
        #
        #    {
        #        "code": 0,
        #        "msg": "",
        #        "data": {
        #            "serverTime": 1675319535362
        #        }
        #    }
        #
        data = self.safe_dict(response, 'data')
        return self.safe_integer(data, 'serverTime')

    def fetch_currencies(self, params={}) -> Currencies:
        """
        fetches all available currencies on an exchange
        :see: https://bingx-api.github.io/docs/#/common/account-api.html#All%20Coins
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: an associative dictionary of currencies
        """
        if not self.check_required_credentials(False):
            return None
        isSandbox = self.safe_bool(self.options, 'sandboxMode', False)
        if isSandbox:
            return None
        response = self.walletsV1PrivateGetCapitalConfigGetall(params)
        #
        #    {
        #        "code": 0,
        #        "timestamp": 1688045966616,
        #        "data": [
        #            {
        #              "coin": "BTC",
        #              "name": "BTC",
        #              "networkList": [
        #                {
        #                  "name": "BTC",
        #                  "network": "BTC",
        #                  "isDefault": True,
        #                  "minConfirm": "2",
        #                  "withdrawEnable": True,
        #                  "withdrawFee": "0.00035",
        #                  "withdrawMax": "1.62842",
        #                  "withdrawMin": "0.0005"
        #                },
        #                {
        #                  "name": "BTC",
        #                  "network": "BEP20",
        #                  "isDefault": False,
        #                  "minConfirm": "15",
        #                  "withdrawEnable": True,
        #                  "withdrawFee": "0.00001",
        #                  "withdrawMax": "1.62734",
        #                  "withdrawMin": "0.0001"
        #                }
        #              ]
        #          },
        #          ...
        #        ],
        #    }
        #
        data = self.safe_list(response, 'data', [])
        result = {}
        for i in range(0, len(data)):
            entry = data[i]
            currencyId = self.safe_string(entry, 'coin')
            code = self.safe_currency_code(currencyId)
            name = self.safe_string(entry, 'name')
            networkList = self.safe_list(entry, 'networkList')
            networks = {}
            fee = None
            active = None
            withdrawEnabled = None
            defaultLimits = {}
            for j in range(0, len(networkList)):
                rawNetwork = networkList[j]
                network = self.safe_string(rawNetwork, 'network')
                networkCode = self.network_id_to_code(network)
                isDefault = self.safe_bool(rawNetwork, 'isDefault')
                withdrawEnabled = self.safe_bool(rawNetwork, 'withdrawEnable')
                limits = {
                    'amounts': {'min': self.safe_number(rawNetwork, 'withdrawMin'), 'max': self.safe_number(rawNetwork, 'withdrawMax')},
                }
                if isDefault:
                    fee = self.safe_number(rawNetwork, 'withdrawFee')
                    active = withdrawEnabled
                    defaultLimits = limits
                networks[networkCode] = {
                    'info': rawNetwork,
                    'id': network,
                    'network': networkCode,
                    'fee': fee,
                    'active': active,
                    'deposit': None,
                    'withdraw': withdrawEnabled,
                    'precision': None,
                    'limits': limits,
                }
            result[code] = {
                'info': entry,
                'code': code,
                'id': currencyId,
                'precision': None,
                'name': name,
                'active': active,
                'deposit': None,
                'withdraw': withdrawEnabled,
                'networks': networks,
                'fee': fee,
                'limits': defaultLimits,
            }
        return result

    def fetch_spot_markets(self, params):
        response = self.spotV1PublicGetCommonSymbols(params)
        #
        #    {
        #        "code": 0,
        #            "msg": "",
        #            "debugMsg": "",
        #            "data": {
        #              "symbols": [
        #                  {
        #                    "symbol": "GEAR-USDT",
        #                    "minQty": 735,
        #                    "maxQty": 2941177,
        #                    "minNotional": 5,
        #                    "maxNotional": 20000,
        #                    "status": 1,
        #                    "tickSize": 0.000001,
        #                    "stepSize": 1
        #                  },
        #                  ...
        #              ]
        #         }
        #    }
        #
        data = self.safe_dict(response, 'data')
        markets = self.safe_list(data, 'symbols', [])
        return self.parse_markets(markets)

    def fetch_swap_markets(self, params):
        response = self.swapV2PublicGetQuoteContracts(params)
        #
        #    {
        #        "code": 0,
        #        "msg": "",
        #        "data": [
        #            {
        #              "contractId": "100",
        #              "symbol": "BTC-USDT",
        #              "size": "0.0001",
        #              "quantityPrecision": 4,
        #              "pricePrecision": 1,
        #              "feeRate": 0.0005,
        #              "tradeMinLimit": 1,
        #              "maxLongLeverage": 150,
        #              "maxShortLeverage": 150,
        #              "currency": "USDT",
        #              "asset": "BTC",
        #              "status": 1
        #            },
        #            ...
        #        ]
        #    }
        #
        markets = self.safe_list(response, 'data', [])
        return self.parse_markets(markets)

    def parse_market(self, market) -> Market:
        id = self.safe_string(market, 'symbol')
        symbolParts = id.split('-')
        baseId = symbolParts[0]
        quoteId = symbolParts[1]
        base = self.safe_currency_code(baseId)
        quote = self.safe_currency_code(quoteId)
        currency = self.safe_string(market, 'currency')
        settle = self.safe_currency_code(currency)
        pricePrecision = self.safe_integer(market, 'pricePrecision')
        if pricePrecision is None:
            pricePrecision = self.precision_from_string(self.safe_string(market, 'tickSize'))
        quantityPrecision = self.safe_integer(market, 'quantityPrecision')
        if quantityPrecision is None:
            quantityPrecision = self.precision_from_string(self.safe_string(market, 'stepSize'))
        type = 'swap' if (settle is not None) else 'spot'
        spot = type == 'spot'
        swap = type == 'swap'
        symbol = base + '/' + quote
        if settle is not None:
            symbol += ':' + settle
        fees = self.safe_dict(self.fees, type, {})
        contractSize = self.parse_number('1') if (swap) else None
        isActive = self.safe_string(market, 'status') == '1'
        isInverse = None if (spot) else False
        isLinear = None if (spot) else swap
        return self.safe_market_structure({
            'id': id,
            'symbol': symbol,
            'base': base,
            'quote': quote,
            'settle': settle,
            'baseId': baseId,
            'quoteId': quoteId,
            'settleId': currency,
            'type': type,
            'spot': spot,
            'margin': False,
            'swap': swap,
            'future': False,
            'option': False,
            'active': isActive,
            'contract': swap,
            'linear': isLinear,
            'inverse': isInverse,
            'taker': self.safe_number(fees, 'taker'),
            'maker': self.safe_number(fees, 'maker'),
            'feeSide': self.safe_string(fees, 'feeSide'),
            'contractSize': contractSize,
            'expiry': None,
            'expiryDatetime': None,
            'strike': None,
            'optionType': None,
            'precision': {
                'amount': quantityPrecision,
                'price': pricePrecision,
            },
            'limits': {
                'leverage': {
                    'min': None,
                    'max': self.safe_integer(market, 'maxLongLeverage'),
                },
                'amount': {
                    'min': self.safe_number_2(market, 'minQty', 'tradeMinQuantity'),
                    'max': self.safe_number(market, 'maxQty'),
                },
                'price': {
                    'min': None,
                    'max': None,
                },
                'cost': {
                    'min': self.safe_number_2(market, 'minNotional', 'tradeMinUSDT'),
                    'max': self.safe_number(market, 'maxNotional'),
                },
            },
            'created': None,
            'info': market,
        })

    def fetch_markets(self, params={}) -> List[Market]:
        """
        retrieves data on all markets for bingx
        :see: https://bingx-api.github.io/docs/#/spot/market-api.html#Query%20Symbols
        :see: https://bingx-api.github.io/docs/#/swapV2/market-api.html#Contract%20Information
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict[]: an array of objects representing market data
        """
        requests = [self.fetch_swap_markets(params)]
        isSandbox = self.safe_bool(self.options, 'sandboxMode', False)
        if not isSandbox:
            requests.append(self.fetch_spot_markets(params))  # sandbox is swap only
        promises = requests
        spotMarkets = self.safe_list(promises, 0, [])
        swapMarkets = self.safe_list(promises, 1, [])
        return self.array_concat(spotMarkets, swapMarkets)

    def fetch_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}) -> List[list]:
        """
        fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
        :see: https://bingx-api.github.io/docs/#/swapV2/market-api.html#K-Line%20Data
        :see: https://bingx-api.github.io/docs/#/spot/market-api.html#Candlestick%20chart%20data
        :see: https://bingx-api.github.io/docs/#/swapV2/market-api.html#%20K-Line%20Data
        :see: https://bingx-api.github.io/docs/#/en-us/swapV2/market-api.html#K-Line%20Data%20-%20Mark%20Price
        :param str symbol: unified symbol of the market to fetch OHLCV data for
        :param str timeframe: the length of time each candle represents
        :param int [since]: timestamp in ms of the earliest candle to fetch
        :param int [limit]: the maximum amount of candles to fetch
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :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 [availble 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, 1440)
        market = self.market(symbol)
        request: dict = {
            'symbol': market['id'],
        }
        request['interval'] = self.safe_string(self.timeframes, timeframe, timeframe)
        if since is not None:
            request['startTime'] = since
        if limit is not None:
            request['limit'] = limit
        until = self.safe_integer_2(params, 'until', 'endTime')
        if until is not None:
            params = self.omit(params, ['until'])
            request['endTime'] = until
        response = None
        if market['spot']:
            response = self.spotV1PublicGetMarketKline(self.extend(request, params))
        else:
            price = self.safe_string(params, 'price')
            params = self.omit(params, 'price')
            if price == 'mark':
                response = self.swapV1PrivateGetMarketMarkPriceKlines(self.extend(request, params))
            else:
                response = self.swapV3PublicGetQuoteKlines(self.extend(request, params))
        #
        #    {
        #        "code": 0,
        #        "msg": "",
        #        "data": [
        #          {
        #            "open": "19396.8",
        #            "close": "19394.4",
        #            "high": "19397.5",
        #            "low": "19385.7",
        #            "volume": "110.05",
        #            "time": 1666583700000
        #          },
        #          ...
        #        ]
        #    }
        #
        # fetchMarkOHLCV
        #
        #    {
        #        "code": 0,
        #        "msg": "",
        #        "data": [
        #            {
        #                "open": "42191.7",
        #                "close": "42189.5",
        #                "high": "42196.5",
        #                "low": "42189.5",
        #                "volume": "0.00",
        #                "openTime": 1706508840000,
        #                "closeTime": 1706508840000
        #            }
        #        ]
        #    }
        #
        ohlcvs = self.safe_value(response, 'data', [])
        if not isinstance(ohlcvs, list):
            ohlcvs = [ohlcvs]
        return self.parse_ohlcvs(ohlcvs, market, timeframe, since, limit)

    def parse_ohlcv(self, ohlcv, market: Market = None) -> list:
        #
        #    {
        #        "open": "19394.4",
        #        "close": "19379.0",
        #        "high": "19394.4",
        #        "low": "19368.3",
        #        "volume": "167.44",
        #        "time": 1666584000000
        #    }
        #
        # fetchMarkOHLCV
        #
        #    {
        #        "open": "42191.7",
        #        "close": "42189.5",
        #        "high": "42196.5",
        #        "low": "42189.5",
        #        "volume": "0.00",
        #        "openTime": 1706508840000,
        #        "closeTime": 1706508840000
        #    }
        # spot
        #    [
        #        1691402580000,
        #        29093.61,
        #        29093.93,
        #        29087.73,
        #        29093.24,
        #        0.59,
        #        1691402639999,
        #        17221.07
        #    ]
        #
        if isinstance(ohlcv, list):
            return [
                self.safe_integer(ohlcv, 0),
                self.safe_number(ohlcv, 1),
                self.safe_number(ohlcv, 2),
                self.safe_number(ohlcv, 3),
                self.safe_number(ohlcv, 4),
                self.safe_number(ohlcv, 5),
            ]
        return [
            self.safe_integer_2(ohlcv, 'time', 'closeTime'),
            self.safe_number(ohlcv, 'open'),
            self.safe_number(ohlcv, 'high'),
            self.safe_number(ohlcv, 'low'),
            self.safe_number(ohlcv, 'close'),
            self.safe_number(ohlcv, 'volume'),
        ]

    def fetch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
        """
        get the list of most recent trades for a particular symbol
        :see: https://bingx-api.github.io/docs/#/spot/market-api.html#Query%20transaction%20records
        :see: https://bingx-api.github.io/docs/#/swapV2/market-api.html#The%20latest%20Trade%20of%20a%20Trading%20Pair
        :param str symbol: unified symbol of the market to fetch trades for
        :param int [since]: timestamp in ms of the earliest trade to fetch
        :param int [limit]: the maximum amount of trades to fetch
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict[]: a list of `trade structures <https://docs.ccxt.com/#/?id=public-trades>`
        """
        self.load_markets()
        market = self.market(symbol)
        request: dict = {
            'symbol': market['id'],
        }
        if limit is not None:
            request['limit'] = min(limit, 100)  # avoid API exception "limit should less than 100"
        response = None
        marketType = None
        marketType, params = self.handle_market_type_and_params('fetchTrades', market, params)
        if marketType == 'spot':
            response = self.spotV1PublicGetMarketTrades(self.extend(request, params))
        else:
            response = self.swapV2PublicGetQuoteTrades(self.extend(request, params))
        #
        # spot
        #
        #    {
        #        "code": 0,
        #        "data": [
        #            {
        #                "id": 43148253,
        #                "price": 25714.71,
        #                "qty": 1.674571,
        #                "time": 1655085975589,
        #                "buyerMaker": False
        #            }
        #        ]
        #    }
        #
        # swap
        #
        #    {
        #      "code":0,
        #      "msg":"",
        #      "data":[
        #        {
        #          "time": 1672025549368,
        #          "isBuyerMaker": True,
        #          "price": "16885.0",
        #          "qty": "3.3002",
        #          "quoteQty": "55723.87"
        #        },
        #        ...
        #      ]
        #    }
        #
        trades = self.safe_list(response, 'data', [])
        return self.parse_trades(trades, market, since, limit)

    def parse_trade(self, trade, market: Market = None) -> Trade:
        #
        # spot
        # fetchTrades
        #
        #    {
        #        "id": 43148253,
        #        "price": 25714.71,
        #        "qty": 1.674571,
        #        "time": 1655085975589,
        #        "buyerMaker": False
        #    }
        #
        # spot
        # fetchMyTrades
        #     {
        #         "symbol": "LTC-USDT",
        #         "id": 36237072,
        #         "orderId": 1674069326895775744,
        #         "price": "85.891",
        #         "qty": "0.0582",
        #         "quoteQty": "4.9988562000000005",
        #         "commission": -0.00005820000000000001,
        #         "commissionAsset": "LTC",
        #         "time": 1687964205000,
        #         "isBuyer": True,
        #         "isMaker": False
        #     }
        #
        # swap
        # fetchTrades
        #
        #    {
        #        "time": 1672025549368,
        #        "isBuyerMaker": True,
        #        "price": "16885.0",
        #        "qty": "3.3002",
        #        "quoteQty": "55723.87"
        #    }
        #
        # swap
        # fetchMyTrades
        #
        #    {
        #        "volume": "0.1",
        #        "price": "106.75",
        #        "amount": "10.6750",
        #        "commission": "-0.0053",
        #        "currency": "USDT",
        #        "orderId": "1676213270274379776",
        #        "liquidatedPrice": "0.00",
        #        "liquidatedMarginRatio": "0.00",
        #        "filledTime": "2023-07-04T20:56:01.000+0800"
        #    }
        #
        #
        # ws
        #
        # spot
        #
        #    {
        #        "E": 1690214529432,
        #        "T": 1690214529386,
        #        "e": "trade",
        #        "m": True,
        #        "p": "29110.19",
        #        "q": "0.1868",
        #        "s": "BTC-USDT",
        #        "t": "57903921"
        #    }
        #
        # swap
        #
        #    {
        #        "q": "0.0421",
        #        "p": "29023.5",
        #        "T": 1690221401344,
        #        "m": False,
        #        "s": "BTC-USDT"
        #    }
        #
        time = self.safe_integer_n(trade, ['time', 'filledTm', 'T'])
        datetimeId = self.safe_string(trade, 'filledTm')
        if datetimeId is not None:
            time = self.parse8601(datetimeId)
        if time == 0:
            time = None
        cost = self.safe_string(trade, 'quoteQty')
        type = 'spot' if (cost is None) else 'swap'
        currencyId = self.safe_string_n(trade, ['currency', 'N', 'commissionAsset'])
        currencyCode = self.safe_currency_code(currencyId)
        m = self.safe_bool(trade, 'm')
        marketId = self.safe_string(trade, 's')
        isBuyerMaker = self.safe_bool_2(trade, 'buyerMaker', 'isBuyerMaker')
        takeOrMaker = None
        if (isBuyerMaker is not None) or (m is not None):
            takeOrMaker = 'maker' if (isBuyerMaker or m) else 'taker'
        side = self.safe_string_lower_2(trade, 'side', 'S')
        if side is None:
            if (isBuyerMaker is not None) or (m is not None):
                side = 'sell' if (isBuyerMaker or m) else 'buy'
                takeOrMaker = 'taker'
        isBuyer = self.safe_bool(trade, 'isBuyer')
        if isBuyer is not None:
            side = 'buy' if isBuyer else 'sell'
        isMaker = self.safe_bool(trade, 'isMaker')
        if isMaker is not None:
            takeOrMaker = 'maker' if isMaker else 'taker'
        amount = self.safe_string_n(trade, ['qty', 'amount', 'q'])
        if (market is not None) and market['swap'] and ('volume' in trade):
            # private trade returns num of contracts instead of base currency(as the order-related methods do)
            contractSize = self.safe_string(market['info'], 'tradeMinQuantity')
            volume = self.safe_string(trade, 'volume')
            amount = Precise.string_mul(volume, contractSize)
        return self.safe_trade({
            'id': self.safe_string_n(trade, ['id', 't']),
            'info': trade,
            'timestamp': time,
            'datetime': self.iso8601(time),
            'symbol': self.safe_symbol(marketId, market, '-', type),
            'order': self.safe_string_2(trade, 'orderId', 'i'),
            'type': self.safe_string_lower(trade, 'o'),
            'side': self.parse_order_side(side),
            'takerOrMaker': takeOrMaker,
            'price': self.safe_string_2(trade, 'price', 'p'),
            'amount': amount,
            'cost': cost,
            'fee': {
                'cost': self.parse_number(Precise.string_abs(self.safe_string_2(trade, 'commission', 'n'))),
                'currency': currencyCode,
                'rate': None,
            },
        }, market)

    def fetch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook:
        """
        fetches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
        :see: https://bingx-api.github.io/docs/#/spot/market-api.html#Query%20depth%20information
        :see: https://bingx-api.github.io/docs/#/swapV2/market-api.html#Get%20Market%20Depth
        :param str symbol: unified symbol of the market to fetch the order book for
        :param int [limit]: the maximum amount of order book entries to return
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: A dictionary of `order book structures <https://docs.ccxt.com/#/?id=order-book-structure>` indexed by market symbols
        """
        self.load_markets()
        market = self.market(symbol)
        request: dict = {
            'symbol': market['id'],
        }
        if limit is not None:
            request['limit'] = limit
        response = None
        marketType = None
        marketType, params = self.handle_market_type_and_params('fetchOrderBook', market, params)
        if marketType == 'spot':
            response = self.spotV1PublicGetMarketDepth(self.extend(request, params))
        else:
            response = self.swapV2PublicGetQuoteDepth(self.extend(request, params))
        #
        # spot
        #
        #     {
        #         "code": 0,
        #         "data": {
        #           "bids": [
        #             [
        #               "26324.73",
        #               "0.37655"
        #             ],
        #             [
        #               "26324.71",
        #               "0.31888"
        #             ],
        #         ],
        #         "asks": [
        #             [
        #               "26340.30",
        #               "6.45221"
        #             ],
        #             [
        #               "26340.15",
        #               "6.73261"
        #             ],
        #         ]}
        #     }
        #
        # swap
        #
        #     {
        #         "code": 0,
        #         "msg": "",
        #         "data": {
        #           "T": 1683914263304,
        #           "bids": [
        #             [
        #               "26300.90000000",
        #               "30408.00000000"
        #             ],
        #             [
        #               "26300.80000000",
        #               "50906.00000000"
        #             ],
        #         ],
        #         "asks": [
        #             [
        #               "26301.00000000",
        #               "43616.00000000"
        #             ],
        #             [
        #               "26301.10000000",
        #               "49402.00000000"
        #             ],
        #         ]}
        #     }
        #
        orderbook = self.safe_dict(response, 'data', {})
        timestamp = self.safe_integer_2(orderbook, 'T', 'ts')
        return self.parse_order_book(orderbook, market['symbol'], timestamp, 'bids', 'asks', 0, 1)

    def fetch_funding_rate(self, symbol: str, params={}):
        """
        fetch the current funding rate
        :see: https://bingx-api.github.io/docs/#/swapV2/market-api.html#Current%20Funding%20Rate
        :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>`
        """
        self.load_markets()
        market = self.market(symbol)
        request: dict = {
            'symbol': market['id'],
        }
        response = self.swapV2PublicGetQuotePremiumIndex(self.extend(request, params))
        #
        #    {
        #        "code":0,
        #        "msg":"",
        #        "data":[
        #          {
        #            "symbol": "BTC-USDT",
        #            "markPrice": "16884.5",
        #            "indexPrice": "16886.9",
        #            "lastFundingRate": "0.0001",
        #            "nextFundingTime": 1672041600000
        #          },
        #          ...
        #        ]
        #    }
        #
        data = self.safe_list(response, 'data', [])
        return self.parse_funding_rate(data, market)

    def fetch_funding_rates(self, symbols: Strings = None, params={}):
        """
        fetch the current funding rate
        :see: https://bingx-api.github.io/docs/#/swapV2/market-api.html#Current%20Funding%20Rate
        :param str[] [symbols]: list of unified market symbols
        :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>`
        """
        self.load_markets()
        symbols = self.market_symbols(symbols, 'swap', True)
        response = self.swapV2PublicGetQuotePremiumIndex(self.extend(params))
        data = self.safe_list(response, 'data', [])
        filteredResponse = []
        for i in range(0, len(data)):
            item = data[i]
            marketId = self.safe_string(item, 'symbol')
            market = self.safe_market(marketId, None, None, 'swap')
            if (symbols is None) or self.in_array(market['symbol'], symbols):
                filteredResponse.append(self.parse_funding_rate(item, market))
        return filteredResponse

    def parse_funding_rate(self, contract, market: Market = None):
        #
        #     {
        #         "symbol": "BTC-USDT",
        #         "markPrice": "16884.5",
        #         "indexPrice": "16886.9",
        #         "lastFundingRate": "0.0001",
        #         "nextFundingTime": 1672041600000
        #     }
        #
        marketId = self.safe_string(contract, 'symbol')
        nextFundingTimestamp = self.safe_integer(contract, 'nextFundingTime')
        return {
            'info': contract,
            'symbol': self.safe_symbol(marketId, market, '-', 'swap'),
            'markPrice': self.safe_number(contract, 'markPrice'),
            'indexPrice': self.safe_number(contract, 'indexPrice'),
            'interestRate': None,
            'estimatedSettlePrice': None,
            'timestamp': None,
            'datetime': None,
            'fundingRate': self.safe_number(contract, 'lastFundingRate'),
            'fundingTimestamp': None,
            'fundingDatetime': None,
            'nextFundingRate': None,
            'nextFundingTimestamp': nextFundingTimestamp,
            'nextFundingDatetime': self.iso8601(nextFundingTimestamp),
            'previousFundingRate': None,
            'previousFundingTimestamp': None,
            'previousFundingDatetime': None,
        }

    def fetch_funding_rate_history(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
        """
        fetches historical funding rate prices
        :see: https://bingx-api.github.io/docs/#/swapV2/market-api.html#Funding%20Rate%20History
        :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 <https://docs.ccxt.com/#/?id=funding-rate-history-structure>` to fetch
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :param int [params.until]: timestamp in ms of the latest funding rate 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 [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
        :returns dict[]: a list of `funding rate structures <https://docs.ccxt.com/#/?id=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_deterministic('fetchFundingRateHistory', symbol, since, limit, '8h', params)
        market = self.market(symbol)
        request: dict = {
            'symbol': market['id'],
        }
        if since is not None:
            request['startTime'] = since
        if limit is not None:
            request['limit'] = limit
        until = self.safe_integer_2(params, 'until', 'startTime')
        if until is not None:
            params = self.omit(params, ['until'])
            request['startTime'] = until
        response = self.swapV2PublicGetQuoteFundingRate(self.extend(request, params))
        #
        #    {
        #        "code":0,
        #        "msg":"",
        #        "data":[
        #          {
        #            "symbol": "BTC-USDT",
        #            "fundingRate": "0.0001",
        #            "fundingTime": 1585684800000
        #          },
        #          ...
        #        ]
        #    }
        #
        data = self.safe_list(response, 'data', [])
        rates = []
        for i in range(0, len(data)):
            entry = data[i]
            marketId = self.safe_string(entry, 'symbol')
            symbolInner = self.safe_symbol(marketId, market, '-', 'swap')
            timestamp = self.safe_integer(entry, 'fundingTime')
            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_open_interest(self, symbol: str, params={}):
        """
        Retrieves the open interest of a currency
        :see: https://bingx-api.github.io/docs/#/swapV2/market-api.html#Get%20Swap%20Open%20Positions
        :param str symbol: Unified CCXT market symbol
        :param dict [params]: exchange specific parameters
        :returns dict} an open interest structure{@link https://docs.ccxt.com/#/?id=open-interest-structure:
        """
        self.load_markets()
        market = self.market(symbol)
        request: dict = {
            'symbol': market['id'],
        }
        response = self.swapV2PublicGetQuoteOpenInterest(self.extend(request, params))
        #
        #     {
        #         "code": 0,
        #         "msg": "",
        #         "data": {
        #           "openInterest": "3289641547.10",
        #           "symbol": "BTC-USDT",
        #           "time": 1672026617364
        #         }
        #     }
        #
        data = self.safe_dict(response, 'data', {})
        return self.parse_open_interest(data, market)

    def parse_open_interest(self, interest, market: Market = None):
        #
        #    {
        #        "openInterest": "3289641547.10",
        #        "symbol": "BTC-USDT",
        #        "time": 1672026617364
        #    }
        #
        timestamp = self.safe_integer(interest, 'time')
        id = self.safe_string(interest, 'symbol')
        symbol = self.safe_symbol(id, market, '-', 'swap')
        openInterest = self.safe_number(interest, 'openInterest')
        return self.safe_open_interest({
            'symbol': symbol,
            'baseVolume': None,
            'quoteVolume': None,  # deprecated
            'openInterestAmount': None,
            'openInterestValue': openInterest,
            'timestamp': timestamp,
            'datetime': self.iso8601(timestamp),
            'info': interest,
        }, market)

    def fetch_ticker(self, symbol: str, params={}) -> Ticker:
        """
        fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
        :see: https://bingx-api.github.io/docs/#/swapV2/market-api.html#Get%20Ticker
        :see: https://bingx-api.github.io/docs/#/spot/market-api.html#24%E5%B0%8F%E6%97%B6%E4%BB%B7%E6%A0%BC%E5%8F%98%E5%8A%A8%E6%83%85%E5%86%B5
        :param str symbol: unified symbol of the market to fetch the ticker for
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
        """
        self.load_markets()
        market = self.market(symbol)
        request: dict = {
            'symbol': market['id'],
        }
        response = None
        if market['spot']:
            response = self.spotV1PublicGetTicker24hr(self.extend(request, params))
        else:
            response = self.swapV2PublicGetQuoteTicker(self.extend(request, params))
        data = self.safe_list(response, 'data')
        if data is not None:
            first = self.safe_dict(data, 0, {})
            return self.parse_ticker(first, market)
        dataDict = self.safe_dict(response, 'data', {})
        return self.parse_ticker(dataDict, market)

    def fetch_tickers(self, symbols: Strings = None, params={}) -> Tickers:
        """
        fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market
        :see: https://bingx-api.github.io/docs/#/swapV2/market-api.html#Get%20Ticker
        :param str[]|None symbols: unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: a dictionary of `ticker structures <https://docs.ccxt.com/#/?id=ticker-structure>`
        """
        self.load_markets()
        market = None
        if symbols is not None:
            symbols = self.market_symbols(symbols)
            firstSymbol = self.safe_string(symbols, 0)
            if firstSymbol is not None:
                market = self.market(firstSymbol)
        type = None
        type, params = self.handle_market_type_and_params('fetchTickers', market, params)
        response = None
        if type == 'spot':
            response = self.spotV1PublicGetTicker24hr(params)
        else:
            response = self.swapV2PublicGetQuoteTicker(params)
        tickers = self.safe_list(response, 'data')
        return self.parse_tickers(tickers, symbols)

    def parse_ticker(self, ticker: dict, market: Market = None) -> Ticker:
        #
        # spot
        #    {
        #        "symbol": "BTC-USDT",
        #        "openPrice": "26032.08",
        #        "highPrice": "26178.86",
        #        "lowPrice": "25968.18",
        #        "lastPrice": "26113.60",
        #        "volume": "1161.79",
        #        "quoteVolume": "30288466.44",
        #        "openTime": "1693081020762",
        #        "closeTime": "1693167420762",
        #  added 2023-11-10:
        #        "bidPrice": 16726.0,
        #        "bidQty": 0.05,
        #        "askPrice": 16726.0,
        #        "askQty": 0.05,
        #    }
        # swap
        #
        #    {
        #        "symbol": "BTC-USDT",
        #        "priceChange": "52.5",
        #        "priceChangePercent": "0.31%",  # they started to add the percent sign in value
        #        "lastPrice": "16880.5",
        #        "lastQty": "2.2238",          # only present in swap!
        #        "highPrice": "16897.5",
        #        "lowPrice": "16726.0",
        #        "volume": "245870.1692",
        #        "quoteVolume": "4151395117.73",
        #        "openPrice": "16832.0",
        #        "openTime": 1672026667803,
        #        "closeTime": 1672026648425,
        #  added 2023-11-10:
        #        "bidPrice": 16726.0,
        #        "bidQty": 0.05,
        #        "askPrice": 16726.0,
        #        "askQty": 0.05,
        #    }
        #
        marketId = self.safe_string(ticker, 'symbol')
        lastQty = self.safe_string(ticker, 'lastQty')
        # in spot markets, lastQty is not present
        # it's(bad, but) the only way we can check the tickers origin
        type = 'spot' if (lastQty is None) else 'swap'
        market = self.safe_market(marketId, market, None, type)
        symbol = market['symbol']
        open = self.safe_string(ticker, 'openPrice')
        high = self.safe_string(ticker, 'highPrice')
        low = self.safe_string(ticker, 'lowPrice')
        close = self.safe_string(ticker, 'lastPrice')
        quoteVolume = self.safe_string(ticker, 'quoteVolume')
        baseVolume = self.safe_string(ticker, 'volume')
        percentage = self.safe_string(ticker, 'priceChangePercent')
        if percentage is not None:
            percentage = percentage.replace('%', '')
        change = self.safe_string(ticker, 'priceChange')
        ts = self.safe_integer(ticker, 'closeTime')
        datetime = self.iso8601(ts)
        bid = self.safe_string(ticker, 'bidPrice')
        bidVolume = self.safe_string(ticker, 'bidQty')
        ask = self.safe_string(ticker, 'askPrice')
        askVolume = self.safe_string(ticker, 'askQty')
        return self.safe_ticker({
            'symbol': symbol,
            'timestamp': ts,
            'datetime': datetime,
            'high': high,
            'low': low,
            'bid': bid,
            'bidVolume': bidVolume,
            'ask': ask,
            'askVolume': askVolume,
            'vwap': None,
            'open': open,
            'close': close,
            'last': None,
            'previousClose': None,
            'change': change,
            'percentage': percentage,
            'average': None,
            'baseVolume': baseVolume,
            'quoteVolume': quoteVolume,
            'info': ticker,
        }, market)

    def fetch_balance(self, params={}) -> Balances:
        """
        query for balance and get the amount of funds available for trading or funds locked in orders
        :see: https://bingx-api.github.io/docs/#/spot/trade-api.html#Query%20Assets
        :see: https://bingx-api.github.io/docs/#/swapV2/account-api.html#Get%20Perpetual%20Swap%20Account%20Asset%20Information
        :see: https://bingx-api.github.io/docs/#/standard/contract-interface.html#Query%20standard%20contract%20balance
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :param boolean [params.standard]: whether to fetch standard contract balances
        :returns dict: a `balance structure <https://docs.ccxt.com/#/?id=balance-structure>`
        """
        self.load_markets()
        response = None
        standard = None
        standard, params = self.handle_option_and_params(params, 'fetchBalance', 'standard', False)
        marketType, marketTypeQuery = self.handle_market_type_and_params('fetchBalance', None, params)
        if standard:
            response = self.contractV1PrivateGetBalance(marketTypeQuery)
        elif marketType == 'spot':
            response = self.spotV1PrivateGetAccountBalance(marketTypeQuery)
        else:
            response = self.swapV2PrivateGetUserBalance(marketTypeQuery)
        #
        # spot
        #
        #    {
        #        "code": 0,
        #        "msg": "",
        #        "ttl": 1,
        #        "data": {
        #            "balances": [
        #                {
        #                    "asset": "USDT",
        #                    "free": "16.73971130673954",
        #                    "locked": "0"
        #                }
        #            ]
        #        }
        #    }
        #
        # swap
        #
        #    {
        #        "code": 0,
        #        "msg": "",
        #        "data": {
        #          "balance": {
        #            "asset": "USDT",
        #            "balance": "15.6128",
        #            "equity": "15.6128",
        #            "unrealizedProfit": "0.0000",
        #            "realisedProfit": "0.0000",
        #            "availableMargin": "15.6128",
        #            "usedMargin": "0.0000",
        #            "freezedMargin": "0.0000"
        #          }
        #        }
        #    }
        # standard futures
        #    {
        #        "code":"0",
        #        "timestamp":"1691148990942",
        #        "data":[
        #           {
        #              "asset":"VST",
        #              "balance":"100000.00000000000000000000",
        #              "crossWalletBalance":"100000.00000000000000000000",
        #              "crossUnPnl":"0",
        #              "availableBalance":"100000.00000000000000000000",
        #              "maxWithdrawAmount":"100000.00000000000000000000",
        #              "marginAvailable":false,
        #              "updateTime":"1691148990902"
        #           },
        #           {
        #              "asset":"USDT",
        #              "balance":"0",
        #              "crossWalletBalance":"0",
        #              "crossUnPnl":"0",
        #              "availableBalance":"0",
        #              "maxWithdrawAmount":"0",
        #              "marginAvailable":false,
        #              "updateTime":"1691148990902"
        #           },
        #        ]
        #     }
        #
        return self.parse_balance(response)

    def parse_balance(self, response) -> Balances:
        data = self.safe_value(response, 'data')
        balances = self.safe_value_2(data, 'balance', 'balances', data)
        result = {'info': response}
        if isinstance(balances, list):
            for i in range(0, len(balances)):
                balance = balances[i]
                currencyId = self.safe_string(balance, 'asset')
                code = self.safe_currency_code(currencyId)
                account = self.account()
                account['free'] = self.safe_string_2(balance, 'free', 'availableBalance')
                account['used'] = self.safe_string(balance, 'locked')
                account['total'] = self.safe_string(balance, 'balance')
                result[code] = account
        else:
            currencyId = self.safe_string(balances, 'asset')
            code = self.safe_currency_code(currencyId)
            account = self.account()
            account['free'] = self.safe_string(balances, 'availableMargin')
            account['used'] = self.safe_string(balances, 'usedMargin')
            result[code] = account
        return self.safe_balance(result)

    def fetch_positions(self, symbols: Strings = None, params={}):
        """
        fetch all open positions
        :see: https://bingx-api.github.io/docs/#/swapV2/account-api.html#Perpetual%20Swap%20Positions
        :see: https://bingx-api.github.io/docs/#/standard/contract-interface.html#Query%20standard%20contract%20balance
        :param str[]|None symbols: list of unified market symbols
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :param boolean [params.standard]: whether to fetch standard contract positions
        :returns dict[]: a list of `position structure <https://docs.ccxt.com/#/?id=position-structure>`
        """
        self.load_markets()
        symbols = self.market_symbols(symbols)
        standard = None
        standard, params = self.handle_option_and_params(params, 'fetchPositions', 'standard', False)
        response = None
        if standard:
            response = self.contractV1PrivateGetAllPosition(params)
        else:
            response = self.swapV2PrivateGetUserPositions(params)
        #
        #    {
        #        "code": 0,
        #            "msg": "",
        #            "data": [
        #            {
        #                "symbol": "BTC-USDT",
        #                "positionId": "12345678",
        #                "positionSide": "LONG",
        #                "isolated": True,
        #                "positionAmt": "123.33",
        #                "availableAmt": "128.99",
        #                "unrealizedProfit": "1.22",
        #                "realisedProfit": "8.1",
        #                "initialMargin": "123.33",
        #                "avgPrice": "2.2",
        #                "leverage": 10,
        #            }
        #        ]
        #    }
        #
        positions = self.safe_list(response, 'data', [])
        return self.parse_positions(positions, symbols)

    def parse_position(self, position, market: Market = None):
        #
        #    {
        #        "positionId":"1773122376147623936",
        #        "symbol":"XRP-USDT",
        #        "currency":"USDT",
        #        "positionAmt":"3",
        #        "availableAmt":"3",
        #        "positionSide":"LONG",
        #        "isolated":false,
        #        "avgPrice":"0.6139",
        #        "initialMargin":"0.0897",
        #        "leverage":20,
        #        "unrealizedProfit":"-0.0023",
        #        "realisedProfit":"-0.0009",
        #        "liquidationPrice":0,
        #        "pnlRatio":"-0.0260",
        #        "maxMarginReduction":"",
        #        "riskRate":"",
        #        "markPrice":"",
        #        "positionValue":"",
        #        "onlyOnePosition":false
        #    }
        #
        # standard position
        #
        #     {
        #         "currentPrice": "82.91",
        #         "symbol": "LTC/USDT",
        #         "initialMargin": "5.00000000000000000000",
        #         "unrealizedProfit": "-0.26464500",
        #         "leverage": "20.000000000",
        #         "isolated": True,
        #         "entryPrice": "83.13",
        #         "positionSide": "LONG",
        #         "positionAmt": "1.20365912",
        #     }
        #
        marketId = self.safe_string(position, 'symbol', '')
        marketId = marketId.replace('/', '-')  # standard return different format
        isolated = self.safe_bool(position, 'isolated')
        marginMode = None
        if isolated is not None:
            marginMode = 'isolated' if isolated else 'cross'
        return self.safe_position({
            'info': position,
            'id': self.safe_string(position, 'positionId'),
            'symbol': self.safe_symbol(marketId, market, '-', 'swap'),
            'notional': self.safe_number(position, 'positionValue'),
            'marginMode': marginMode,
            'liquidationPrice': None,
            'entryPrice': self.safe_number_2(position, 'avgPrice', 'entryPrice'),
            'unrealizedPnl': self.safe_number(position, 'unrealizedProfit'),
            'realizedPnl': self.safe_number(position, 'realisedProfit'),
            'percentage': None,
            'contracts': self.safe_number(position, 'positionAmt'),
            'contractSize': None,
            'markPrice': None,
            'lastPrice': None,
            'side': self.safe_string_lower(position, 'positionSide'),
            'hedged': None,
            'timestamp': None,
            'datetime': None,
            'lastUpdateTimestamp': None,
            'maintenanceMargin': None,
            'maintenanceMarginPercentage': None,
            'collateral': None,
            'initialMargin': self.safe_number(position, 'initialMargin'),
            'initialMarginPercentage': None,
            'leverage': self.safe_number(position, 'leverage'),
            'marginRatio': None,
            'stopLossPrice': None,
            'takeProfitPrice': None,
        })

    def create_market_order_with_cost(self, symbol: str, side: OrderSide, cost: float, params={}):
        """
        create a market order by providing the symbol, side and cost
        :param str symbol: unified symbol of the market to create an order in
        :param str side: 'buy' or 'sell'
        :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>`
        """
        params['quoteOrderQty'] = cost
        return self.create_order(symbol, 'market', side, cost, None, params)

    def create_market_buy_order_with_cost(self, symbol: str, cost: float, params={}):
        """
        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>`
        """
        params['quoteOrderQty'] = cost
        return self.create_order(symbol, 'market', 'buy', cost, None, params)

    def create_market_sell_order_with_cost(self, symbol: str, cost: float, params={}):
        """
        create a market sell 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>`
        """
        params['quoteOrderQty'] = cost
        return self.create_order(symbol, 'market', 'sell', cost, None, params)

    def create_order_request(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
        """
         * @ignore
        helper function to build request
        :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 at which the order is to be fullfilled, in units of the quote currency, ignored in market orders
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: request to be sent to the exchange
        """
        market = self.market(symbol)
        postOnly = None
        marketType = None
        marketType, params = self.handle_market_type_and_params('createOrder', market, params)
        type = type.upper()
        request: dict = {
            'symbol': market['id'],
            'type': type,
            'side': side.upper(),
        }
        isMarketOrder = type == 'MARKET'
        isSpot = marketType == 'spot'
        exchangeClientOrderId = 'newClientOrderId' if isSpot else 'clientOrderID'
        clientOrderId = self.safe_string_2(params, exchangeClientOrderId, 'clientOrderId')
        if clientOrderId is not None:
            request[exchangeClientOrderId] = clientOrderId
        timeInForce = self.safe_string_upper(params, 'timeInForce')
        postOnly, params = self.handle_post_only(isMarketOrder, timeInForce == 'PostOnly', params)
        if postOnly or (timeInForce == 'PostOnly'):
            request['timeInForce'] = 'PostOnly'
        elif timeInForce == 'IOC':
            request['timeInForce'] = 'IOC'
        elif timeInForce == 'GTC':
            request['timeInForce'] = 'GTC'
        triggerPrice = self.safe_string_2(params, 'stopPrice', 'triggerPrice')
        if isSpot:
            cost = self.safe_number_2(params, 'cost', 'quoteOrderQty')
            params = self.omit(params, 'cost')
            if cost is not None:
                request['quoteOrderQty'] = self.parse_to_numeric(self.cost_to_precision(symbol, cost))
            else:
                if isMarketOrder and (price is not None):
                    # keep the legacy behavior, to avoid  breaking the old spot-market-buying code
                    calculatedCost = Precise.string_mul(self.number_to_string(amount), self.number_to_string(price))
                    request['quoteOrderQty'] = self.parse_to_numeric(calculatedCost)
                else:
                    request['quantity'] = self.parse_to_numeric(self.amount_to_precision(symbol, amount))
            if not isMarketOrder:
                request['price'] = self.parse_to_numeric(self.price_to_precision(symbol, price))
            if triggerPrice is not None:
                if isMarketOrder and self.safe_string(request, 'quoteOrderQty') is None:
                    raise ArgumentsRequired(self.id + ' createOrder() requires the cost parameter(or the amount + price) for placing spot market-buy trigger orders')
                request['stopPrice'] = self.price_to_precision(symbol, triggerPrice)
                if type == 'LIMIT':
                    request['type'] = 'TRIGGER_LIMIT'
                elif type == 'MARKET':
                    request['type'] = 'TRIGGER_MARKET'
        else:
            if timeInForce == 'FOK':
                request['timeInForce'] = 'FOK'
            stopLossPrice = self.safe_string(params, 'stopLossPrice')
            takeProfitPrice = self.safe_string(params, 'takeProfitPrice')
            trailingAmount = self.safe_string(params, 'trailingAmount')
            trailingPercent = self.safe_string_2(params, 'trailingPercent', 'priceRate')
            trailingType = self.safe_string(params, 'trailingType', 'TRAILING_STOP_MARKET')
            isTriggerOrder = triggerPrice is not None
            isStopLossPriceOrder = stopLossPrice is not None
            isTakeProfitPriceOrder = takeProfitPrice is not None
            isTrailingAmountOrder = trailingAmount is not None
            isTrailingPercentOrder = trailingPercent is not None
            isTrailing = isTrailingAmountOrder or isTrailingPercentOrder
            stopLoss = self.safe_value(params, 'stopLoss')
            takeProfit = self.safe_value(params, 'takeProfit')
            isStopLoss = stopLoss is not None
            isTakeProfit = takeProfit is not None
            if ((type == 'LIMIT') or (type == 'TRIGGER_LIMIT') or (type == 'STOP') or (type == 'TAKE_PROFIT')) and not isTrailing:
                request['price'] = self.parse_to_numeric(self.price_to_precision(symbol, price))
            reduceOnly = self.safe_bool(params, 'reduceOnly', False)
            if isTriggerOrder:
                request['stopPrice'] = self.parse_to_numeric(self.price_to_precision(symbol, triggerPrice))
                if isMarketOrder or (type == 'TRIGGER_MARKET'):
                    request['type'] = 'TRIGGER_MARKET'
                elif (type == 'LIMIT') or (type == 'TRIGGER_LIMIT'):
                    request['type'] = 'TRIGGER_LIMIT'
            elif isStopLossPriceOrder or isTakeProfitPriceOrder:
                # This can be used to set the stop loss and take profit, but the position needs to be opened first
                reduceOnly = True
                if isStopLossPriceOrder:
                    request['stopPrice'] = self.parse_to_numeric(self.price_to_precision(symbol, stopLossPrice))
                    if isMarketOrder or (type == 'STOP_MARKET'):
                        request['type'] = 'STOP_MARKET'
                    elif (type == 'LIMIT') or (type == 'STOP'):
                        request['type'] = 'STOP'
                elif isTakeProfitPriceOrder:
                    request['stopPrice'] = self.parse_to_numeric(self.price_to_precision(symbol, takeProfitPrice))
                    if isMarketOrder or (type == 'TAKE_PROFIT_MARKET'):
                        request['type'] = 'TAKE_PROFIT_MARKET'
                    elif (type == 'LIMIT') or (type == 'TAKE_PROFIT'):
                        request['type'] = 'TAKE_PROFIT'
            elif isTrailing:
                request['type'] = trailingType
                if isTrailingAmountOrder:
                    request['price'] = self.parse_to_numeric(trailingAmount)
                elif isTrailingPercentOrder:
                    requestTrailingPercent = Precise.string_div(trailingPercent, '100')
                    request['priceRate'] = self.parse_to_numeric(requestTrailingPercent)
            if isStopLoss or isTakeProfit:
                stringifiedAmount = self.number_to_string(amount)
                if isStopLoss:
                    slTriggerPrice = self.safe_string_2(stopLoss, 'triggerPrice', 'stopPrice', stopLoss)
                    slWorkingType = self.safe_string(stopLoss, 'workingType', 'MARK_PRICE')
                    slType = self.safe_string(stopLoss, 'type', 'STOP_MARKET')
                    slRequest: dict = {
                        'stopPrice': self.parse_to_numeric(self.price_to_precision(symbol, slTriggerPrice)),
                        'workingType': slWorkingType,
                        'type': slType,
                    }
                    slPrice = self.safe_string(stopLoss, 'price')
                    if slPrice is not None:
                        slRequest['price'] = self.parse_to_numeric(self.price_to_precision(symbol, slPrice))
                    slQuantity = self.safe_string(stopLoss, 'quantity', stringifiedAmount)
                    slRequest['quantity'] = self.parse_to_numeric(self.amount_to_precision(symbol, slQuantity))
                    request['stopLoss'] = self.json(slRequest)
                if isTakeProfit:
                    tkTriggerPrice = self.safe_string_2(takeProfit, 'triggerPrice', 'stopPrice', takeProfit)
                    tkWorkingType = self.safe_string(takeProfit, 'workingType', 'MARK_PRICE')
                    tpType = self.safe_string(takeProfit, 'type', 'TAKE_PROFIT_MARKET')
                    tpRequest: dict = {
                        'stopPrice': self.parse_to_numeric(self.price_to_precision(symbol, tkTriggerPrice)),
                        'workingType': tkWorkingType,
                        'type': tpType,
                    }
                    slPrice = self.safe_string(takeProfit, 'price')
                    if slPrice is not None:
                        tpRequest['price'] = self.parse_to_numeric(self.price_to_precision(symbol, slPrice))
                    tkQuantity = self.safe_string(takeProfit, 'quantity', stringifiedAmount)
                    tpRequest['quantity'] = self.parse_to_numeric(self.amount_to_precision(symbol, tkQuantity))
                    request['takeProfit'] = self.json(tpRequest)
            positionSide = None
            if reduceOnly:
                positionSide = 'SHORT' if (side == 'buy') else 'LONG'
            else:
                positionSide = 'LONG' if (side == 'buy') else 'SHORT'
            request['positionSide'] = positionSide
            request['quantity'] = self.parse_to_numeric(self.amount_to_precision(symbol, amount))
            params = self.omit(params, ['reduceOnly', 'triggerPrice', 'stopLossPrice', 'takeProfitPrice', 'trailingAmount', 'trailingPercent', 'trailingType', 'takeProfit', 'stopLoss', 'clientOrderId'])
        return self.extend(request, params)

    def create_order(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
        """
        create a trade order
        :see: https://bingx-api.github.io/docs/#/en-us/swapV2/trade-api.html#Trade%20order
        :see: https://bingx-api.github.io/docs/#/en-us/spot/trade-api.html#Create%20an%20Order
        :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 at which the order is to be fullfilled, in units of the quote currency, ignored in market orders
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :param str [params.clientOrderId]: a unique id for the order
        :param bool [params.postOnly]: True to place a post only order
        :param str [params.timeInForce]: spot supports 'PO', 'GTC' and 'IOC', swap supports 'PO', 'GTC', 'IOC' and 'FOK'
        :param bool [params.reduceOnly]: *swap only* True or False whether the order is reduce only
        :param float [params.triggerPrice]: *swap only* triggerPrice at which the attached take profit / stop loss order will be triggered
        :param float [params.stopLossPrice]: *swap only* stop loss trigger price
        :param float [params.takeProfitPrice]: *swap only* take profit trigger price
        :param float [params.cost]: the quote quantity that can be used alternative for the amount
        :param float [params.trailingAmount]: *swap only* the quote amount to trail away from the current market price
        :param float [params.trailingPercent]: *swap only* the percent to trail away from the current market price
        :param dict [params.takeProfit]: *takeProfit object in params* containing the triggerPrice at which the attached take profit order will be triggered
        :param float [params.takeProfit.triggerPrice]: take profit trigger price
        :param dict [params.stopLoss]: *stopLoss object in params* containing the triggerPrice at which the attached stop loss order will be triggered
        :param float [params.stopLoss.triggerPrice]: stop loss trigger price
        :param boolean [params.test]: *swap only* whether to use the test endpoint or not, default is False
        :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
        """
        self.load_markets()
        market = self.market(symbol)
        test = self.safe_bool(params, 'test', False)
        params = self.omit(params, 'test')
        request = self.create_order_request(symbol, type, side, amount, price, params)
        response = None
        if market['swap']:
            if test:
                response = self.swapV2PrivatePostTradeOrderTest(request)
            else:
                response = self.swapV2PrivatePostTradeOrder(request)
        else:
            response = self.spotV1PrivatePostTradeOrder(request)
        #
        # spot
        #
        #    {
        #        "code": 0,
        #        "msg": "",
        #        "data": {
        #            "symbol": "XRP-USDT",
        #            "orderId": 1514090846268424192,
        #            "transactTime": 1649822362855,
        #            "price": "0.5",
        #            "origQty": "10",
        #            "executedQty": "0",
        #            "cummulativeQuoteQty": "0",
        #            "status": "PENDING",
        #            "type": "LIMIT",
        #            "side": "BUY"
        #        }
        #    }
        #
        # swap
        #
        #     {
        #         "code": 0,
        #         "msg": "",
        #         "data": {
        #             "order": {
        #                 "symbol": "BTC-USDT",
        #                 "orderId": 1709036527545438208,
        #                 "side": "BUY",
        #                 "positionSide": "LONG",
        #                 "type": "TRIGGER_LIMIT",
        #                 "clientOrderID": "",
        #                 "workingType": ""
        #             }
        #         }
        #     }
        #
        if isinstance(response, str):
            # broken api engine : order-ids are too long numbers(i.e. 1742930526912864656)
            # and json.loadscan not handle them in JS, so we have to use .parse_json            # however, when order has an attached SL/TP, their value types need extra parsing
            response = self.fix_stringified_json_members(response)
            response = self.parse_json(response)
        data = self.safe_value(response, 'data', {})
        order = self.safe_dict(data, 'order', data)
        return self.parse_order(order, market)

    def create_orders(self, orders: List[OrderRequest], params={}):
        """
        create a list of trade orders
        :see: https://bingx-api.github.io/docs/#/spot/trade-api.html#Batch%20Placing%20Orders
        :see: https://bingx-api.github.io/docs/#/swapV2/trade-api.html#Bulk%20order
        :param Array orders: list of orders to create, each object should contain the parameters required by createOrder, namely symbol, type, side, amount, price and params
        :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()
        ordersRequests = []
        symbol = None
        for i in range(0, len(orders)):
            rawOrder = orders[i]
            marketId = self.safe_string(rawOrder, 'symbol')
            if symbol is None:
                symbol = marketId
            else:
                if symbol != marketId:
                    raise BadRequest(self.id + ' createOrders() requires all orders to have the same symbol')
            type = self.safe_string(rawOrder, 'type')
            side = self.safe_string(rawOrder, 'side')
            amount = self.safe_number(rawOrder, 'amount')
            price = self.safe_number(rawOrder, 'price')
            orderParams = self.safe_dict(rawOrder, 'params', {})
            orderRequest = self.create_order_request(marketId, type, side, amount, price, orderParams)
            ordersRequests.append(orderRequest)
        market = self.market(symbol)
        request: dict = {}
        response = None
        if market['swap']:
            request['batchOrders'] = self.json(ordersRequests)
            response = self.swapV2PrivatePostTradeBatchOrders(request)
        else:
            request['data'] = self.json(ordersRequests)
            response = self.spotV1PrivatePostTradeBatchOrders(request)
        #
        # spot
        #
        #     {
        #         "code": 0,
        #         "msg": "",
        #         "debugMsg": "",
        #         "data": {
        #             "orders": [
        #                 {
        #                     "symbol": "BTC-USDT",
        #                     "orderId": 1720661389564968960,
        #                     "transactTime": 1699072618272,
        #                     "price": "25000",
        #                     "origQty": "0.0002",
        #                     "executedQty": "0",
        #                     "cummulativeQuoteQty": "0",
        #                     "status": "PENDING",
        #                     "type": "LIMIT",
        #                     "side": "BUY"
        #                 },
        #             ]
        #         }
        #     }
        #
        # swap
        #
        #     {
        #         "code": 0,
        #         "msg": "",
        #         "data": {
        #             "orders": [
        #                 {
        #                     "symbol": "BTC-USDT",
        #                     "orderId": 1720657081994006528,
        #                     "side": "BUY",
        #                     "positionSide": "LONG",
        #                     "type": "LIMIT",
        #                     "clientOrderID": "",
        #                     "workingType": ""
        #                 },
        #             ]
        #         }
        #     }
        #
        data = self.safe_dict(response, 'data', {})
        result = self.safe_list(data, 'orders', [])
        return self.parse_orders(result, market)

    def parse_order_side(self, side):
        sides = {
            'BUY': 'buy',
            'SELL': 'sell',
            'SHORT': 'sell',
            'LONG': 'buy',
            'ask': 'sell',
            'bid': 'buy',
        }
        return self.safe_string(sides, side, side)

    def parse_order_type(self, type):
        types = {
            'trigger_market': 'market',
            'trigger_limit': 'limit',
        }
        return self.safe_string(types, type, type)

    def parse_order(self, order, market: Market = None) -> Order:
        #
        # spot
        # createOrder, createOrders, cancelOrder
        #
        #    {
        #        "symbol": "XRP-USDT",
        #        "orderId": 1514090846268424192,
        #        "transactTime": 1649822362855,
        #        "price": "0.5",
        #        "origQty": "10",
        #        "executedQty": "0",
        #        "cummulativeQuoteQty": "0",
        #        "status": "PENDING",
        #        "type": "LIMIT",
        #        "side": "BUY"
        #    }
        #
        # fetchOrder
        #
        #    {
        #        "symbol": "ETH-USDT",
        #        "orderId": "1660602123001266176",
        #        "price": "1700",
        #        "origQty": "0.003",
        #        "executedQty": "0",
        #        "cummulativeQuoteQty": "0",
        #        "status": "PENDING",
        #        "type": "LIMIT",
        #        "side": "BUY",
        #        "time": "1684753373276",
        #        "updateTime": "1684753373276",
        #        "origQuoteOrderQty": "0",
        #        "fee": "0",
        #        "feeAsset": "ETH"
        #    }
        #
        # fetchOpenOrders, fetchClosedOrders
        #
        #   {
        #       "symbol": "XRP-USDT",
        #       "orderId": 1514073325788200960,
        #       "price": "0.5",
        #       "StopPrice": "0",
        #       "origQty": "20",
        #       "executedQty": "10",
        #       "cummulativeQuoteQty": "5",
        #       "status": "PENDING",
        #       "type": "LIMIT",
        #       "side": "BUY",
        #       "time": 1649818185647,
        #       "updateTime": 1649818185647,
        #       "origQuoteOrderQty": "0"
        #       "fee": "-0.01"
        #   }
        #
        #
        # swap
        # createOrder, createOrders
        #
        #    {
        #      "symbol": "BTC-USDT",
        #      "orderId": 1590973236294713344,
        #      "side": "BUY",
        #      "positionSide": "LONG",
        #      "type": "LIMIT"
        #    }
        #
        # fetchOrder, fetchOpenOrders, fetchClosedOrders
        #
        #     {
        #         "symbol": "BTC-USDT",
        #         "orderId": 1709036527545438208,
        #         "side": "BUY",
        #         "positionSide": "LONG",
        #         "type": "TRIGGER_LIMIT",
        #         "origQty": "0.0010",
        #         "price": "22000.0",
        #         "executedQty": "0.0000",
        #         "avgPrice": "0.0",
        #         "cumQuote": "",
        #         "stopPrice": "23000.0",
        #         "profit": "",
        #         "commission": "",
        #         "status": "NEW",
        #         "time": 1696301035187,
        #         "updateTime": 1696301035187,
        #         "clientOrderId": "",
        #         "leverage": "",
        #         "takeProfit": "",
        #         "stopLoss": "",
        #         "advanceAttr": 0,
        #         "positionID": 0,
        #         "takeProfitEntrustPrice": 0,
        #         "stopLossEntrustPrice": 0,
        #         "orderType": "",
        #         "workingType": "MARK_PRICE"
        #     }
        # with tp and sl
        #    {
        #        orderId: 1741440894764281900,
        #        symbol: 'LTC-USDT',
        #        positionSide: 'LONG',
        #        side: 'BUY',
        #        type: 'MARKET',
        #        price: 0,
        #        quantity: 1,
        #        stopPrice: 0,
        #        workingType: 'MARK_PRICE',
        #        clientOrderID: '',
        #        timeInForce: 'GTC',
        #        priceRate: 0,
        #        stopLoss: '{"stopPrice":50,"workingType":"MARK_PRICE","type":"STOP_MARKET","quantity":1}',
        #        takeProfit: '{"stopPrice":150,"workingType":"MARK_PRICE","type":"TAKE_PROFIT_MARKET","quantity":1}',
        #        reduceOnly: False
        #    }
        #
        # editOrder(swap)
        #
        #    {
        #        cancelResult: 'true',
        #        cancelMsg: '',
        #        cancelResponse: {
        #            cancelClientOrderId: '',
        #            cancelOrderId: '1755336244265705472',
        #            symbol: 'SOL-USDT',
        #            orderId: '1755336244265705472',
        #            side: 'SELL',
        #            positionSide: 'SHORT',
        #            type: 'LIMIT',
        #            origQty: '1',
        #            price: '100.000',
        #            executedQty: '0',
        #            avgPrice: '0.000',
        #            cumQuote: '0',
        #            stopPrice: '',
        #            profit: '0.0000',
        #            commission: '0.000000',
        #            status: 'PENDING',
        #            time: '1707339747860',
        #            updateTime: '1707339747860',
        #            clientOrderId: '',
        #            leverage: '20X',
        #            workingType: 'MARK_PRICE',
        #            onlyOnePosition: False,
        #            reduceOnly: False
        #        },
        #        replaceResult: 'true',
        #        replaceMsg: '',
        #        newOrderResponse: {
        #            orderId: '1755338440612995072',
        #            symbol: 'SOL-USDT',
        #            positionSide: 'SHORT',
        #            side: 'SELL',
        #            type: 'LIMIT',
        #            price: '99',
        #            quantity: '2',
        #            stopPrice: '0',
        #            workingType: 'MARK_PRICE',
        #            clientOrderID: '',
        #            timeInForce: 'GTC',
        #            priceRate: '0',
        #            stopLoss: '',
        #            takeProfit: '',
        #            reduceOnly: False
        #        }
        #    }
        #
        # editOrder(spot)
        #
        #    {
        #        cancelResult: {code: '0', msg: '', result: True},
        #        openResult: {code: '0', msg: '', result: True},
        #        orderOpenResponse: {
        #            symbol: 'SOL-USDT',
        #            orderId: '1755334007697866752',
        #            transactTime: '1707339214620',
        #            price: '99',
        #            stopPrice: '0',
        #            origQty: '0.2',
        #            executedQty: '0',
        #            cummulativeQuoteQty: '0',
        #            status: 'PENDING',
        #            type: 'LIMIT',
        #            side: 'SELL',
        #            clientOrderID: ''
        #        },
        #        orderCancelResponse: {
        #            symbol: 'SOL-USDT',
        #            orderId: '1755117055251480576',
        #            price: '100',
        #            stopPrice: '0',
        #            origQty: '0.2',
        #            executedQty: '0',
        #            cummulativeQuoteQty: '0',
        #            status: 'CANCELED',
        #            type: 'LIMIT',
        #            side: 'SELL'
        #        }
        #    }
        #
        info = order
        newOrder = self.safe_dict_2(order, 'newOrderResponse', 'orderOpenResponse')
        if newOrder is not None:
            order = newOrder
        positionSide = self.safe_string_2(order, 'positionSide', 'ps')
        marketType = 'spot' if (positionSide is None) else 'swap'
        marketId = self.safe_string_2(order, 'symbol', 's')
        if market is None:
            market = self.safe_market(marketId, None, None, marketType)
        side = self.safe_string_lower_2(order, 'side', 'S')
        timestamp = self.safe_integer_n(order, ['time', 'transactTime', 'E'])
        lastTradeTimestamp = self.safe_integer_2(order, 'updateTime', 'T')
        statusId = self.safe_string_2(order, 'status', 'X')
        feeCurrencyCode = self.safe_string_2(order, 'feeAsset', 'N')
        feeCost = self.safe_string_n(order, ['fee', 'commission', 'n'])
        if (feeCurrencyCode is None):
            if market['spot']:
                if side == 'buy':
                    feeCurrencyCode = market['base']
                else:
                    feeCurrencyCode = market['quote']
            else:
                feeCurrencyCode = market['quote']
        stopLoss = self.safe_value(order, 'stopLoss')
        stopLossPrice = None
        if (stopLoss is not None) and (stopLoss != ''):
            stopLossPrice = self.safe_number(stopLoss, 'stopLoss')
        if (stopLoss is not None) and ((not isinstance(stopLoss, numbers.Real))) and (stopLoss != ''):
            #  stopLoss: '{"stopPrice":50,"workingType":"MARK_PRICE","type":"STOP_MARKET","quantity":1}',
            if isinstance(stopLoss, str):
                stopLoss = self.parse_json(stopLoss)
            stopLossPrice = self.safe_number(stopLoss, 'stopPrice')
        takeProfit = self.safe_value(order, 'takeProfit')
        takeProfitPrice = None
        if takeProfit is not None and (takeProfit != ''):
            takeProfitPrice = self.safe_number(takeProfit, 'takeProfit')
        if (takeProfit is not None) and ((not isinstance(takeProfit, numbers.Real))) and (takeProfit != ''):
            #  takeProfit: '{"stopPrice":150,"workingType":"MARK_PRICE","type":"TAKE_PROFIT_MARKET","quantity":1}',
            if isinstance(takeProfit, str):
                takeProfit = self.parse_json(takeProfit)
            takeProfitPrice = self.safe_number(takeProfit, 'stopPrice')
        return self.safe_order({
            'info': info,
            'id': self.safe_string_2(order, 'orderId', 'i'),
            'clientOrderId': self.safe_string_n(order, ['clientOrderID', 'origClientOrderId', 'c']),
            'symbol': self.safe_symbol(marketId, market, '-', marketType),
            'timestamp': timestamp,
            'datetime': self.iso8601(timestamp),
            'lastTradeTimestamp': lastTradeTimestamp,
            'lastUpdateTimestamp': self.safe_integer(order, 'updateTime'),
            'type': self.parse_order_type(self.safe_string_lower_2(order, 'type', 'o')),
            'timeInForce': self.safe_string(order, 'timeInForce'),
            'postOnly': None,
            'side': self.parse_order_side(side),
            'price': self.safe_string_2(order, 'price', 'p'),
            'stopPrice': self.safe_number(order, 'stopPrice'),
            'triggerPrice': self.safe_number(order, 'stopPrice'),
            'stopLossPrice': stopLossPrice,
            'takeProfitPrice': takeProfitPrice,
            'average': self.safe_string_2(order, 'avgPrice', 'ap'),
            'cost': None,
            'amount': self.safe_string_n(order, ['origQty', 'q', 'quantity']),
            'filled': self.safe_string_2(order, 'executedQty', 'z'),
            'remaining': None,
            'status': self.parse_order_status(statusId),
            'fee': {
                'currency': feeCurrencyCode,
                'cost': Precise.string_abs(feeCost),
            },
            'trades': None,
            'reduceOnly': self.safe_bool(order, 'reduceOnly'),
        }, market)

    def parse_order_status(self, status):
        statuses = {
            'NEW': 'open',
            'PENDING': 'open',
            'PARTIALLY_FILLED': 'open',
            'FILLED': 'closed',
            'CANCELED': 'canceled',
            'CANCELLED': 'canceled',
            'FAILED': 'canceled',
        }
        return self.safe_string(statuses, status, status)

    def cancel_order(self, id: str, symbol: Str = None, params={}):
        """
        cancels an open order
        :see: https://bingx-api.github.io/docs/#/spot/trade-api.html#Cancel%20an%20Order
        :see: https://bingx-api.github.io/docs/#/swapV2/trade-api.html#Cancel%20an%20Order
        :param str id: order id
        :param str symbol: unified symbol of the market the order was made in
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :param str [params.clientOrderId]: a unique id for the order
        :returns dict: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
        """
        if symbol is None:
            raise ArgumentsRequired(self.id + ' cancelOrder() requires a symbol argument')
        self.load_markets()
        market = self.market(symbol)
        request: dict = {
            'symbol': market['id'],
        }
        clientOrderId = self.safe_string_2(params, 'clientOrderId', 'clientOrderID')
        params = self.omit(params, ['clientOrderId'])
        if clientOrderId is not None:
            request['clientOrderID'] = clientOrderId
        else:
            request['orderId'] = id
        response = None
        marketType, query = self.handle_market_type_and_params('cancelOrder', market, params)
        if marketType == 'spot':
            response = self.spotV1PrivatePostTradeCancel(self.extend(request, query))
        else:
            response = self.swapV2PrivateDeleteTradeOrder(self.extend(request, query))
        #
        # spot
        #
        #   {
        #       "code": 0,
        #       "msg": "",
        #       "data": {
        #           "symbol": "XRP-USDT",
        #           "orderId": 1514090846268424192,
        #           "price": "0.5",
        #           "origQty": "10",
        #           "executedQty": "0",
        #           "cummulativeQuoteQty": "0",
        #           "status": "CANCELED",
        #           "type": "LIMIT",
        #           "side": "BUY"
        #       }
        #   }
        #
        # swap
        #
        #    {
        #        "code": 0,
        #        "msg": "",
        #        "data": {
        #          "order": {
        #            "symbol": "LINK-USDT",
        #            "orderId": 1597783850786750464,
        #            "side": "BUY",
        #            "positionSide": "LONG",
        #            "type": "TRIGGER_MARKET",
        #            "origQty": "5.0",
        #            "price": "5.0000",
        #            "executedQty": "0.0",
        #            "avgPrice": "0.0000",
        #            "cumQuote": "0",
        #            "stopPrice": "5.0000",
        #            "profit": "",
        #            "commission": "",
        #            "status": "CANCELLED",
        #            "time": 1669776330000,
        #            "updateTime": 1669776330000
        #          }
        #        }
        #    }
        #
        data = self.safe_value(response, 'data')
        first = self.safe_dict(data, 'order', data)
        return self.parse_order(first, market)

    def cancel_all_orders(self, symbol: Str = None, params={}):
        """
        cancel all open orders
        :see: https://bingx-api.github.io/docs/#/en-us/spot/trade-api.html#Cancel%20orders%20by%20symbol
        :see: https://bingx-api.github.io/docs/#/swapV2/trade-api.html#Cancel%20All%20Orders
        :param str [symbol]: unified market symbol, only orders in the market of self symbol are cancelled when symbol is not None
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
        """
        if symbol is None:
            raise ArgumentsRequired(self.id + ' cancelAllOrders() requires a symbol argument')
        self.load_markets()
        market = self.market(symbol)
        request: dict = {
            'symbol': market['id'],
        }
        response = None
        if market['spot']:
            response = self.spotV1PrivatePostTradeCancelOpenOrders(self.extend(request, params))
            #
            #     {
            #         "code": 0,
            #         "msg": "",
            #         "debugMsg": "",
            #         "data": {
            #             "orders": [{
            #                 "symbol": "ADA-USDT",
            #                 "orderId": 1740659971369992192,
            #                 "transactTime": 1703840651730,
            #                 "price": 5,
            #                 "stopPrice": 0,
            #                 "origQty": 10,
            #                 "executedQty": 0,
            #                 "cummulativeQuoteQty": 0,
            #                 "status": "CANCELED",
            #                 "type": "LIMIT",
            #                 "side": "SELL"
            #             }]
            #         }
            #     }
            #
        elif market['swap']:
            response = self.swapV2PrivateDeleteTradeAllOpenOrders(self.extend(request, params))
            #
            #    {
            #        "code": 0,
            #        "msg": "",
            #        "data": {
            #          "success": [
            #            {
            #              "symbol": "LINK-USDT",
            #              "orderId": 1597783835095859200,
            #              "side": "BUY",
            #              "positionSide": "LONG",
            #              "type": "TRIGGER_LIMIT",
            #              "origQty": "5.0",
            #              "price": "9.0000",
            #              "executedQty": "0.0",
            #              "avgPrice": "0.0000",
            #              "cumQuote": "0",
            #              "stopPrice": "9.5000",
            #              "profit": "",
            #              "commission": "",
            #              "status": "NEW",
            #              "time": 1669776326000,
            #              "updateTime": 1669776326000
            #            }
            #          ],
            #          "failed": null
            #        }
            #    }
            #
        else:
            raise BadRequest(self.id + ' cancelAllOrders is only supported for spot and swap markets.')
        return response

    def cancel_orders(self, ids: List[str], symbol: Str = None, params={}):
        """
        cancel multiple orders
        :see: https://bingx-api.github.io/docs/#/swapV2/trade-api.html#Cancel%20a%20Batch%20of%20Orders
        :see: https://bingx-api.github.io/docs/#/spot/trade-api.html#Cancel%20a%20Batch%20of%20Orders
        :param str[] ids: order ids
        :param str symbol: unified market symbol, default is None
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :param str[] [params.clientOrderIds]: client order ids
        :returns dict: an list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
        """
        if symbol is None:
            raise ArgumentsRequired(self.id + ' cancelOrders() requires a symbol argument')
        self.load_markets()
        market = self.market(symbol)
        request: dict = {
            'symbol': market['id'],
        }
        clientOrderIds = self.safe_value(params, 'clientOrderIds')
        params = self.omit(params, 'clientOrderIds')
        idsToParse = ids
        areClientOrderIds = (clientOrderIds is not None)
        if areClientOrderIds:
            idsToParse = clientOrderIds
        parsedIds = []
        for i in range(0, len(idsToParse)):
            id = idsToParse[i]
            stringId = str(id)
            parsedIds.append(stringId)
        response = None
        if market['spot']:
            spotReqKey = 'clientOrderIDs' if areClientOrderIds else 'orderIds'
            request[spotReqKey] = ','.join(parsedIds)
            response = self.spotV1PrivatePostTradeCancelOrders(self.extend(request, params))
        else:
            if areClientOrderIds:
                request['clientOrderIDList'] = self.json(parsedIds)
            else:
                request['orderIdList'] = parsedIds
            response = self.swapV2PrivateDeleteTradeBatchOrders(self.extend(request, params))
        #
        #    {
        #        "code": 0,
        #        "msg": "",
        #        "data": {
        #          "success": [
        #            {
        #              "symbol": "LINK-USDT",
        #              "orderId": 1597783850786750464,
        #              "side": "BUY",
        #              "positionSide": "LONG",
        #              "type": "TRIGGER_MARKET",
        #              "origQty": "5.0",
        #              "price": "5.5710",
        #              "executedQty": "0.0",
        #              "avgPrice": "0.0000",
        #              "cumQuote": "0",
        #              "stopPrice": "5.0000",
        #              "profit": "0.0000",
        #              "commission": "0.000000",
        #              "status": "CANCELLED",
        #              "time": 1669776330000,
        #              "updateTime": 1672370837000
        #            }
        #          ],
        #          "failed": null
        #        }
        #    }
        #
        return response

    def fetch_order(self, id: str, symbol: Str = None, params={}):
        """
        fetches information on an order made by the user
        :see: https://bingx-api.github.io/docs/#/spot/trade-api.html#Query%20Orders
        :see: https://bingx-api.github.io/docs/#/swapV2/trade-api.html#Query%20Order
        :param str symbol: unified symbol of the market the order was made in
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
        """
        if symbol is None:
            raise ArgumentsRequired(self.id + ' fetchOrder() requires a symbol argument')
        self.load_markets()
        market = self.market(symbol)
        request: dict = {
            'symbol': market['id'],
            'orderId': id,
        }
        response = None
        marketType, query = self.handle_market_type_and_params('fetchOrder', market, params)
        if marketType == 'spot':
            response = self.spotV1PrivateGetTradeQuery(self.extend(request, query))
        else:
            response = self.swapV2PrivateGetTradeOrder(self.extend(request, query))
        #
        # spot
        #
        #     {
        #         "code": 0,
        #         "msg": "",
        #         "data": {
        #             "symbol": "XRP-USDT",
        #             "orderId": 1514087361158316032,
        #             "price": "0.5",
        #             "origQty": "10",
        #             "executedQty": "0",
        #             "cummulativeQuoteQty": "0",
        #             "status": "CANCELED",
        #             "type": "LIMIT",
        #             "side": "BUY",
        #             "time": 1649821532000,
        #             "updateTime": 1649821543000,
        #             "origQuoteOrderQty": "0",
        #             "fee": "0",
        #             "feeAsset": "XRP"
        #         }
        #     }
        #
        # swap
        #
        #      {
        #          "code": 0,
        #          "msg": "",
        #          "data": {
        #            "order": {
        #              "symbol": "BTC-USDT",
        #              "orderId": 1597597642269917184,
        #              "side": "SELL",
        #              "positionSide": "LONG",
        #              "type": "TAKE_PROFIT_MARKET",
        #              "origQty": "1.0000",
        #              "price": "0.0",
        #              "executedQty": "0.0000",
        #              "avgPrice": "0.0",
        #              "cumQuote": "",
        #              "stopPrice": "16494.0",
        #              "profit": "",
        #              "commission": "",
        #              "status": "FILLED",
        #              "time": 1669731935000,
        #              "updateTime": 1669752524000
        #            }
        #          }
        #      }
        #
        data = self.safe_value(response, 'data')
        first = self.safe_dict(data, 'order', data)
        return self.parse_order(first, market)

    def fetch_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
        """
        fetches information on multiple orders made by the user
        :see: https://bingx-api.github.io/docs/#/en-us/swapV2/trade-api.html#User's%20All%20Orders
        :param str symbol: unified market symbol of the market orders were made in
        :param int [since]: the earliest time in ms to fetch orders for
        :param int [limit]: the maximum number of order structures to retrieve
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :param int [params.until]: the latest time in ms to fetch entries for
        :param int [params.orderId]: Only return subsequent orders, and return the latest order by default
        :returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
        """
        self.load_markets()
        request = {}
        market = None
        if symbol is not None:
            market = self.market(symbol)
            request['symbol'] = market['id']
        type = None
        type, params = self.handle_market_type_and_params('fetchOrders', market, params)
        if type != 'swap':
            raise NotSupported(self.id + ' fetchOrders() is only supported for swap markets')
        if limit is not None:
            request['limit'] = limit
        if since is not None:
            request['startTime'] = since
        until = self.safe_integer_2(params, 'until', 'till')  # unified in milliseconds
        endTime = self.safe_integer(params, 'endTime', until)  # exchange-specific in milliseconds
        params = self.omit(params, ['endTime', 'till', 'until'])
        if endTime is not None:
            request['endTime'] = endTime
        response = self.swapV1PrivateGetTradeFullOrder(self.extend(request, params))
        #
        #     {
        #         "code": 0,
        #         "msg": "",
        #         "data": {
        #         "orders": [
        #           {
        #             "symbol": "PYTH-USDT",
        #             "orderId": 1736007506620112100,
        #             "side": "SELL",
        #             "positionSide": "SHORT",
        #             "type": "LIMIT",
        #             "origQty": "33",
        #             "price": "0.3916",
        #             "executedQty": "33",
        #             "avgPrice": "0.3916",
        #             "cumQuote": "13",
        #             "stopPrice": "",
        #             "profit": "0.0000",
        #             "commission": "-0.002585",
        #             "status": "FILLED",
        #             "time": 1702731418000,
        #             "updateTime": 1702731470000,
        #             "clientOrderId": "",
        #             "leverage": "15X",
        #             "takeProfit": {
        #                 "type": "TAKE_PROFIT",
        #                 "quantity": 0,
        #                 "stopPrice": 0,
        #                 "price": 0,
        #                 "workingType": ""
        #             },
        #             "stopLoss": {
        #                 "type": "STOP",
        #                 "quantity": 0,
        #                 "stopPrice": 0,
        #                 "price": 0,
        #                 "workingType": ""
        #             },
        #             "advanceAttr": 0,
        #             "positionID": 0,
        #             "takeProfitEntrustPrice": 0,
        #             "stopLossEntrustPrice": 0,
        #             "orderType": "",
        #             "workingType": "MARK_PRICE",
        #             "stopGuaranteed": False,
        #             "triggerOrderId": 1736012449498123500
        #           }
        #         ]
        #       }
        #     }
        #
        data = self.safe_dict(response, 'data', {})
        orders = self.safe_list(data, 'orders', [])
        return self.parse_orders(orders, market, since, limit)

    def fetch_open_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
        """
        :see: https://bingx-api.github.io/docs/#/spot/trade-api.html#Query%20Open%20Orders
        :see: https://bingx-api.github.io/docs/#/swapV2/trade-api.html#Query%20all%20current%20pending%20orders
        fetch all unfilled currently open orders
        :param str symbol: unified market symbol
        :param int [since]: the earliest time in ms to fetch open orders for
        :param int [limit]: the maximum number of open order structures to retrieve
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
        """
        self.load_markets()
        market = None
        request: dict = {}
        if symbol is not None:
            market = self.market(symbol)
            request['symbol'] = market['id']
        response = None
        marketType, query = self.handle_market_type_and_params('fetchOpenOrders', market, params)
        if marketType == 'spot':
            response = self.spotV1PrivateGetTradeOpenOrders(self.extend(request, query))
        else:
            response = self.swapV2PrivateGetTradeOpenOrders(self.extend(request, query))
        #
        #  spot
        #
        #    {
        #        "code": 0,
        #        "msg": "",
        #        "data": {
        #            "orders": [
        #                {
        #                    "symbol": "XRP-USDT",
        #                    "orderId": 1514073325788200960,
        #                    "price": "0.5",
        #                    "origQty": "20",
        #                    "executedQty": "0",
        #                    "cummulativeQuoteQty": "0",
        #                    "status": "PENDING",
        #                    "type": "LIMIT",
        #                    "side": "BUY",
        #                    "time": 1649818185647,
        #                    "updateTime": 1649818185647,
        #                    "origQuoteOrderQty": "0"
        #                }
        #            ]
        #        }
        #    }
        #
        # swap
        #
        #    {
        #        "code": 0,
        #        "msg": "",
        #        "data": {
        #          "orders": [
        #            {
        #              "symbol": "LINK-USDT",
        #              "orderId": 1585839271162413056,
        #              "side": "BUY",
        #              "positionSide": "LONG",
        #              "type": "TRIGGER_MARKET",
        #              "origQty": "5.0",
        #              "price": "9",
        #              "executedQty": "0.0",
        #              "avgPrice": "0",
        #              "cumQuote": "0",
        #              "stopPrice": "5",
        #              "profit": "0.0000",
        #              "commission": "0.000000",
        #              "status": "CANCELLED",
        #              "time": 1667631605000,
        #              "updateTime": 1667631605000
        #            },
        #          ]
        #        }
        #    }
        #
        data = self.safe_dict(response, 'data', {})
        orders = self.safe_list(data, 'orders', [])
        return self.parse_orders(orders, market, since, limit)

    def fetch_closed_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
        """
        fetches information on multiple closed orders made by the user
        :see: https://bingx-api.github.io/docs/#/spot/trade-api.html#Query%20Order%20History
        :see: https://bingx-api.github.io/docs/#/swapV2/trade-api.html#User's%20Force%20Orders
        :see: https://bingx-api.github.io/docs/#/standard/contract-interface.html#Historical%20order
        :param str [symbol]: unified market symbol of the market orders were made in
        :param int [since]: the earliest time in ms to fetch orders for
        :param int [limit]: the maximum number of order structures to retrieve
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :param int [params.until]: the latest time in ms to fetch orders for
        :param boolean [params.standard]: whether to fetch standard contract orders
        :returns dict[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
        """
        if symbol is None:
            raise ArgumentsRequired(self.id + ' fetchClosedOrders() requires a symbol argument')
        self.load_markets()
        market = self.market(symbol)
        request: dict = {
            'symbol': market['id'],
        }
        response = None
        standard = None
        standard, params = self.handle_option_and_params(params, 'fetchClosedOrders', 'standard', False)
        marketType, query = self.handle_market_type_and_params('fetchClosedOrders', market, params)
        if standard:
            response = self.contractV1PrivateGetAllOrders(self.extend(request, query))
        elif marketType == 'spot':
            response = self.spotV1PrivateGetTradeHistoryOrders(self.extend(request, query))
        else:
            response = self.swapV2PrivateGetTradeAllOrders(self.extend(request, query))
        #
        #  spot
        #
        #    {
        #        "code": 0,
        #        "msg": "",
        #        "data": {
        #            "orders": [
        #                {
        #                    "symbol": "XRP-USDT",
        #                    "orderId": 1514073325788200960,
        #                    "price": "0.5",
        #                    "origQty": "20",
        #                    "executedQty": "0",
        #                    "cummulativeQuoteQty": "0",
        #                    "status": "PENDING",
        #                    "type": "LIMIT",
        #                    "side": "BUY",
        #                    "time": 1649818185647,
        #                    "updateTime": 1649818185647,
        #                    "origQuoteOrderQty": "0"
        #                }
        #            ]
        #        }
        #    }
        #
        # swap
        #
        #    {
        #        "code": 0,
        #        "msg": "",
        #        "data": {
        #          "orders": [
        #            {
        #              "symbol": "LINK-USDT",
        #              "orderId": 1585839271162413056,
        #              "side": "BUY",
        #              "positionSide": "LONG",
        #              "type": "TRIGGER_MARKET",
        #              "origQty": "5.0",
        #              "price": "9",
        #              "executedQty": "0.0",
        #              "avgPrice": "0",
        #              "cumQuote": "0",
        #              "stopPrice": "5",
        #              "profit": "0.0000",
        #              "commission": "0.000000",
        #              "status": "CANCELLED",
        #              "time": 1667631605000,
        #              "updateTime": 1667631605000
        #            },
        #          ]
        #        }
        #    }
        #
        data = self.safe_value(response, 'data', [])
        orders = self.safe_list(data, 'orders', [])
        return self.parse_orders(orders, market, since, limit)

    def transfer(self, code: str, amount: float, fromAccount: str, toAccount: str, params={}) -> TransferEntry:
        """
        transfer currency internally between wallets on the same account
        :see: https://bingx-api.github.io/docs/#/spot/account-api.html#User%20Universal%20Transfer
        :param str code: unified currency code
        :param float amount: amount to transfer
        :param str fromAccount: account to transfer from
        :param str toAccount: account to transfer to
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: a `transfer structure <https://docs.ccxt.com/#/?id=transfer-structure>`
        """
        self.load_markets()
        currency = self.currency(code)
        accountsByType = self.safe_dict(self.options, 'accountsByType', {})
        fromId = self.safe_string(accountsByType, fromAccount, fromAccount)
        toId = self.safe_string(accountsByType, toAccount, toAccount)
        request: dict = {
            'asset': currency['id'],
            'amount': self.currency_to_precision(code, amount),
            'type': fromId + '_' + toId,
        }
        response = self.spotV3PrivateGetGetAssetTransfer(self.extend(request, params))
        #
        #    {
        #        "tranId":13526853623
        #    }
        #
        return {
            'info': response,
            'id': self.safe_string(response, 'tranId'),
            'timestamp': None,
            'datetime': None,
            'currency': code,
            'amount': amount,
            'fromAccount': fromAccount,
            'toAccount': toAccount,
            'status': None,
        }

    def fetch_transfers(self, code: Str = None, since: Int = None, limit: Int = None, params={}):
        """
        fetch a history of internal transfers made on an account
        :see: https://bingx-api.github.io/docs/#/spot/account-api.html#Query%20User%20Universal%20Transfer%20History%20(USER_DATA)
        :param str [code]: unified currency code of the currency transferred
        :param int [since]: the earliest time in ms to fetch transfers for
        :param int [limit]: the maximum number of transfers structures to retrieve
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict[]: a list of `transfer structures <https://docs.ccxt.com/#/?id=transfer-structure>`
        """
        self.load_markets()
        currency = None
        if code is not None:
            currency = self.currency(code)
        accountsByType = self.safe_dict(self.options, 'accountsByType', {})
        fromAccount = self.safe_string(params, 'fromAccount')
        toAccount = self.safe_string(params, 'toAccount')
        fromId = self.safe_string(accountsByType, fromAccount, fromAccount)
        toId = self.safe_string(accountsByType, toAccount, toAccount)
        if fromId is None or toId is None:
            raise ExchangeError(self.id + ' fromAccount & toAccount parameter are required')
        request: dict = {
            'type': fromId + '_' + toId,
        }
        if since is not None:
            request['startTime'] = since
        if limit is not None:
            request['size'] = limit
        response = self.spotV3PrivateGetAssetTransfer(self.extend(request, params))
        #
        #     {
        #         "total": 3,
        #         "rows": [
        #             {
        #                 "asset":"USDT",
        #                 "amount":"-100.00000000000000000000",
        #                 "type":"FUND_SFUTURES",
        #                 "status":"CONFIRMED",
        #                 "tranId":1067594500957016069,
        #                 "timestamp":1658388859000
        #             },
        #         ]
        #     }
        #
        rows = self.safe_list(response, 'rows', [])
        return self.parse_transfers(rows, currency, since, limit)

    def parse_transfer(self, transfer, currency: Currency = None):
        tranId = self.safe_string(transfer, 'tranId')
        timestamp = self.safe_integer(transfer, 'timestamp')
        currencyCode = self.safe_currency_code(None, currency)
        status = self.safe_string(transfer, 'status')
        accountsById = self.safe_dict(self.options, 'accountsById', {})
        typeId = self.safe_string(transfer, 'type')
        typeIdSplit = typeId.split('_')
        fromId = self.safe_string(typeIdSplit, 0)
        toId = self.safe_string(typeId, 1)
        fromAccount = self.safe_string(accountsById, fromId, fromId)
        toAccount = self.safe_string(accountsById, toId, toId)
        return {
            'info': transfer,
            'id': tranId,
            'timestamp': timestamp,
            'datetime': self.iso8601(timestamp),
            'currency': currencyCode,
            'amount': self.safe_number(transfer, 'amount'),
            'fromAccount': fromAccount,
            'toAccount': toAccount,
            'status': status,
        }

    def fetch_deposit_addresses_by_network(self, code: str, params={}):
        """
        fetch the deposit addresses for a currency associated with self account
        :see: https://bingx-api.github.io/docs/#/en-us/common/wallet-api.html#Query%20Main%20Account%20Deposit%20Address
        :param str code: unified currency code
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: a dictionary `address structures <https://docs.ccxt.com/#/?id=address-structure>`, indexed by the network
        """
        self.load_markets()
        currency = self.currency(code)
        defaultRecvWindow = self.safe_integer(self.options, 'recvWindow')
        recvWindow = self.safe_integer(self.parse_params, 'recvWindow', defaultRecvWindow)
        request: dict = {
            'coin': currency['id'],
            'offset': 0,
            'limit': 1000,
            'recvWindow': recvWindow,
        }
        response = self.walletsV1PrivateGetCapitalDepositAddress(self.extend(request, params))
        #
        #     {
        #         "code": "0",
        #         "timestamp": "1695200226859",
        #         "data": {
        #           "data": [
        #             {
        #               "coinId": "799",
        #               "coin": "USDT",
        #               "network": "BEP20",
        #               "address": "6a7eda2817462dabb6493277a2cfe0f5c3f2550b",
        #               "tag": ''
        #             }
        #           ],
        #           "total": "1"
        #         }
        #     }
        #
        data = self.safe_list(self.safe_dict(response, 'data'), 'data')
        parsed = self.parse_deposit_addresses(data, [currency['code']], False)
        return self.index_by(parsed, 'network')

    def fetch_deposit_address(self, code: str, params={}):
        """
        fetch the deposit address for a currency associated with self account
        :see: https://bingx-api.github.io/docs/#/en-us/common/wallet-api.html#Query%20Main%20Account%20Deposit%20Address
        :param str code: unified currency code
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :param str [params.network]: The chain of currency. This only apply for multi-chain currency, and there is no need for single chain currency
        :returns dict: an `address structure <https://docs.ccxt.com/#/?id=address-structure>`
        """
        network = self.safe_string(params, 'network')
        params = self.omit(params, ['network'])
        addressStructures = self.fetch_deposit_addresses_by_network(code, params)
        if network is not None:
            return self.safe_dict(addressStructures, network)
        else:
            options = self.safe_dict(self.options, 'defaultNetworks')
            defaultNetworkForCurrency = self.safe_string(options, code)
            if defaultNetworkForCurrency is not None:
                return self.safe_dict(addressStructures, defaultNetworkForCurrency)
            else:
                keys = list(addressStructures.keys())
                key = self.safe_string(keys, 0)
                return self.safe_dict(addressStructures, key)

    def parse_deposit_address(self, depositAddress, currency: Currency = None):
        #
        #     {
        #         "coinId": "799",
        #         "coin": "USDT",
        #         "network": "BEP20",
        #         "address": "6a7eda2817462dabb6493277a2cfe0f5c3f2550b",
        #         "tag": ''
        #     }
        #
        address = self.safe_string(depositAddress, 'address')
        tag = self.safe_string(depositAddress, 'tag')
        currencyId = self.safe_string(depositAddress, 'coin')
        currency = self.safe_currency(currencyId, currency)
        code = currency['code']
        network = self.safe_string(depositAddress, 'network')
        self.check_address(address)
        return {
            'currency': code,
            'address': address,
            'tag': tag,
            'network': network,
            'info': depositAddress,
        }

    def fetch_deposits(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Transaction]:
        """
        fetch all deposits made to an account
        :see: https://bingx-api.github.io/docs/#/spot/account-api.html#Deposit%20History(supporting%20network)
        :param str [code]: unified currency code
        :param int [since]: the earliest time in ms to fetch deposits for
        :param int [limit]: the maximum number of deposits structures to retrieve
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict[]: a list of `transaction structures <https://docs.ccxt.com/#/?id=transaction-structure>`
        """
        self.load_markets()
        request: dict = {
        }
        currency = None
        if code is not None:
            currency = self.currency(code)
            request['coin'] = currency['id']
        if since is not None:
            request['startTime'] = since
        if limit is not None:
            request['limit'] = limit  # default 1000
        response = self.spotV3PrivateGetCapitalDepositHisrec(self.extend(request, params))
        #
        #    [
        #        {
        #            "amount":"0.00999800",
        #            "coin":"PAXG",
        #            "network":"ETH",
        #            "status":1,
        #            "address":"0x788cabe9236ce061e5a892e1a59395a81fc8d62c",
        #            "addressTag":"",
        #            "txId":"0xaad4654a3234aa6118af9b4b335f5ae81c360b2394721c019b5d1e75328b09f3",
        #            "insertTime":1599621997000,
        #            "transferType":0,
        #            "unlockConfirm":"12/12",  # confirm times for unlocking
        #            "confirmTimes":"12/12"
        #        },
        #    ]
        #
        return self.parse_transactions(response, currency, since, limit)

    def fetch_withdrawals(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Transaction]:
        """
        fetch all withdrawals made from an account
        :see: https://bingx-api.github.io/docs/#/spot/account-api.html#Withdraw%20History%20(supporting%20network)
        :param str [code]: unified currency code
        :param int [since]: the earliest time in ms to fetch withdrawals for
        :param int [limit]: the maximum number of withdrawals structures to retrieve
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict[]: a list of `transaction structures <https://docs.ccxt.com/#/?id=transaction-structure>`
        """
        self.load_markets()
        request: dict = {
        }
        currency = None
        if code is not None:
            currency = self.currency(code)
            request['coin'] = currency['id']
        if since is not None:
            request['startTime'] = since
        if limit is not None:
            request['limit'] = limit  # default 1000
        response = self.spotV3PrivateGetCapitalWithdrawHistory(self.extend(request, params))
        #
        #    [
        #        {
        #            "address": "0x94df8b352de7f46f64b01d3666bf6e936e44ce60",
        #            "amount": "8.91000000",
        #            "applyTime": "2019-10-12 11:12:02",
        #            "coin": "USDT",
        #            "id": "b6ae22b3aa844210a7041aee7589627c",
        #            "withdrawOrderId": "WITHDRAWtest123",
        #            "network": "ETH",
        #            "transferType": 0
        #            "status": 6,
        #            "transactionFee": "0.004",
        #            "confirmNo":3,
        #            "info": "The address is not valid. Please confirm with the recipient",
        #            "txId": "0xb5ef8c13b968a406cc62a93a8bd80f9e9a906ef1b3fcf20a2e48573c17659268"
        #        },
        #    ]
        #
        return self.parse_transactions(response, currency, since, limit)

    def parse_transaction(self, transaction, currency: Currency = None) -> Transaction:
        #
        # fetchDeposits
        #
        #    {
        #        "amount":"0.00999800",
        #        "coin":"PAXG",
        #        "network":"ETH",
        #        "status":1,
        #        "address":"0x788cabe9236ce061e5a892e1a59395a81fc8d62c",
        #        "addressTag":"",
        #        "txId":"0xaad4654a3234aa6118af9b4b335f5ae81c360b2394721c019b5d1e75328b09f3",
        #        "insertTime":1599621997000,
        #        "transferType":0,
        #        "unlockConfirm":"12/12",  # confirm times for unlocking
        #        "confirmTimes":"12/12"
        #    }
        #
        # fetchWithdrawals
        #
        #    {
        #        "address": "0x94df8b352de7f46f64b01d3666bf6e936e44ce60",
        #        "amount": "8.91000000",
        #        "applyTime": "2019-10-12 11:12:02",
        #        "coin": "USDT",
        #        "id": "b6ae22b3aa844210a7041aee7589627c",
        #        "withdrawOrderId": "WITHDRAWtest123",
        #        "network": "ETH",
        #        "transferType": 0
        #        "status": 6,
        #        "transactionFee": "0.004",
        #        "confirmNo":3,
        #        "info": "The address is not valid. Please confirm with the recipient",
        #        "txId": "0xb5ef8c13b968a406cc62a93a8bd80f9e9a906ef1b3fcf20a2e48573c17659268"
        #    }
        #
        # withdraw
        #
        #     {
        #         "code":0,
        #         "timestamp":1705274263621,
        #         "data":{
        #             "id":"1264246141278773252"
        #         }
        #     }
        #
        # parse withdraw-type output first...
        #
        data = self.safe_value(transaction, 'data')
        dataId = None if (data is None) else self.safe_string(data, 'id')
        id = self.safe_string(transaction, 'id', dataId)
        address = self.safe_string(transaction, 'address')
        tag = self.safe_string(transaction, 'addressTag')
        timestamp = self.safe_integer(transaction, 'insertTime')
        datetime = self.iso8601(timestamp)
        if timestamp is None:
            datetime = self.safe_string(transaction, 'applyTime')
            timestamp = self.parse8601(datetime)
        network = self.safe_string(transaction, 'network')
        currencyId = self.safe_string(transaction, 'coin')
        code = self.safe_currency_code(currencyId, currency)
        if (code is not None) and (code != network) and code.find(network) >= 0:
            if network is not None:
                code = code.replace(network, '')
        rawType = self.safe_string(transaction, 'transferType')
        type = 'deposit' if (rawType == '0') else 'withdrawal'
        return {
            'info': transaction,
            'id': id,
            'txid': self.safe_string(transaction, 'txId'),
            'type': type,
            'currency': code,
            'network': self.network_id_to_code(network),
            'amount': self.safe_number(transaction, 'amount'),
            'status': self.parse_transaction_status(self.safe_string(transaction, 'status')),
            'timestamp': timestamp,
            'datetime': datetime,
            'address': address,
            'addressFrom': None,
            'addressTo': address,
            'tag': tag,
            'tagFrom': tag,
            'tagTo': None,
            'updated': None,
            'comment': self.safe_string(transaction, 'info'),
            'fee': {
                'currency': code,
                'cost': self.safe_number(transaction, 'transactionFee'),
                'rate': None,
            },
            'internal': None,
        }

    def parse_transaction_status(self, status: str):
        statuses = {
            '0': 'pending',
            '1': 'ok',
            '10': 'pending',
            '20': 'rejected',
            '30': 'ok',
            '40': 'rejected',
            '50': 'ok',
            '60': 'pending',
            '70': 'rejected',
            '2': 'pending',
            '3': 'rejected',
            '4': 'pending',
            '5': 'rejected',
            '6': 'ok',
        }
        return self.safe_string(statuses, status, status)

    def set_margin_mode(self, marginMode: str, symbol: Str = None, params={}):
        """
        set margin mode to 'cross' or 'isolated'
        :see: https://bingx-api.github.io/docs/#/swapV2/trade-api.html#Switch%20Margin%20Mode
        :param str marginMode: 'cross' or 'isolated'
        :param str symbol: unified market symbol
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :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['type'] != 'swap':
            raise BadSymbol(self.id + ' setMarginMode() supports swap contracts only')
        marginMode = marginMode.upper()
        if marginMode == 'CROSS':
            marginMode = 'CROSSED'
        if marginMode != 'ISOLATED' and marginMode != 'CROSSED':
            raise BadRequest(self.id + ' setMarginMode() marginMode argument should be isolated or cross')
        request: dict = {
            'symbol': market['id'],
            'marginType': marginMode,
        }
        return self.swapV2PrivatePostTradeMarginType(self.extend(request, params))

    def add_margin(self, symbol: str, amount: float, params={}) -> MarginModification:
        request = {
            'type': 1,
        }
        return self.set_margin(symbol, amount, self.extend(request, params))

    def reduce_margin(self, symbol: str, amount: float, params={}) -> MarginModification:
        request = {
            'type': 2,
        }
        return self.set_margin(symbol, amount, self.extend(request, params))

    def set_margin(self, symbol: str, amount: float, params={}) -> MarginModification:
        """
        Either adds or reduces margin in an isolated position in order to set the margin to a specific value
        :see: https://bingx-api.github.io/docs/#/swapV2/trade-api.html#Adjust%20isolated%20margin
        :param str symbol: unified market symbol of the market to set margin in
        :param float amount: the amount to set the margin to
        :param dict [params]: parameters specific to the bingx api endpoint
        :returns dict: A `margin structure <https://docs.ccxt.com/#/?id=add-margin-structure>`
        """
        type = self.safe_integer(params, 'type')  # 1 increase margin 2 decrease margin
        if type is None:
            raise ArgumentsRequired(self.id + ' setMargin() requires a type parameter either 1(increase margin) or 2(decrease margin)')
        if not self.in_array(type, [1, 2]):
            raise ArgumentsRequired(self.id + ' setMargin() requires a type parameter either 1(increase margin) or 2(decrease margin)')
        self.load_markets()
        market = self.market(symbol)
        request: dict = {
            'symbol': market['id'],
            'amount': self.amount_to_precision(market['symbol'], amount),
            'type': type,
        }
        response = self.swapV2PrivatePostTradePositionMargin(self.extend(request, params))
        #
        #    {
        #        "code": 0,
        #        "msg": "",
        #        "amount": 1,
        #        "type": 1
        #    }
        #
        return self.parse_margin_modification(response, market)

    def parse_margin_modification(self, data, market: Market = None) -> MarginModification:
        #
        #    {
        #        "code": 0,
        #        "msg": "",
        #        "amount": 1,
        #        "type": 1
        #    }
        #
        type = self.safe_string(data, 'type')
        return {
            'info': data,
            'symbol': self.safe_string(market, 'symbol'),
            'type': 'add' if (type == '1') else 'reduce',
            'marginMode': 'isolated',
            'amount': self.safe_number(data, 'amount'),
            'total': self.safe_number(data, 'margin'),
            'code': self.safe_string(market, 'settle'),
            'status': None,
            'timestamp': None,
            'datetime': None,
        }

    def fetch_leverage(self, symbol: str, params={}) -> Leverage:
        """
        fetch the set leverage for a market
        :see: https://bingx-api.github.io/docs/#/swapV2/trade-api.html#Query%20Leverage
        :param str symbol: unified market symbol
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: a `leverage structure <https://docs.ccxt.com/#/?id=leverage-structure>`
        """
        self.load_markets()
        market = self.market(symbol)
        request: dict = {
            'symbol': market['id'],
        }
        response = self.swapV2PrivateGetTradeLeverage(self.extend(request, params))
        #
        #    {
        #        "code": 0,
        #        "msg": "",
        #        "data": {
        #            "longLeverage": 6,
        #            "shortLeverage": 6
        #        }
        #    }
        #
        data = self.safe_dict(response, 'data', {})
        return self.parse_leverage(data, market)

    def parse_leverage(self, leverage, market=None) -> Leverage:
        marketId = self.safe_string(leverage, 'symbol')
        return {
            'info': leverage,
            'symbol': self.safe_symbol(marketId, market),
            'marginMode': None,
            'longLeverage': self.safe_integer(leverage, 'longLeverage'),
            'shortLeverage': self.safe_integer(leverage, 'shortLeverage'),
        }

    def set_leverage(self, leverage: Int, symbol: Str = None, params={}):
        """
        set the level of leverage for a market
        :see: https://bingx-api.github.io/docs/#/swapV2/trade-api.html#Switch%20Leverage
        :param float leverage: the rate of leverage
        :param str symbol: unified market symbol
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :param str [params.side]: hedged: ['long' or 'short']. one way: ['both']
        :returns dict: response from the exchange
        """
        if symbol is None:
            raise ArgumentsRequired(self.id + ' setLeverage() requires a symbol argument')
        side = self.safe_string_upper(params, 'side')
        self.check_required_argument('setLeverage', side, 'side', ['LONG', 'SHORT', 'BOTH'])
        self.load_markets()
        market = self.market(symbol)
        request: dict = {
            'symbol': market['id'],
            'side': side,
            'leverage': leverage,
        }
        #
        #    {
        #        "code": 0,
        #        "msg": "",
        #        "data": {
        #            "leverage": 6,
        #            "symbol": "BTC-USDT"
        #        }
        #    }
        #
        return self.swapV2PrivatePostTradeLeverage(self.extend(request, params))

    def fetch_my_trades(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
        """
        fetch all trades made by the user
        :see: https://bingx-api.github.io/docs/#/en-us/spot/trade-api.html#Query%20Order%20History
        :see: https://bingx-api.github.io/docs/#/swapV2/trade-api.html#Query%20historical%20transaction%20orders
        :param str [symbol]: unified market symbol
        :param int [since]: the earliest time in ms to fetch trades for
        :param int [limit]: the maximum number of trades structures to retrieve
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :param int [params.until]: timestamp in ms for the ending date filter, default is None
        :param str params['trandingUnit']: COIN(directly represent assets such and ETH) or CONT(represents the number of contract sheets)
        :returns dict[]: a list of `trade structures <https://docs.ccxt.com/#/?id=trade-structure>`
        """
        if symbol is None:
            raise ArgumentsRequired(self.id + ' fetchMyTrades() requires a symbol argument')
        self.load_markets()
        market = self.market(symbol)
        now = self.milliseconds()
        response = None
        request: dict = {
            'symbol': market['id'],
        }
        if since is not None:
            startTimeReq = 'startTime' if market['spot'] else 'startTs'
            request[startTimeReq] = since
        elif market['swap']:
            request['startTs'] = now - 7776000000  # 90 days
        until = self.safe_integer(params, 'until')
        params = self.omit(params, 'until')
        if until is not None:
            endTimeReq = 'endTime' if market['spot'] else 'endTs'
            request[endTimeReq] = until
        elif market['swap']:
            request['endTs'] = now
        fills = None
        if market['spot']:
            response = self.spotV1PrivateGetTradeMyTrades(self.extend(request, params))
            data = self.safe_dict(response, 'data', {})
            fills = self.safe_list(data, 'fills', [])
            #
            #     {
            #         "code": 0,
            #         "msg": "",
            #         "debugMsg": "",
            #         "data": {
            #             "fills": [
            #                 {
            #                     "symbol": "LTC-USDT",
            #                     "id": 36237072,
            #                     "orderId": 1674069326895775744,
            #                     "price": "85.891",
            #                     "qty": "0.0582",
            #                     "quoteQty": "4.9988562000000005",
            #                     "commission": -0.00005820000000000001,
            #                     "commissionAsset": "LTC",
            #                     "time": 1687964205000,
            #                     "isBuyer": True,
            #                     "isMaker": False
            #                 }
            #             ]
            #         }
            #     }
            #
        else:
            tradingUnit = self.safe_string_upper(params, 'tradingUnit', 'CONT')
            params = self.omit(params, 'tradingUnit')
            request['tradingUnit'] = tradingUnit
            response = self.swapV2PrivateGetTradeAllFillOrders(self.extend(request, params))
            data = self.safe_dict(response, 'data', {})
            fills = self.safe_list(data, 'fill_orders', [])
            #
            #    {
            #       "code": "0",
            #       "msg": '',
            #       "data": {fill_orders: [
            #          {
            #              "volume": "0.1",
            #              "price": "106.75",
            #              "amount": "10.6750",
            #              "commission": "-0.0053",
            #              "currency": "USDT",
            #              "orderId": "1676213270274379776",
            #              "liquidatedPrice": "0.00",
            #              "liquidatedMarginRatio": "0.00",
            #              "filledTime": "2023-07-04T20:56:01.000+0800"
            #          }
            #        ]
            #      }
            #    }
            #
        return self.parse_trades(fills, market, since, limit, params)

    def parse_deposit_withdraw_fee(self, fee, currency: Currency = None):
        #
        #    {
        #        "coin": "BTC",
        #        "name": "BTC",
        #        "networkList": [
        #          {
        #            "name": "BTC",
        #            "network": "BTC",
        #            "isDefault": True,
        #            "minConfirm": "2",
        #            "withdrawEnable": True,
        #            "withdrawFee": "0.00035",
        #            "withdrawMax": "1.62842",
        #            "withdrawMin": "0.0005"
        #          },
        #          {
        #            "name": "BTC",
        #            "network": "BEP20",
        #            "isDefault": False,
        #            "minConfirm": "15",
        #            "withdrawEnable": True,
        #            "withdrawFee": "0.00001",
        #            "withdrawMax": "1.62734",
        #            "withdrawMin": "0.0001"
        #          }
        #        ]
        #    }
        #
        networkList = self.safe_list(fee, 'networkList', [])
        networkListLength = len(networkList)
        result = {
            'info': fee,
            'withdraw': {
                'fee': None,
                'percentage': None,
            },
            'deposit': {
                'fee': None,
                'percentage': None,
            },
            'networks': {},
        }
        if networkListLength != 0:
            for i in range(0, networkListLength):
                network = networkList[i]
                networkId = self.safe_string(network, 'network')
                isDefault = self.safe_bool(network, 'isDefault')
                currencyCode = self.safe_string(currency, 'code')
                networkCode = self.network_id_to_code(networkId, currencyCode)
                result['networks'][networkCode] = {
                    'deposit': {'fee': None, 'percentage': None},
                    'withdraw': {'fee': self.safe_number(network, 'withdrawFee'), 'percentage': False},
                }
                if isDefault:
                    result['withdraw']['fee'] = self.safe_number(network, 'withdrawFee')
                    result['withdraw']['percentage'] = False
        return result

    def fetch_deposit_withdraw_fees(self, codes: Strings = None, params={}):
        """
        fetch deposit and withdraw fees
        :see: https://bingx-api.github.io/docs/#/common/account-api.html#All%20Coins'%20Information
        :param str[]|None codes: list of unified currency codes
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: a list of `fee structures <https://docs.ccxt.com/#/?id=fee-structure>`
        """
        self.load_markets()
        response = self.walletsV1PrivateGetCapitalConfigGetall(params)
        coins = self.safe_list(response, 'data')
        return self.parse_deposit_withdraw_fees(coins, codes, 'coin')

    def withdraw(self, code: str, amount: float, address, tag=None, params={}):
        """
        make a withdrawal
        :see: https://bingx-api.github.io/docs/#/common/account-api.html#Withdraw
        :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 exchange API endpoint
        :param int [params.walletType]: 1 fund account, 2 standard account, 3 perpetual account
        :returns dict: a `transaction structure <https://docs.ccxt.com/#/?id=transaction-structure>`
        """
        self.load_markets()
        currency = self.currency(code)
        walletType = self.safe_integer(params, 'walletType')
        if walletType is None:
            walletType = 1
        if not self.in_array(walletType, [1, 2, 3]):
            raise BadRequest(self.id + ' withdraw() requires either 1 fund account, 2 standard futures account, 3 perpetual account for walletType')
        request: dict = {
            'coin': currency['id'],
            'address': address,
            'amount': self.number_to_string(amount),
            'walletType': walletType,
        }
        network = self.safe_string_upper(params, 'network')
        if network is not None:
            request['network'] = self.network_code_to_id(network)
        params = self.omit(params, ['walletType', 'network'])
        response = self.walletsV1PrivatePostCapitalWithdrawApply(self.extend(request, params))
        data = self.safe_value(response, 'data')
        #    {
        #        "code":0,
        #        "timestamp":1689258953651,
        #        "data":{
        #           "id":"1197073063359000577"
        #        }
        #    }
        return self.parse_transaction(data)

    def parse_params(self, params):
        sortedParams = self.keysort(params)
        keys = list(sortedParams.keys())
        for i in range(0, len(keys)):
            key = keys[i]
            value = sortedParams[key]
            if isinstance(value, list):
                arrStr = '['
                for j in range(0, len(value)):
                    arrayElement = value[j]
                    if j > 0:
                        arrStr += ','
                    arrStr += str(arrayElement)
                arrStr += ']'
                sortedParams[key] = arrStr
        return sortedParams

    def fetch_my_liquidations(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
        """
        retrieves the users liquidated positions
        :see: https://bingx-api.github.io/docs/#/swapV2/trade-api.html#User's%20Force%20Orders
        :param str [symbol]: unified CCXT market symbol
        :param int [since]: the earliest time in ms to fetch liquidations for
        :param int [limit]: the maximum number of liquidation structures to retrieve
        :param dict [params]: exchange specific parameters for the bingx api endpoint
        :param int [params.until]: timestamp in ms of the latest liquidation
        :returns dict: an array of `liquidation structures <https://docs.ccxt.com/#/?id=liquidation-structure>`
        """
        self.load_markets()
        request = {
            'autoCloseType': 'LIQUIDATION',
        }
        request, params = self.handle_until_option('endTime', request, params)
        market = None
        if symbol is not None:
            market = self.market(symbol)
            request['symbol'] = symbol
        if since is not None:
            request['startTime'] = since
        if limit is not None:
            request['limit'] = limit
        response = self.swapV2PrivateGetTradeForceOrders(self.extend(request, params))
        #
        #     {
        #         "code": 0,
        #         "msg": "",
        #         "data": {
        #             "orders": [
        #                 {
        #                     "time": "int64",
        #                     "symbol": "string",
        #                     "side": "string",
        #                      "type": "string",
        #                     "positionSide": "string",
        #                     "cumQuote": "string",
        #                     "status": "string",
        #                     "stopPrice": "string",
        #                     "price": "string",
        #                     "origQty": "string",
        #                     "avgPrice": "string",
        #                     "executedQty": "string",
        #                     "orderId": "int64",
        #                     "profit": "string",
        #                     "commission": "string",
        #                     "workingType": "string",
        #                     "updateTime": "int64"
        #                 },
        #             ]
        #         }
        #     }
        #
        data = self.safe_dict(response, 'data', {})
        liquidations = self.safe_list(data, 'orders', [])
        return self.parse_liquidations(liquidations, market, since, limit)

    def parse_liquidation(self, liquidation, market: Market = None):
        #
        #     {
        #         "time": "int64",
        #         "symbol": "string",
        #         "side": "string",
        #         "type": "string",
        #         "positionSide": "string",
        #         "cumQuote": "string",
        #         "status": "string",
        #         "stopPrice": "string",
        #         "price": "string",
        #         "origQty": "string",
        #         "avgPrice": "string",
        #         "executedQty": "string",
        #         "orderId": "int64",
        #         "profit": "string",
        #         "commission": "string",
        #         "workingType": "string",
        #         "updateTime": "int64"
        #     }
        #
        marketId = self.safe_string(liquidation, 'symbol')
        timestamp = self.safe_integer(liquidation, 'time')
        contractsString = self.safe_string(liquidation, 'executedQty')
        contractSizeString = self.safe_string(market, 'contractSize')
        priceString = self.safe_string(liquidation, 'avgPrice')
        baseValueString = Precise.string_mul(contractsString, contractSizeString)
        quoteValueString = Precise.string_mul(baseValueString, priceString)
        return self.safe_liquidation({
            'info': liquidation,
            'symbol': self.safe_symbol(marketId, market),
            'contracts': self.parse_number(contractsString),
            'contractSize': self.parse_number(contractSizeString),
            'price': self.parse_number(priceString),
            'baseValue': self.parse_number(baseValueString),
            'quoteValue': self.parse_number(quoteValueString),
            'timestamp': timestamp,
            'datetime': self.iso8601(timestamp),
        })

    def close_position(self, symbol: str, side: OrderSide = None, params={}) -> Order:
        """
        closes open positions for a market
        :see: https://bingx-api.github.io/docs/#/en-us/swapV2/trade-api.html#One-Click%20Close%20All%20Positions
        :param str symbol: Unified CCXT market symbol
        :param str [side]: not used by bingx
        :param dict [params]: extra parameters specific to the bingx api endpoint
        :param str|None [params.positionId]: it is recommended to hasattr(self, fill) parameter when closing a position
        :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
        """
        self.load_markets()
        positionId = self.safe_string(params, 'positionId')
        params = self.omit(params, 'positionId')
        response = None
        if positionId is not None:
            request: dict = {
                'positionId': positionId,
            }
            response = self.swapV1PrivatePostTradeClosePosition(self.extend(request, params))
        else:
            market = self.market(symbol)
            request: dict = {
                'symbol': market['id'],
            }
            response = self.swapV2PrivatePostTradeCloseAllPositions(self.extend(request, params))
        #
        # swapV1PrivatePostTradeClosePosition
        #
        #    {
        #        "code": 0,
        #        "msg": "",
        #        "timestamp": 1710992264190,
        #        "data": {
        #            "orderId": 1770656007907930112,
        #            "positionId": "1751667128353910784",
        #            "symbol": "LTC-USDT",
        #            "side": "Ask",
        #            "type": "MARKET",
        #            "positionSide": "Long",
        #            "origQty": "0.2"
        #        }
        #    }
        #
        # swapV2PrivatePostTradeCloseAllPositions
        #
        #    {
        #        "code": 0,
        #        "msg": "",
        #        "data": {
        #            "success": [
        #                1727686766700486656,
        #            ],
        #            "failed": null
        #        }
        #    }
        #
        data = self.safe_dict(response, 'data')
        return self.parse_order(data)

    def close_all_positions(self, params={}) -> List[Position]:
        """
        closes open positions for a market
        :see: https://bingx-api.github.io/docs/#/en-us/swapV2/trade-api.html#One-Click%20Close%20All%20Positions
        :param dict [params]: extra parameters specific to the okx api endpoint
        :param str [params.recvWindow]: request valid time window value
        :returns dict[]: `A list of position structures <https://docs.ccxt.com/#/?id=position-structure>`
        """
        self.load_markets()
        defaultRecvWindow = self.safe_integer(self.options, 'recvWindow')
        recvWindow = self.safe_integer(self.parse_params, 'recvWindow', defaultRecvWindow)
        marketType = None
        marketType, params = self.handle_market_type_and_params('closeAllPositions', None, params)
        if marketType == 'margin':
            raise BadRequest(self.id + ' closePositions() cannot be used for ' + marketType + ' markets')
        request: dict = {
            'recvWindow': recvWindow,
        }
        response = self.swapV2PrivatePostTradeCloseAllPositions(self.extend(request, params))
        #
        #    {
        #        "code": 0,
        #        "msg": "",
        #        "data": {
        #            "success": [
        #                1727686766700486656,
        #                1727686767048613888
        #            ],
        #            "failed": null
        #        }
        #    }
        #
        data = self.safe_dict(response, 'data', {})
        success = self.safe_list(data, 'success', [])
        positions = []
        for i in range(0, len(success)):
            position = self.parse_position({'positionId': success[i]})
            positions.append(position)
        return positions

    def fetch_position_mode(self, symbol: Str = None, params={}):
        """
        fetchs the position mode, hedged or one way, hedged for binance is set identically for all linear markets or all inverse markets
        :see: https://bingx-api.github.io/docs/#/en-us/swapV2/trade-api.html#Get%20Position%20Mode
        :param str symbol: unified symbol of the market to fetch the order book for
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: an object detailing whether the market is in hedged or one-way mode
        """
        response = self.swapV1PrivateGetPositionSideDual(params)
        #
        #     {
        #         "code": "0",
        #         "msg": "",
        #         "timeStamp": "1709002057516",
        #         "data": {
        #             "dualSidePosition": "false"
        #         }
        #     }
        #
        data = self.safe_dict(response, 'data', {})
        dualSidePosition = self.safe_string(data, 'dualSidePosition')
        return {
            'info': response,
            'hedged': (dualSidePosition == 'true'),
        }

    def set_position_mode(self, hedged: bool, symbol: Str = None, params={}):
        """
        set hedged to True or False for a market
        :see: https://bingx-api.github.io/docs/#/en-us/swapV2/trade-api.html#Set%20Position%20Mode
        :param bool hedged: set to True to use dualSidePosition
        :param str symbol: not used by bingx setPositionMode()
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: response from the exchange
        """
        dualSidePosition = None
        if hedged:
            dualSidePosition = 'true'
        else:
            dualSidePosition = 'false'
        request: dict = {
            'dualSidePosition': dualSidePosition,
        }
        #
        #     {
        #         code: '0',
        #         msg: '',
        #         timeStamp: '1703327432734',
        #         data: {dualSidePosition: 'false'}
        #     }
        #
        return self.swapV1PrivatePostPositionSideDual(self.extend(request, params))

    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
        :see: https://bingx-api.github.io/docs/#/en-us/spot/trade-api.html#Cancel%20order%20and%20place%20a%20new%20order  # spot
        :see: https://bingx-api.github.io/docs/#/en-us/swapV2/trade-api.html#Cancel%20an%20order%20and%20then%20Place%20a%20new%20order  # swap
        :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 fullfilled, in units of the quote currency, ignored in market orders
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :param str [params.stopPrice]: Trigger price used for TAKE_STOP_LIMIT, TAKE_STOP_MARKET, TRIGGER_LIMIT, TRIGGER_MARKET order types.
        :param dict [params.takeProfit]: *takeProfit object in params* containing the triggerPrice at which the attached take profit order will be triggered
        :param float [params.takeProfit.triggerPrice]: take profit trigger price
        :param dict [params.stopLoss]: *stopLoss object in params* containing the triggerPrice at which the attached stop loss order will be triggered
        :param float [params.stopLoss.triggerPrice]: stop loss trigger price
         *
         * EXCHANGE SPECIFIC PARAMETERS
        :param str [params.cancelClientOrderID]: the user-defined id of the order to be canceled, 1-40 characters, different orders cannot use the same clientOrderID, only supports a query range of 2 hours
        :param str [params.cancelRestrictions]: cancel orders with specified status, NEW: New order, PENDING: Pending order, PARTIALLY_FILLED: Partially filled
        :param str [params.cancelReplaceMode]: STOP_ON_FAILURE - if the cancel order fails, it will not continue to place a new order, ALLOW_FAILURE - regardless of whether the cancel order succeeds or fails, it will continue to place a new order
        :param float [params.quoteOrderQty]: order amount
        :param str [params.newClientOrderId]: custom order id consisting of letters, numbers, and _, 1-40 characters, different orders cannot use the same newClientOrderId.
        :param str [params.positionSide]: *contract only* position direction, required for single position, for both long and short positions only LONG or SHORT can be chosen, defaults to LONG if empty
        :param str [params.reduceOnly]: *contract only* True or False, default=false for single position mode. self parameter is not accepted for both long and short positions mode
        :param float [params.priceRate]: *contract only* for type TRAILING_STOP_Market or TRAILING_TP_SL, Max = 1
        :param str [params.workingType]: *contract only* StopPrice trigger price types, MARK_PRICE(default), CONTRACT_PRICE, or INDEX_PRICE
        :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
        """
        self.load_markets()
        market = self.market(symbol)
        request = self.create_order_request(symbol, type, side, amount, price, params)
        request['cancelOrderId'] = id
        request['cancelReplaceMode'] = 'STOP_ON_FAILURE'
        response = None
        if market['swap']:
            response = self.swapV1PrivatePostTradeCancelReplace(self.extend(request, params))
            #
            #    {
            #        code: '0',
            #        msg: '',
            #        data: {
            #            cancelResult: 'true',
            #            cancelMsg: '',
            #            cancelResponse: {
            #                cancelClientOrderId: '',
            #                cancelOrderId: '1755336244265705472',
            #                symbol: 'SOL-USDT',
            #                orderId: '1755336244265705472',
            #                side: 'SELL',
            #                positionSide: 'SHORT',
            #                type: 'LIMIT',
            #                origQty: '1',
            #                price: '100.000',
            #                executedQty: '0',
            #                avgPrice: '0.000',
            #                cumQuote: '0',
            #                stopPrice: '',
            #                profit: '0.0000',
            #                commission: '0.000000',
            #                status: 'PENDING',
            #                time: '1707339747860',
            #                updateTime: '1707339747860',
            #                clientOrderId: '',
            #                leverage: '20X',
            #                workingType: 'MARK_PRICE',
            #                onlyOnePosition: False,
            #                reduceOnly: False
            #            },
            #            replaceResult: 'true',
            #            replaceMsg: '',
            #            newOrderResponse: {
            #                orderId: '1755338440612995072',
            #                symbol: 'SOL-USDT',
            #                positionSide: 'SHORT',
            #                side: 'SELL',
            #                type: 'LIMIT',
            #                price: '99',
            #                quantity: '2',
            #                stopPrice: '0',
            #                workingType: 'MARK_PRICE',
            #                clientOrderID: '',
            #                timeInForce: 'GTC',
            #                priceRate: '0',
            #                stopLoss: '',
            #                takeProfit: '',
            #                reduceOnly: False
            #            }
            #        }
            #    }
            #
        else:
            response = self.spotV1PrivatePostTradeOrderCancelReplace(self.extend(request, params))
            #
            #    {
            #        code: '0',
            #        msg: '',
            #        debugMsg: '',
            #        data: {
            #            cancelResult: {code: '0', msg: '', result: True},
            #            openResult: {code: '0', msg: '', result: True},
            #            orderOpenResponse: {
            #                symbol: 'SOL-USDT',
            #                orderId: '1755334007697866752',
            #                transactTime: '1707339214620',
            #                price: '99',
            #                stopPrice: '0',
            #                origQty: '0.2',
            #                executedQty: '0',
            #                cummulativeQuoteQty: '0',
            #                status: 'PENDING',
            #                type: 'LIMIT',
            #                side: 'SELL',
            #                clientOrderID: ''
            #            },
            #            orderCancelResponse: {
            #                symbol: 'SOL-USDT',
            #                orderId: '1755117055251480576',
            #                price: '100',
            #                stopPrice: '0',
            #                origQty: '0.2',
            #                executedQty: '0',
            #                cummulativeQuoteQty: '0',
            #                status: 'CANCELED',
            #                type: 'LIMIT',
            #                side: 'SELL'
            #            }
            #        }
            #    }
            #
        data = self.safe_dict(response, 'data')
        return self.parse_order(data, market)

    def fetch_margin_mode(self, symbol: str, params={}) -> MarginMode:
        """
        fetches the margin mode of the trading pair
        :see: https://bingx-api.github.io/docs/#/en-us/swapV2/trade-api.html#Query%20Margin%20Mode
        :param str symbol: unified symbol of the market to fetch the margin mode for
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: a `margin mode structure <https://docs.ccxt.com/#/?id=margin-mode-structure>`
        """
        self.load_markets()
        market = self.market(symbol)
        request: dict = {
            'symbol': market['id'],
        }
        response = self.swapV2PrivateGetTradeMarginType(self.extend(request, params))
        #
        #     {
        #         "code": 0,
        #         "msg": "",
        #         "data": {
        #             "marginType": "CROSSED"
        #         }
        #     }
        #
        data = self.safe_dict(response, 'data', {})
        return self.parse_margin_mode(data, market)

    def parse_margin_mode(self, marginMode, market=None) -> MarginMode:
        marginType = self.safe_string_lower(marginMode, 'marginType')
        marginType = 'cross' if (marginType == 'crossed') else marginType
        return {
            'info': marginMode,
            'symbol': market['symbol'],
            'marginMode': marginType,
        }

    def sign(self, path, section='public', method='GET', params={}, headers=None, body=None):
        type = section[0]
        version = section[1]
        access = section[2]
        isSandbox = self.safe_bool(self.options, 'sandboxMode', False)
        if isSandbox and (type != 'swap'):
            raise NotSupported(self.id + ' does not have a testnet/sandbox URL for ' + type + ' endpoints')
        url = self.implode_hostname(self.urls['api'][type])
        if type == 'spot' and version == 'v3':
            url += '/api'
        else:
            url += '/' + type
        url += '/' + version + '/'
        path = self.implode_params(path, params)
        url += path
        params = self.omit(params, self.extract_params(path))
        params = self.keysort(params)
        if access == 'public':
            params['timestamp'] = self.nonce()
            if params:
                url += '?' + self.urlencode(params)
        elif access == 'private':
            self.check_required_credentials()
            params['timestamp'] = self.nonce()
            parsedParams = self.parse_params(params)
            query = self.urlencode(parsedParams)
            signature = self.hmac(self.encode(self.rawencode(parsedParams)), self.encode(self.secret), hashlib.sha256)
            if params:
                query = '?' + query + '&'
            else:
                query += '?'
            query += 'signature=' + signature
            headers = {
                'X-BX-APIKEY': self.apiKey,
                'X-SOURCE-KEY': self.safe_string(self.options, 'broker', 'CCXT'),
            }
            url += query
        return {'url': url, 'method': method, 'body': body, 'headers': headers}

    def nonce(self):
        return self.milliseconds()

    def set_sandbox_mode(self, enable: bool):
        super(bingx, self).set_sandbox_mode(enable)
        self.options['sandboxMode'] = enable

    def handle_errors(self, httpCode, reason, url, method, headers, body, response, requestHeaders, requestBody):
        if response is None:
            return None  # fallback to default error handler
        #
        #    {
        #        "code": 80014,
        #        "msg": "Invalid parameters, err:Key: 'GetTickerRequest.Symbol' Error:Field validation for "Symbol" failed on the "len=0|endswith=-USDT" tag",
        #        "data": {
        #        }
        #    }
        #
        code = self.safe_string(response, 'code')
        message = self.safe_string(response, 'msg')
        if code is not None and code != '0':
            feedback = self.id + ' ' + body
            self.throw_exactly_matched_exception(self.exceptions['exact'], message, feedback)
            self.throw_exactly_matched_exception(self.exceptions['exact'], code, feedback)
            self.throw_broadly_matched_exception(self.exceptions['broad'], message, feedback)
            raise ExchangeError(feedback)  # unknown message
        return None
