UNPKG

astro-perp-ccxt-dev

Version:

A JavaScript / TypeScript / Python / C# / PHP cryptocurrency trading library with support for 100+ exchanges

9,287 lines 444 kB
'use strict';

var bybit$1 = require('./abstract/bybit.js');
var number = require('./base/functions/number.js');
var errors = require('./base/errors.js');
var Precise = require('./base/Precise.js');
var sha256 = require('./static_dependencies/noble-hashes/sha256.js');
var rsa = require('./base/functions/rsa.js');

// ----------------------------------------------------------------------------
//  ---------------------------------------------------------------------------
/**
 * @class bybit
 * @augments Exchange
 */
class bybit extends bybit$1 {
    describe() {
        return this.deepExtend(super.describe(), {
            'id': 'bybit',
            'name': 'Bybit',
            'countries': ['VG'],
            'version': 'v5',
            'userAgent': undefined,
            'rateLimit': 20,
            'hostname': 'bybit.com',
            'pro': true,
            'certified': true,
            'has': {
                'CORS': true,
                'spot': true,
                'margin': true,
                'swap': true,
                'future': true,
                'option': true,
                'borrowCrossMargin': true,
                'cancelAllOrders': true,
                'cancelAllOrdersAfter': true,
                'cancelOrder': true,
                'cancelOrders': true,
                'cancelOrdersForSymbols': true,
                'closeAllPositions': false,
                'closePosition': false,
                'createConvertTrade': true,
                'createMarketBuyOrderWithCost': true,
                'createMarketSellOrderWithCost': true,
                'createOrder': true,
                'createOrders': true,
                'createOrderWithTakeProfitAndStopLoss': true,
                'createPostOnlyOrder': true,
                'createReduceOnlyOrder': true,
                'createStopLimitOrder': true,
                'createStopLossOrder': true,
                'createStopMarketOrder': true,
                'createStopOrder': true,
                'createTakeProfitOrder': true,
                'createTrailingAmountOrder': true,
                'createTriggerOrder': true,
                'editOrder': true,
                'editOrders': true,
                'fetchBalance': true,
                'fetchBidsAsks': 'emulated',
                'fetchBorrowInterest': false,
                'fetchBorrowRateHistories': false,
                'fetchBorrowRateHistory': false,
                'fetchCanceledAndClosedOrders': true,
                'fetchCanceledOrders': true,
                'fetchClosedOrder': true,
                'fetchClosedOrders': true,
                'fetchConvertCurrencies': true,
                'fetchConvertQuote': true,
                'fetchConvertTrade': true,
                'fetchConvertTradeHistory': true,
                'fetchCrossBorrowRate': true,
                'fetchCrossBorrowRates': false,
                'fetchCurrencies': true,
                'fetchDeposit': false,
                'fetchDepositAddress': true,
                'fetchDepositAddresses': false,
                'fetchDepositAddressesByNetwork': true,
                'fetchDeposits': true,
                'fetchDepositWithdrawFee': 'emulated',
                'fetchDepositWithdrawFees': true,
                'fetchFundingHistory': true,
                'fetchFundingRate': 'emulated',
                'fetchFundingRateHistory': true,
                'fetchFundingRates': true,
                'fetchGreeks': true,
                'fetchIndexOHLCV': true,
                'fetchIsolatedBorrowRate': false,
                'fetchIsolatedBorrowRates': false,
                'fetchLedger': true,
                'fetchLeverage': true,
                'fetchLeverageTiers': true,
                'fetchLongShortRatio': false,
                'fetchLongShortRatioHistory': true,
                'fetchMarginAdjustmentHistory': false,
                'fetchMarketLeverageTiers': true,
                'fetchMarkets': true,
                'fetchMarkOHLCV': true,
                'fetchMyLiquidations': true,
                'fetchMySettlementHistory': true,
                'fetchMyTrades': true,
                'fetchOHLCV': true,
                'fetchOpenInterest': true,
                'fetchOpenInterestHistory': true,
                'fetchOpenOrder': true,
                'fetchOpenOrders': true,
                'fetchOption': true,
                'fetchOptionChain': true,
                'fetchOrder': true,
                'fetchOrderBook': true,
                'fetchOrders': false,
                'fetchOrderTrades': true,
                'fetchPosition': true,
                'fetchPositionHistory': 'emulated',
                'fetchPositions': true,
                'fetchPositionsHistory': true,
                'fetchPremiumIndexOHLCV': true,
                'fetchSettlementHistory': true,
                'fetchTicker': true,
                'fetchTickers': true,
                'fetchTime': true,
                'fetchTrades': true,
                'fetchTradingFee': true,
                'fetchTradingFees': true,
                'fetchTransactions': false,
                'fetchTransfers': true,
                'fetchUnderlyingAssets': false,
                'fetchVolatilityHistory': true,
                'fetchWithdrawals': true,
                'repayCrossMargin': true,
                'sandbox': true,
                'setLeverage': true,
                'setMarginMode': true,
                'setPositionMode': true,
                'transfer': true,
                'withdraw': true,
            },
            'timeframes': {
                '1m': '1',
                '3m': '3',
                '5m': '5',
                '15m': '15',
                '30m': '30',
                '1h': '60',
                '2h': '120',
                '4h': '240',
                '6h': '360',
                '12h': '720',
                '1d': 'D',
                '1w': 'W',
                '1M': 'M',
            },
            'urls': {
                'test': {
                    'spot': 'https://api-testnet.{hostname}',
                    'futures': 'https://api-testnet.{hostname}',
                    'v2': 'https://api-testnet.{hostname}',
                    'public': 'https://api-testnet.{hostname}',
                    'private': 'https://api-testnet.{hostname}',
                },
                'logo': 'https://github.com/user-attachments/assets/97a5d0b3-de10-423d-90e1-6620960025ed',
                'api': {
                    'spot': 'https://api.{hostname}',
                    'futures': 'https://api.{hostname}',
                    'v2': 'https://api.{hostname}',
                    'public': 'https://api.{hostname}',
                    'private': 'https://api.{hostname}',
                },
                'demotrading': {
                    'spot': 'https://api-demo.{hostname}',
                    'futures': 'https://api-demo.{hostname}',
                    'v2': 'https://api-demo.{hostname}',
                    'public': 'https://api-demo.{hostname}',
                    'private': 'https://api-demo.{hostname}',
                },
                'www': 'https://www.bybit.com',
                'doc': [
                    'https://bybit-exchange.github.io/docs/inverse/',
                    'https://bybit-exchange.github.io/docs/linear/',
                    'https://github.com/bybit-exchange',
                ],
                'fees': 'https://help.bybit.com/hc/en-us/articles/360039261154',
                'referral': 'https://www.bybit.com/register?affiliate_id=35953',
            },
            'api': {
                'public': {
                    'get': {
                        // spot
                        'spot/v3/public/symbols': 1,
                        'spot/v3/public/quote/depth': 1,
                        'spot/v3/public/quote/depth/merged': 1,
                        'spot/v3/public/quote/trades': 1,
                        'spot/v3/public/quote/kline': 1,
                        'spot/v3/public/quote/ticker/24hr': 1,
                        'spot/v3/public/quote/ticker/price': 1,
                        'spot/v3/public/quote/ticker/bookTicker': 1,
                        'spot/v3/public/server-time': 1,
                        'spot/v3/public/infos': 1,
                        'spot/v3/public/margin-product-infos': 1,
                        'spot/v3/public/margin-ensure-tokens': 1,
                        // data
                        'v3/public/time': 1,
                        'contract/v3/public/copytrading/symbol/list': 1,
                        // derivative
                        'derivatives/v3/public/order-book/L2': 1,
                        'derivatives/v3/public/kline': 1,
                        'derivatives/v3/public/tickers': 1,
                        'derivatives/v3/public/instruments-info': 1,
                        'derivatives/v3/public/mark-price-kline': 1,
                        'derivatives/v3/public/index-price-kline': 1,
                        'derivatives/v3/public/funding/history-funding-rate': 1,
                        'derivatives/v3/public/risk-limit/list': 1,
                        'derivatives/v3/public/delivery-price': 1,
                        'derivatives/v3/public/recent-trade': 1,
                        'derivatives/v3/public/open-interest': 1,
                        'derivatives/v3/public/insurance': 1,
                        // v5
                        'v5/announcements/index': 5,
                        // market
                        'v5/market/time': 5,
                        'v5/market/kline': 5,
                        'v5/market/mark-price-kline': 5,
                        'v5/market/index-price-kline': 5,
                        'v5/market/premium-index-price-kline': 5,
                        'v5/market/instruments-info': 5,
                        'v5/market/orderbook': 5,
                        'v5/market/tickers': 5,
                        'v5/market/funding/history': 5,
                        'v5/market/recent-trade': 5,
                        'v5/market/open-interest': 5,
                        'v5/market/historical-volatility': 5,
                        'v5/market/insurance': 5,
                        'v5/market/risk-limit': 5,
                        'v5/market/delivery-price': 5,
                        'v5/market/account-ratio': 5,
                        // spot leverage token
                        'v5/spot-lever-token/info': 5,
                        'v5/spot-lever-token/reference': 5,
                        // spot margin trade
                        'v5/spot-margin-trade/data': 5,
                        'v5/spot-margin-trade/collateral': 5,
                        'v5/spot-cross-margin-trade/data': 5,
                        'v5/spot-cross-margin-trade/pledge-token': 5,
                        'v5/spot-cross-margin-trade/borrow-token': 5,
                        // crypto loan
                        'v5/crypto-loan/collateral-data': 5,
                        'v5/crypto-loan/loanable-data': 5,
                        // institutional lending
                        'v5/ins-loan/product-infos': 5,
                        'v5/ins-loan/ensure-tokens-convert': 5,
                        // earn
                        'v5/earn/product': 5,
                    },
                },
                'private': {
                    'get': {
                        'v5/market/instruments-info': 5,
                        // Legacy inverse swap
                        'v2/private/wallet/fund/records': 25,
                        // spot
                        'spot/v3/private/order': 2.5,
                        'spot/v3/private/open-orders': 2.5,
                        'spot/v3/private/history-orders': 2.5,
                        'spot/v3/private/my-trades': 2.5,
                        'spot/v3/private/account': 2.5,
                        'spot/v3/private/reference': 2.5,
                        'spot/v3/private/record': 2.5,
                        'spot/v3/private/cross-margin-orders': 10,
                        'spot/v3/private/cross-margin-account': 10,
                        'spot/v3/private/cross-margin-loan-info': 10,
                        'spot/v3/private/cross-margin-repay-history': 10,
                        'spot/v3/private/margin-loan-infos': 10,
                        'spot/v3/private/margin-repaid-infos': 10,
                        'spot/v3/private/margin-ltv': 10,
                        // account
                        'asset/v3/private/transfer/inter-transfer/list/query': 50,
                        'asset/v3/private/transfer/sub-member/list/query': 50,
                        'asset/v3/private/transfer/sub-member-transfer/list/query': 50,
                        'asset/v3/private/transfer/universal-transfer/list/query': 25,
                        'asset/v3/private/coin-info/query': 25,
                        'asset/v3/private/deposit/address/query': 10,
                        'contract/v3/private/copytrading/order/list': 30,
                        'contract/v3/private/copytrading/position/list': 40,
                        'contract/v3/private/copytrading/wallet/balance': 25,
                        'contract/v3/private/position/limit-info': 25,
                        'contract/v3/private/order/unfilled-orders': 1,
                        'contract/v3/private/order/list': 1,
                        'contract/v3/private/position/list': 1,
                        'contract/v3/private/execution/list': 1,
                        'contract/v3/private/position/closed-pnl': 1,
                        'contract/v3/private/account/wallet/balance': 1,
                        'contract/v3/private/account/fee-rate': 1,
                        'contract/v3/private/account/wallet/fund-records': 1,
                        // derivative
                        'unified/v3/private/order/unfilled-orders': 1,
                        'unified/v3/private/order/list': 1,
                        'unified/v3/private/position/list': 1,
                        'unified/v3/private/execution/list': 1,
                        'unified/v3/private/delivery-record': 1,
                        'unified/v3/private/settlement-record': 1,
                        'unified/v3/private/account/wallet/balance': 1,
                        'unified/v3/private/account/transaction-log': 1,
                        'unified/v3/private/account/borrow-history': 1,
                        'unified/v3/private/account/borrow-rate': 1,
                        'unified/v3/private/account/info': 1,
                        'user/v3/private/frozen-sub-member': 10,
                        'user/v3/private/query-sub-members': 5,
                        'user/v3/private/query-api': 5,
                        'user/v3/private/get-member-type': 1,
                        'asset/v3/private/transfer/transfer-coin/list/query': 50,
                        'asset/v3/private/transfer/account-coin/balance/query': 50,
                        'asset/v3/private/transfer/account-coins/balance/query': 25,
                        'asset/v3/private/transfer/asset-info/query': 50,
                        'asset/v3/public/deposit/allowed-deposit-list/query': 0.17,
                        'asset/v3/private/deposit/record/query': 10,
                        'asset/v3/private/withdraw/record/query': 10,
                        // v5
                        // trade
                        'v5/order/realtime': 5,
                        'v5/order/history': 5,
                        'v5/order/spot-borrow-check': 1,
                        // position
                        'v5/position/list': 5,
                        'v5/execution/list': 5,
                        'v5/position/closed-pnl': 5,
                        'v5/position/move-history': 5,
                        // pre-upgrade
                        'v5/pre-upgrade/order/history': 5,
                        'v5/pre-upgrade/execution/list': 5,
                        'v5/pre-upgrade/position/closed-pnl': 5,
                        'v5/pre-upgrade/account/transaction-log': 5,
                        'v5/pre-upgrade/asset/delivery-record': 5,
                        'v5/pre-upgrade/asset/settlement-record': 5,
                        // account
                        'v5/account/wallet-balance': 1,
                        'v5/account/borrow-history': 1,
                        'v5/account/collateral-info': 1,
                        'v5/asset/coin-greeks': 1,
                        'v5/account/fee-rate': 10,
                        'v5/account/info': 5,
                        'v5/account/transaction-log': 1,
                        'v5/account/contract-transaction-log': 1,
                        'v5/account/smp-group': 1,
                        'v5/account/mmp-state': 5,
                        'v5/account/withdrawal': 5,
                        // asset
                        'v5/asset/exchange/query-coin-list': 0.5,
                        'v5/asset/exchange/convert-result-query': 0.5,
                        'v5/asset/exchange/query-convert-history': 0.5,
                        'v5/asset/exchange/order-record': 5,
                        'v5/asset/delivery-record': 5,
                        'v5/asset/settlement-record': 5,
                        'v5/asset/transfer/query-asset-info': 50,
                        'v5/asset/transfer/query-account-coins-balance': 25,
                        'v5/asset/transfer/query-account-coin-balance': 50,
                        'v5/asset/transfer/query-transfer-coin-list': 50,
                        'v5/asset/transfer/query-inter-transfer-list': 50,
                        'v5/asset/transfer/query-sub-member-list': 50,
                        'v5/asset/transfer/query-universal-transfer-list': 25,
                        'v5/asset/deposit/query-allowed-list': 5,
                        'v5/asset/deposit/query-record': 10,
                        'v5/asset/deposit/query-sub-member-record': 10,
                        'v5/asset/deposit/query-internal-record': 5,
                        'v5/asset/deposit/query-address': 10,
                        'v5/asset/deposit/query-sub-member-address': 10,
                        'v5/asset/coin/query-info': 28,
                        'v5/asset/withdraw/query-record': 10,
                        'v5/asset/withdraw/withdrawable-amount': 5,
                        'v5/asset/withdraw/vasp/list': 5,
                        // user
                        'v5/user/query-sub-members': 5,
                        'v5/user/query-api': 5,
                        'v5/user/sub-apikeys': 5,
                        'v5/user/get-member-type': 5,
                        'v5/user/aff-customer-info': 5,
                        'v5/user/del-submember': 5,
                        'v5/user/submembers': 5,
                        // affilate
                        'v5/affiliate/aff-user-list': 5,
                        // spot leverage token
                        'v5/spot-lever-token/order-record': 1,
                        // spot margin trade
                        'v5/spot-margin-trade/interest-rate-history': 5,
                        'v5/spot-margin-trade/state': 5,
                        'v5/spot-cross-margin-trade/loan-info': 1,
                        'v5/spot-cross-margin-trade/account': 1,
                        'v5/spot-cross-margin-trade/orders': 1,
                        'v5/spot-cross-margin-trade/repay-history': 1,
                        // crypto loan
                        'v5/crypto-loan/borrowable-collateralisable-number': 5,
                        'v5/crypto-loan/ongoing-orders': 5,
                        'v5/crypto-loan/repayment-history': 5,
                        'v5/crypto-loan/borrow-history': 5,
                        'v5/crypto-loan/max-collateral-amount': 5,
                        'v5/crypto-loan/adjustment-history': 5,
                        // institutional lending
                        'v5/ins-loan/product-infos': 5,
                        'v5/ins-loan/ensure-tokens-convert': 5,
                        'v5/ins-loan/loan-order': 5,
                        'v5/ins-loan/repaid-history': 5,
                        'v5/ins-loan/ltv-convert': 5,
                        // c2c lending
                        'v5/lending/info': 5,
                        'v5/lending/history-order': 5,
                        'v5/lending/account': 5,
                        // broker
                        'v5/broker/earning-record': 5,
                        'v5/broker/earnings-info': 5,
                        'v5/broker/account-info': 5,
                        'v5/broker/asset/query-sub-member-deposit-record': 10,
                        // earn
                        'v5/earn/order': 5,
                        'v5/earn/position': 5,
                    },
                    'post': {
                        // spot
                        'spot/v3/private/order': 2.5,
                        'spot/v3/private/cancel-order': 2.5,
                        'spot/v3/private/cancel-orders': 2.5,
                        'spot/v3/private/cancel-orders-by-ids': 2.5,
                        'spot/v3/private/purchase': 2.5,
                        'spot/v3/private/redeem': 2.5,
                        'spot/v3/private/cross-margin-loan': 10,
                        'spot/v3/private/cross-margin-repay': 10,
                        // account
                        'asset/v3/private/transfer/inter-transfer': 150,
                        'asset/v3/private/withdraw/create': 300,
                        'asset/v3/private/withdraw/cancel': 50,
                        'asset/v3/private/transfer/sub-member-transfer': 150,
                        'asset/v3/private/transfer/transfer-sub-member-save': 150,
                        'asset/v3/private/transfer/universal-transfer': 10,
                        'user/v3/private/create-sub-member': 10,
                        'user/v3/private/create-sub-api': 10,
                        'user/v3/private/update-api': 10,
                        'user/v3/private/delete-api': 10,
                        'user/v3/private/update-sub-api': 10,
                        'user/v3/private/delete-sub-api': 10,
                        // contract
                        'contract/v3/private/copytrading/order/create': 30,
                        'contract/v3/private/copytrading/order/cancel': 30,
                        'contract/v3/private/copytrading/order/close': 30,
                        'contract/v3/private/copytrading/position/close': 40,
                        'contract/v3/private/copytrading/position/set-leverage': 40,
                        'contract/v3/private/copytrading/wallet/transfer': 25,
                        'contract/v3/private/copytrading/order/trading-stop': 2.5,
                        'contract/v3/private/order/create': 1,
                        'contract/v3/private/order/cancel': 1,
                        'contract/v3/private/order/cancel-all': 1,
                        'contract/v3/private/order/replace': 1,
                        'contract/v3/private/position/set-auto-add-margin': 1,
                        'contract/v3/private/position/switch-isolated': 1,
                        'contract/v3/private/position/switch-mode': 1,
                        'contract/v3/private/position/switch-tpsl-mode': 1,
                        'contract/v3/private/position/set-leverage': 1,
                        'contract/v3/private/position/trading-stop': 1,
                        'contract/v3/private/position/set-risk-limit': 1,
                        'contract/v3/private/account/setMarginMode': 1,
                        // derivative
                        'unified/v3/private/order/create': 30,
                        'unified/v3/private/order/replace': 30,
                        'unified/v3/private/order/cancel': 30,
                        'unified/v3/private/order/create-batch': 30,
                        'unified/v3/private/order/replace-batch': 30,
                        'unified/v3/private/order/cancel-batch': 30,
                        'unified/v3/private/order/cancel-all': 30,
                        'unified/v3/private/position/set-leverage': 2.5,
                        'unified/v3/private/position/tpsl/switch-mode': 2.5,
                        'unified/v3/private/position/set-risk-limit': 2.5,
                        'unified/v3/private/position/trading-stop': 2.5,
                        'unified/v3/private/account/upgrade-unified-account': 2.5,
                        'unified/v3/private/account/setMarginMode': 2.5,
                        // tax
                        'fht/compliance/tax/v3/private/registertime': 50,
                        'fht/compliance/tax/v3/private/create': 50,
                        'fht/compliance/tax/v3/private/status': 50,
                        'fht/compliance/tax/v3/private/url': 50,
                        // v5
                        // trade
                        'v5/order/create': 2.5,
                        'v5/order/amend': 5,
                        'v5/order/cancel': 2.5,
                        'v5/order/cancel-all': 50,
                        'v5/order/create-batch': 5,
                        'v5/order/amend-batch': 5,
                        'v5/order/cancel-batch': 5,
                        'v5/order/disconnected-cancel-all': 5,
                        // position
                        'v5/position/set-leverage': 5,
                        'v5/position/switch-isolated': 5,
                        'v5/position/set-tpsl-mode': 5,
                        'v5/position/switch-mode': 5,
                        'v5/position/set-risk-limit': 5,
                        'v5/position/trading-stop': 5,
                        'v5/position/set-auto-add-margin': 5,
                        'v5/position/add-margin': 5,
                        'v5/position/move-positions': 5,
                        'v5/position/confirm-pending-mmr': 5,
                        // account
                        'v5/account/upgrade-to-uta': 5,
                        'v5/account/quick-repayment': 5,
                        'v5/account/set-margin-mode': 5,
                        'v5/account/set-hedging-mode': 5,
                        'v5/account/mmp-modify': 5,
                        'v5/account/mmp-reset': 5,
                        // asset
                        'v5/asset/exchange/quote-apply': 1,
                        'v5/asset/exchange/convert-execute': 1,
                        'v5/asset/transfer/inter-transfer': 50,
                        'v5/asset/transfer/save-transfer-sub-member': 150,
                        'v5/asset/transfer/universal-transfer': 10,
                        'v5/asset/deposit/deposit-to-account': 5,
                        'v5/asset/withdraw/create': 50,
                        'v5/asset/withdraw/cancel': 50,
                        // user
                        'v5/user/create-sub-member': 10,
                        'v5/user/create-sub-api': 10,
                        'v5/user/frozen-sub-member': 10,
                        'v5/user/update-api': 10,
                        'v5/user/update-sub-api': 10,
                        'v5/user/delete-api': 10,
                        'v5/user/delete-sub-api': 10,
                        // spot leverage token
                        'v5/spot-lever-token/purchase': 2.5,
                        'v5/spot-lever-token/redeem': 2.5,
                        // spot margin trade
                        'v5/spot-margin-trade/switch-mode': 5,
                        'v5/spot-margin-trade/set-leverage': 5,
                        'v5/spot-cross-margin-trade/loan': 2.5,
                        'v5/spot-cross-margin-trade/repay': 2.5,
                        'v5/spot-cross-margin-trade/switch': 2.5,
                        // crypto loan
                        'v5/crypto-loan/borrow': 5,
                        'v5/crypto-loan/repay': 5,
                        'v5/crypto-loan/adjust-ltv': 5,
                        // institutional lending
                        'v5/ins-loan/association-uid': 5,
                        // c2c lending
                        'v5/lending/purchase': 5,
                        'v5/lending/redeem': 5,
                        'v5/lending/redeem-cancel': 5,
                        'v5/account/set-collateral-switch': 5,
                        'v5/account/set-collateral-switch-batch': 5,
                        // demo trading
                        'v5/account/demo-apply-money': 5,
                        // broker
                        'v5/broker/award/info': 5,
                        'v5/broker/award/distribute-award': 5,
                        'v5/broker/award/distribution-record': 5,
                        // earn
                        'v5/earn/place-order': 5,
                    },
                },
            },
            'httpExceptions': {
                '403': errors.RateLimitExceeded, // Forbidden -- You request too many times
            },
            'exceptions': {
                // Uncodumented explanation of error strings:
                // - oc_diff: order cost needed to place this order
                // - new_oc: total order cost of open orders including the order you are trying to open
                // - ob: order balance - the total cost of current open orders
                // - ab: available balance
                'exact': {
                    '-10009': errors.BadRequest,
                    '-1004': errors.BadRequest,
                    '-1021': errors.BadRequest,
                    '-1103': errors.BadRequest,
                    '-1140': errors.InvalidOrder,
                    '-1197': errors.InvalidOrder,
                    '-2013': errors.InvalidOrder,
                    '-2015': errors.AuthenticationError,
                    '-6017': errors.BadRequest,
                    '-6025': errors.BadRequest,
                    '-6029': errors.BadRequest,
                    '5004': errors.ExchangeError,
                    '7001': errors.BadRequest,
                    '10001': errors.BadRequest,
                    '10002': errors.InvalidNonce,
                    '10003': errors.AuthenticationError,
                    '10004': errors.AuthenticationError,
                    '10005': errors.PermissionDenied,
                    '10006': errors.RateLimitExceeded,
                    '10007': errors.AuthenticationError,
                    '10008': errors.AccountSuspended,
                    '10009': errors.AuthenticationError,
                    '10010': errors.PermissionDenied,
                    '10014': errors.BadRequest,
                    '10016': errors.ExchangeError,
                    '10017': errors.BadRequest,
                    '10018': errors.RateLimitExceeded,
                    '10020': errors.PermissionDenied,
                    '10024': errors.PermissionDenied,
                    '10027': errors.PermissionDenied,
                    '10028': errors.PermissionDenied,
                    '10029': errors.PermissionDenied,
                    '12137': errors.InvalidOrder,
                    '12201': errors.BadRequest,
                    '12141': errors.BadRequest,
                    '100028': errors.PermissionDenied,
                    '110001': errors.OrderNotFound,
                    '110003': errors.InvalidOrder,
                    '110004': errors.InsufficientFunds,
                    '110005': errors.InvalidOrder,
                    '110006': errors.InsufficientFunds,
                    '110007': errors.InsufficientFunds,
                    '110008': errors.InvalidOrder,
                    '110009': errors.InvalidOrder,
                    '110010': errors.InvalidOrder,
                    '110011': errors.InvalidOrder,
                    '110012': errors.InsufficientFunds,
                    '110013': errors.BadRequest,
                    '110014': errors.InsufficientFunds,
                    '110015': errors.BadRequest,
                    '110016': errors.InvalidOrder,
                    '110017': errors.InvalidOrder,
                    '110018': errors.BadRequest,
                    '110019': errors.InvalidOrder,
                    '110020': errors.InvalidOrder,
                    '110021': errors.InvalidOrder,
                    '110022': errors.InvalidOrder,
                    '110023': errors.InvalidOrder,
                    '110024': errors.BadRequest,
                    '110025': errors.NoChange,
                    '110026': errors.MarginModeAlreadySet,
                    '110027': errors.NoChange,
                    '110028': errors.BadRequest,
                    '110029': errors.BadRequest,
                    '110030': errors.InvalidOrder,
                    '110031': errors.InvalidOrder,
                    '110032': errors.InvalidOrder,
                    '110033': errors.InvalidOrder,
                    '110034': errors.InvalidOrder,
                    '110035': errors.InvalidOrder,
                    '110036': errors.InvalidOrder,
                    '110037': errors.InvalidOrder,
                    '110038': errors.InvalidOrder,
                    '110039': errors.InvalidOrder,
                    '110040': errors.InvalidOrder,
                    '110041': errors.InvalidOrder,
                    '110042': errors.InvalidOrder,
                    '110043': errors.BadRequest,
                    '110044': errors.InsufficientFunds,
                    '110045': errors.InsufficientFunds,
                    '110046': errors.BadRequest,
                    '110047': errors.BadRequest,
                    '110048': errors.BadRequest,
                    '110049': errors.BadRequest,
                    '110050': errors.BadRequest,
                    '110051': errors.InsufficientFunds,
                    '110052': errors.InsufficientFunds,
                    '110053': errors.InsufficientFunds,
                    '110054': errors.InvalidOrder,
                    '110055': errors.InvalidOrder,
                    '110056': errors.InvalidOrder,
                    '110057': errors.InvalidOrder,
                    '110058': errors.InvalidOrder,
                    '110059': errors.InvalidOrder,
                    '110060': errors.BadRequest,
                    '110061': errors.BadRequest,
                    '110062': errors.BadRequest,
                    '110063': errors.ExchangeError,
                    '110064': errors.InvalidOrder,
                    '110065': errors.PermissionDenied,
                    '110066': errors.ExchangeError,
                    '110067': errors.PermissionDenied,
                    '110068': errors.PermissionDenied,
                    '110069': errors.PermissionDenied,
                    '110070': errors.InvalidOrder,
                    '110071': errors.ExchangeError,
                    '110072': errors.InvalidOrder,
                    '110073': errors.ExchangeError,
                    '110092': errors.InvalidOrder,
                    '110093': errors.InvalidOrder,
                    '110094': errors.InvalidOrder,
                    '130006': errors.InvalidOrder,
                    '130021': errors.InsufficientFunds,
                    '130074': errors.InvalidOrder,
                    '131001': errors.InsufficientFunds,
                    '131084': errors.ExchangeError,
                    '131200': errors.ExchangeError,
                    '131201': errors.ExchangeError,
                    '131202': errors.BadRequest,
                    '131203': errors.BadRequest,
                    '131204': errors.BadRequest,
                    '131205': errors.BadRequest,
                    '131206': errors.ExchangeError,
                    '131207': errors.BadRequest,
                    '131208': errors.ExchangeError,
                    '131209': errors.BadRequest,
                    '131210': errors.BadRequest,
                    '131211': errors.BadRequest,
                    '131212': errors.InsufficientFunds,
                    '131213': errors.BadRequest,
                    '131214': errors.BadRequest,
                    '131215': errors.BadRequest,
                    '131216': errors.ExchangeError,
                    '131217': errors.ExchangeError,
                    '131231': errors.NotSupported,
                    '131232': errors.NotSupported,
                    '131002': errors.BadRequest,
                    '131003': errors.ExchangeError,
                    '131004': errors.AuthenticationError,
                    '131085': errors.InsufficientFunds,
                    '131086': errors.BadRequest,
                    '131088': errors.BadRequest,
                    '131089': errors.BadRequest,
                    '131090': errors.ExchangeError,
                    '131091': errors.ExchangeError,
                    '131092': errors.ExchangeError,
                    '131093': errors.ExchangeError,
                    '131094': errors.BadRequest,
                    '131095': errors.BadRequest,
                    '131096': errors.BadRequest,
                    '131097': errors.ExchangeError,
                    '131098': errors.ExchangeError,
                    '131099': errors.ExchangeError,
                    '140001': errors.OrderNotFound,
                    '140003': errors.InvalidOrder,
                    '140004': errors.InsufficientFunds,
                    '140005': errors.InvalidOrder,
                    '140006': errors.InsufficientFunds,
                    '140007': errors.InsufficientFunds,
                    '140008': errors.InvalidOrder,
                    '140009': errors.InvalidOrder,
                    '140010': errors.InvalidOrder,
                    '140011': errors.InvalidOrder,
                    '140012': errors.InsufficientFunds,
                    '140013': errors.BadRequest,
                    '140014': errors.InsufficientFunds,
                    '140015': errors.InvalidOrder,
                    '140016': errors.InvalidOrder,
                    '140017': errors.InvalidOrder,
                    '140018': errors.BadRequest,
                    '140019': errors.InvalidOrder,
                    '140020': errors.InvalidOrder,
                    '140021': errors.InvalidOrder,
                    '140022': errors.InvalidOrder,
                    '140023': errors.InvalidOrder,
                    '140024': errors.BadRequest,
                    '140025': errors.BadRequest,
                    '140026': errors.BadRequest,
                    '140027': errors.BadRequest,
                    '140028': errors.InvalidOrder,
                    '140029': errors.BadRequest,
                    '140030': errors.InvalidOrder,
                    '140031': errors.BadRequest,
                    '140032': errors.InvalidOrder,
                    '140033': errors.InvalidOrder,
                    '140034': errors.InvalidOrder,
                    '140035': errors.InvalidOrder,
                    '140036': errors.BadRequest,
                    '140037': errors.InvalidOrder,
                    '140038': errors.BadRequest,
                    '140039': errors.BadRequest,
                    '140040': errors.InvalidOrder,
                    '140041': errors.InvalidOrder,
                    '140042': errors.InvalidOrder,
                    '140043': errors.BadRequest,
                    '140044': errors.InsufficientFunds,
                    '140045': errors.InsufficientFunds,
                    '140046': errors.BadRequest,
                    '140047': errors.BadRequest,
                    '140048': errors.BadRequest,
                    '140049': errors.BadRequest,
                    '140050': errors.InvalidOrder,
                    '140051': errors.InsufficientFunds,
                    '140052': errors.InsufficientFunds,
                    '140053': errors.InsufficientFunds,
                    '140054': errors.InvalidOrder,
                    '140055': errors.InvalidOrder,
                    '140056': errors.InvalidOrder,
                    '140057': errors.InvalidOrder,
                    '140058': errors.InvalidOrder,
                    '140059': errors.InvalidOrder,
                    '140060': errors.BadRequest,
                    '140061': errors.BadRequest,
                    '140062': errors.BadRequest,
                    '140063': errors.ExchangeError,
                    '140064': errors.InvalidOrder,
                    '140065': errors.PermissionDenied,
                    '140066': errors.ExchangeError,
                    '140067': errors.PermissionDenied,
                    '140068': errors.PermissionDenied,
                    '140069': errors.PermissionDenied,
                    '140070': errors.InvalidOrder,
                    '170001': errors.ExchangeError,
                    '170005': errors.InvalidOrder,
                    '170007': errors.RequestTimeout,
                    '170010': errors.InvalidOrder,
                    '170011': errors.InvalidOrder,
                    '170019': errors.InvalidOrder,
                    '170031': errors.ExchangeError,
                    '170032': errors.ExchangeError,
                    '170033': errors.InsufficientFunds,
                    '170034': errors.InsufficientFunds,
                    '170035': errors.BadRequest,
                    '170036': errors.BadRequest,
                    '170037': errors.BadRequest,
                    '170105': errors.BadRequest,
                    '170115': errors.InvalidOrder,
                    '170116': errors.InvalidOrder,
                    '170117': errors.InvalidOrder,
                    '170121': errors.InvalidOrder,
                    '170124': errors.InvalidOrder,
                    '170130': errors.BadRequest,
                    '170131': errors.InsufficientFunds,
                    '170132': errors.InvalidOrder,
                    '170133': errors.InvalidOrder,
                    '170134': errors.InvalidOrder,
                    '170135': errors.InvalidOrder,
                    '170136': errors.InvalidOrder,
                    '170137': errors.InvalidOrder,
                    '170139': errors.InvalidOrder,
                    '170140': errors.InvalidOrder,
                    '170141': errors.InvalidOrder,
                    '170142': errors.InvalidOrder,
                    '170143': errors.InvalidOrder,
                    '170144': errors.InvalidOrder,
                    '170145': errors.InvalidOrder,
                    '170146': errors.InvalidOrder,
                    '170147': errors.InvalidOrder,
                    '170148': errors.InvalidOrder,
                    '170149': errors.ExchangeError,
                    '170150': errors.ExchangeError,
                    '170151': errors.InvalidOrder,
                    '170157': errors.InvalidOrder,
                    '170159': errors.InvalidOrder,
                    '170190': errors.InvalidOrder,
                    '170191': errors.InvalidOrder,
                    '170192': errors.InvalidOrder,
                    '170193': errors.InvalidOrder,
                    '170194': errors.InvalidOrder,
                    '170195': errors.InvalidOrder,
                    '170196': errors.InvalidOrder,
                    '170197': errors.InvalidOrder,
                    '170198': errors.InvalidOrder,
                    '170199': errors.InvalidOrder,
                    '170200': errors.InvalidOrder,
                    '170201': errors.PermissionDenied,
                    '170202': errors.InvalidOrder,
                    '170203': errors.InvalidOrder,
                    '170204': errors.InvalidOrder,
                    '170206': errors.InvalidOrder,
                    '170210': errors.InvalidOrder,
                    '170213': errors.OrderNotFound,
                    '170217': errors.InvalidOrder,
                    '170218': errors.InvalidOrder,
                    '170221': errors.BadRequest,
                    '170222': errors.RateLimitExceeded,
                    '170223': errors.InsufficientFunds,
                    '170224': errors.PermissionDenied,
                    '170226': errors.InsufficientFunds,
                    '170227': errors.ExchangeError,
                    '170228': errors.InvalidOrder,
                    '170229': errors.InvalidOrder,
                    '170234': errors.ExchangeError,
                    '170241': errors.ManualInteractionNeeded,
                    '175000': errors.InvalidOrder,
                    '175001': errors.InvalidOrder,
                    '175002': errors.InvalidOrder,
                    '175003': errors.InsufficientFunds,
                    '175004': errors.InvalidOrder,
                    '175005': errors.InvalidOrder,
                    '175006': errors.InsufficientFunds,
                    '175007': errors.InvalidOrder,
                    '175008': errors.InvalidOrder,
                    '175009': errors.InvalidOrder,
                    '175010': errors.PermissionDenied,
                    '175012': errors.InvalidOrder,
                    '175013': errors.InvalidOrder,
                    '175014': errors.InvalidOrder,
                    '175015': errors.InvalidOrder,
                    '175016': errors.InvalidOrder,
                    '175017': errors.InvalidOrder,
                    '175027': errors.ExchangeError,
                    '176002': errors.BadRequest,
                    '176004': errors.BadRequest,
                    '176003': errors.BadRequest,
                    '176006': errors.BadRequest,
                    '176005': errors.BadRequest,
                    '176008': errors.BadRequest,
                    '176007': errors.BadRequest,
                    '176010': errors.BadRequest,
                    '176009': errors.BadRequest,
                    '176012': errors.BadRequest,
                    '176011': errors.BadRequest,
                    '176014': errors.BadRequest,
                    '176013': errors.BadRequest,
                    '176015': errors.InsufficientFunds,
                    '176016': errors.BadRequest,
                    '176017': errors.BadRequest,
                    '176018': errors.BadRequest,
                    '176019': errors.BadRequest,
                    '176020': errors.BadRequest,
                    '176021': errors.BadRequest,
                    '176022': errors.BadRequest,
                    '176023': errors.BadRequest,
                    '176024': errors.BadRequest,
                    '176025': errors.BadRequest,
                    '176026': errors.BadRequest,
                    '176027': errors.BadRequest,
                    '176028': errors.BadRequest,
                    '176029': errors.BadRequest,
                    '176030': errors.BadRequest,
                    '176031': errors.BadRequest,
                    '176034': errors.BadRequest,
                    '176035': errors.PermissionDenied,
                    '176036': errors.PermissionDenied,
                    '176037': errors.PermissionDenied,
                    '176038': errors.BadRequest,
                    '176039': errors.BadRequest,
                    '176040': errors.BadRequest,
                    '181000': errors.BadRequest,
                    '181001': errors.BadRequest,
                    '181002': errors.InvalidOrder,
                    '181003': errors.InvalidOrder,
                    '181004': errors.InvalidOrder,
                    '182000': errors.InvalidOrder,
                    '181017': errors.BadRequest,
                    '20001': errors.OrderNotFound,
                    '20003': errors.InvalidOrder,
                    '20004': errors.InvalidOrder,
                    '20005': errors.InvalidOrder,
                    '20006': errors.InvalidOrder,
                    '20007': errors.InvalidOrder,
                    '20008': errors.InvalidOrder,
                    '20009': errors.InvalidOrder,
                    '20010': errors.InvalidOrder,
                    '20011': errors.InvalidOrder,
                    '20012': errors.InvalidOrder,
                    '20013': errors.InvalidOrder,
                    '20014': errors.InvalidOrder,
                    '20015': errors.InvalidOrder,
                    '20016': errors.InvalidOrder,
                    '20017': errors.InvalidOrder,
                    '20018': errors.InvalidOrder,
                    '20019': errors.InvalidOrder,
                    '20020': errors.InvalidOrder,
                    '20021': errors.InvalidOrder,
                    '20022': errors.BadRequest,
                    '20023': errors.BadRequest,
                    '20031': errors.BadRequest,
                    '20070': errors.BadRequest,
                    '20071': errors.BadRequest,
                    '20084': errors.BadRequest,
                    '30001': errors.BadRequest,
                    '30003': errors.InvalidOrder,
                    '30004': errors.InvalidOrder,
                    '30005': errors.InvalidOrder,
                    '30007': errors.InvalidOrder,
                    '30008': errors.InvalidOrder,
                    '30009': errors.ExchangeError,
                    '30010': errors.InsufficientFunds,
                    '30011': errors.PermissionDenied,
                    '30012': errors.PermissionDenied,
                    '30013': errors.PermissionDenied,
                    '30014': errors.InvalidOrder,
                    '30015': errors.InvalidOrder,
                    '30016': errors.ExchangeError,
                    '30017': errors.InvalidOrder,
                    '30018': errors.InvalidOrder,
                    '30019': errors.InvalidOrder,
                    '30020': errors.InvalidOrder,
                    '30021': errors.InvalidOrder,
                    '30022': errors.InvalidOrder,
                    '30023': errors.InvalidOrder,
                    '30024': errors.InvalidOrder,
                    '30025': errors.InvalidOrder,
                    '30026': errors.InvalidOrder,
                    '30027': errors.InvalidOrder,
                    '30028': errors.InvalidOrder,
                    '30029': errors.InvalidOrder,
                    '30030': errors.InvalidOrder,
                    '30031': errors.InsufficientFunds,
                    '30032': errors.InvalidOrder,
                    '30033': errors.RateLimitExceeded,
                    '30034': errors.OrderNotFound,
                    '30035': errors.RateLimitExceeded,
                    '30036': errors.ExchangeError,
                    '30037': errors.InvalidOrder,
                    '30041': errors.ExchangeError,
                    '30042': errors.InsufficientFunds,
                    '30043': errors.InvalidOrder,
                    '30044': errors.InvalidOrder,
                    '30045': errors.InvalidOrder,
                    '30049': errors.InsufficientFunds,
                    '30050': errors.ExchangeError,
                    '30051': errors.ExchangeError,
                    '30052': errors.ExchangeError,
                    '30054': errors.ExchangeError,
                    '30057': errors.ExchangeError,
                    '30063': errors.ExchangeError,
                    '30067': errors.InsufficientFunds,
                    '30068': errors.ExchangeError,
                    '30074': errors.InvalidOrder,
                    '30075': errors.InvalidOrder,
                    '30078': errors.ExchangeError,
                    // '30084': BadRequest, // Isolated not modified, see handleErrors below
                    '33004': errors.AuthenticationError,
                    '34026': errors.ExchangeError,
                    '34036': errors.BadRequest,
                    '35015': errors.BadRequest,
                    '340099': errors.ExchangeError,
                    '3400045': errors.ExchangeError,
                    '3100116': errors.BadRequest,
                    '3100198': errors.BadRequest,
                    '3200300': errors.InsufficientFunds, // {"retCode":3200300,"retMsg":"Insufficient margin balance.","result":null,"retExtMap":{}}
                },
                'broad': {
                    'Not supported symbols': errors.BadSymbol,
                    'Request timeout': errors.RequestTimeout,
                    'unknown orderInfo': errors.OrderNotFound,
                    'invalid api_key': errors.AuthenticationError,
                    // the below two issues are caused as described: issues/9149#issuecomment-1146559498, when response is such:  {"ret_code":130021,"ret_msg":"oc_diff[1707966351], new_oc[1707966351] with ob[....]+AB[....]","ext_code":"","ext_info":"","result":null,"time_now":"1658395300.872766","rate_limit_status":99,"rate_limit_reset_ms":1658395300855,"rate_limit":100}
                    'oc_diff': errors.InsufficientFunds,
                    'new_oc': errors.InsufficientFunds,
                    'openapi sign params error!': errors.AuthenticationError, // {"retCode":10001,"retMsg":"empty value: apiTimestamp[] apiKey[] apiSignature[xxxxxxxxxxxxxxxxxxxxxxx]: openapi sign params error!","result":null,"retExtInfo":null,"time":1664789597123}
                },
            },
            'precisionMode': number.TICK_SIZE,
            'options': {
                'usePrivateInstrumentsInfo': false,
                'enableDemoTrading': false,
                'fetchMarkets': ['spot', 'linear', 'inverse', 'option'],
                'enableUnifiedMargin': undefined,
                'enableUnifiedAccount': undefined,
                'unifiedMarginStatus': undefined,
                'createMarketBuyOrderRequiresPrice': false,
                'createUnifiedMarginAccount': false,
                'defaultType': 'swap',
                'defaultSubType': 'linear',
                'defaultSettle': 'USDT',
                'code': 'BTC',
                'recvWindow': 5 * 1000,
                'timeDifference': 0,
                'adjustForTimeDifference': false,
                'loadAllOptions': false,
                'loadExpiredOptions': false,
                'brokerId': 'CCXT',
                'accountsByType': {
                    'spot': 'SPOT',
                    'margin': 'SPOT',
                    'future': 'CONTRACT',
                    'swap': 'CONTRACT',
                    'option': 'OPTION',
                    'investment': 'INVESTMENT',
                    'unified': 'UNIFIED',
                    'funding': 'FUND',
                    'fund': 'FUND',
                    'contract': 'CONTRACT',
                },
                'accountsById': {
                    'SPOT': 'spot',
                    'MARGIN': 'spot',
                    'CONTRACT': 'contract',
                    'OPTION': 'option',
                    'INVESTMENT': 'investment',
                    'UNIFIED': 'unified',
                    'FUND': 'fund',
                },
                'networks': {
                    'ERC20': 'ETH',
                    'TRC20': 'TRX',
                    'BEP20': 'BSC',
                    'SOL': 'SOL',
                    'ACA': 'ACA',
                    'ADA': 'ADA',
                    'ALGO': 'ALGO',
                    'APT': 'APTOS',
                    'AR': 'AR',
                    'ARBONE': 'ARBI',
                    'AVAXC': 'CAVAX',
                    'AVAXX': 'XAVAX',
                    'ATOM': 'ATOM',
                    'BCH': 'BCH',
                    'BEP2': 'BNB',
                    'CHZ': 'CHZ',
                    'DCR': 'DCR',
                    'DGB': 'DGB',
                    'DOGE': 'DOGE',
                    'DOT': 'DOT',
                    'EGLD': 'EGLD',
                    'EOS': 'EOS',
                    'ETC': 'ETC',
                    'ETHF': 'ETHF',
                    'ETHW': 'ETHW',
                    'FIL': 'FIL',
                    'STEP': 'FITFI',
                    'FLOW': 'FLOW',
                    'FTM': 'FTM',
                    'GLMR': 'GLMR',
                    'HBAR': 'HBAR',
                    'HNT': 'HNT',
                    'ICP': 'ICP',
                    'ICX': 'ICX',
                    'KDA': 'KDA',
                    'KLAY': 'KLAY',
                    'KMA': 'KMA',
                    'KSM': 'KSM',
                    'LTC': 'LTC',
                    // 'TERRA': 'LUNANEW',
                    // 'TERRACLASSIC': 'LUNA',
                    'MATIC': 'MATIC',
                    'MINA': 'MINA',
                    'MOVR': 'MOVR',
                    'NEAR': 'NEAR',
                    'NEM': 'NEM',
                    'OASYS': 'OAS',
                    'OASIS': 'ROSE',
                    'OMNI': 'OMNI',
                    'ONE': 'ONE',
                    'OPTIMISM': 'OP',
                    'POKT': 'POKT',
                    'QTUM': 'QTUM',
                    'RVN': 'RVN',
                    'SC': 'SC',
                    'SCRT': 'SCRT',
                    'STX': 'STX',
                    'THETA': 'THETA',
                    'TON': 'TON',
                    'WAVES': 'WAVES',
                    'WAX': 'WAXP',
                    'XDC': 'XDC',
                    'XEC': 'XEC',
                    'XLM': 'XLM',
                    'XRP': 'XRP',
                    'XTZ': 'XTZ',
                    'XYM': 'XYM',
                    'ZEN': 'ZEN',
                    'ZIL': 'ZIL',
                    'ZKSYNC': 'ZKSYNC',
                    // todo: uncomment after consensus
                    // 'CADUCEUS': 'CMP',
                    // 'KON': 'KON', // konpay, "konchain"
                    // 'AURORA': 'AURORA',
                    // 'BITCOINGOLD': 'BTG',
                },
                'networksById': {
                    'ETH': 'ERC20',
                    'TRX': 'TRC20',
                    'BSC': 'BEP20',
                    'OMNI': 'OMNI',
                    'SPL': 'SOL',
                },
                'defaultNetwork': 'ERC20',
                'defaultNetworks': {
                    'USDT': 'TRC20',
                },
                'intervals': {
                    '5m': '5min',
                    '15m': '15min',
                    '30m': '30min',
                    '1h': '1h',
                    '4h': '4h',
                    '1d': '1d',
                },
            },
            'features': {
                'default': {
                    'sandbox': true,
                    'createOrder': {
                        'marginMode': false,
                        'triggerPrice': true,
                        'triggerPriceType': {
                            'last': true,
                            'mark': true,
                            'index': true,
                        },
                        'triggerDirection': true,
                        'stopLossPrice': true,
                        'takeProfitPrice': true,
                        'attachedStopLossTakeProfit': {
                            'triggerPriceType': {
                                'last': true,
                                'mark': true,
                                'index': true,
                            },
                            'price': true,
                        },
                        'timeInForce': {
                            'IOC': true,
                            'FOK': true,
                            'PO': true,
                            'GTD': false,
                        },
                        'hedged': true,
                        'selfTradePrevention': true,
                        'trailing': true,
                        'iceberg': false,
                        'leverage': false,
                        'marketBuyRequiresPrice': false,
                        'marketBuyByCost': true,
                    },
                    'createOrders': {
                        'max': 10,
                    },
                    'fetchMyTrades': {
                        'marginMode': false,
                        'limit': 100,
                        'daysBack': 365 * 2,
                        'untilDays': 7,
                        'symbolRequired': false,
                    },
                    'fetchOrder': {
                        'marginMode': false,
                        'trigger': true,
                        'trailing': false,
                        'symbolRequired': true,
                    },
                    'fetchOpenOrders': {
                        'marginMode': false,
                        'limit': 50,
                        'trigger': true,
                        'trailing': false,
                        'symbolRequired': false,
                    },
                    'fetchOrders': undefined,
                    'fetchClosedOrders': {
                        'marginMode': false,
                        'limit': 50,
                        'daysBack': 365 * 2,
                        'daysBackCanceled': 1,
                        'untilDays': 7,
                        'trigger': true,
                        'trailing': false,
                        'symbolRequired': false,
                    },
                    'fetchOHLCV': {
                        'limit': 1000,
                    },
                    'editOrders': {
                        'max': 10,
                    },
                },
                'spot': {
                    'extends': 'default',
                    'createOrder': {
                        'triggerPriceType': undefined,
                        'triggerDirection': false,
                        'attachedStopLossTakeProfit': {
                            'triggerPriceType': undefined,
                            'price': true,
                        },
                        'marketBuyRequiresPrice': true,
                    },
                },
                'swap': {
                    'linear': {
                        'extends': 'default',
                    },
                    'inverse': {
                        'extends': 'default',
                    },
                },
                'future': {
                    'linear': {
                        'extends': 'default',
                    },
                    'inverse': {
                        'extends': 'default',
                    },
                },
            },
            'fees': {
                'trading': {
                    'feeSide': 'get',
                    'tierBased': true,
                    'percentage': true,
                    'taker': 0.00075,
                    'maker': 0.0001,
                },
                'funding': {
                    'tierBased': false,
                    'percentage': false,
                    'withdraw': {},
                    'deposit': {},
                },
            },
        });
    }
    enableDemoTrading(enable) {
        /**
         * @method
         * @name bybit#enableDemoTrading
         * @description enables or disables demo trading mode
         * @see https://bybit-exchange.github.io/docs/v5/demo
         * @param {boolean} [enable] true if demo trading should be enabled, false otherwise
         */
        if (this.isSandboxModeEnabled) {
            throw new errors.NotSupported(this.id + ' demo trading does not support in sandbox environment');
        }
        // enable demo trading in bybit, see: https://bybit-exchange.github.io/docs/v5/demo
        if (enable) {
            this.urls['apiBackupDemoTrading'] = this.urls['api'];
            this.urls['api'] = this.urls['demotrading'];
        }
        else if ('apiBackupDemoTrading' in this.urls) {
            this.urls['api'] = this.urls['apiBackupDemoTrading'];
            const newUrls = this.omit(this.urls, 'apiBackupDemoTrading');
            this.urls = newUrls;
        }
        this.options['enableDemoTrading'] = enable;
    }
    nonce() {
        return this.milliseconds() - this.options['timeDifference'];
    }
    addPaginationCursorToResult(response) {
        const result = this.safeDict(response, 'result', {});
        const data = this.safeListN(result, ['list', 'rows', 'data', 'dataList'], []);
        const paginationCursor = this.safeString2(result, 'nextPageCursor', 'cursor');
        const dataLength = data.length;
        if ((paginationCursor !== undefined) && (dataLength > 0)) {
            const first = data[0];
            first['nextPageCursor'] = paginationCursor;
            data[0] = first;
        }
        return data;
    }
    /**
     * @method
     * @name bybit#isUnifiedEnabled
     * @see https://bybit-exchange.github.io/docs/v5/user/apikey-info#http-request
     * @see https://bybit-exchange.github.io/docs/v5/account/account-info
     * @description returns [enableUnifiedMargin, enableUnifiedAccount] so the user can check if unified account is enabled
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {any} [enableUnifiedMargin, enableUnifiedAccount]
     */
    async isUnifiedEnabled(params = {}) {
        // The API key of user id must own one of permissions will be allowed to call following API endpoints:
        // SUB UID: "Account Transfer"
        // MASTER UID: "Account Transfer", "Subaccount Transfer", "Withdrawal"
        const enableUnifiedMargin = this.safeBool(this.options, 'enableUnifiedMargin');
        const enableUnifiedAccount = this.safeBool(this.options, 'enableUnifiedAccount');
        if (enableUnifiedMargin === undefined || enableUnifiedAccount === undefined) {
            if (this.options['enableDemoTrading']) {
                // info endpoint is not available in demo trading
                // so we're assuming UTA is enabled
                this.options['enableUnifiedMargin'] = false;
                this.options['enableUnifiedAccount'] = true;
                this.options['unifiedMarginStatus'] = 6;
                return [this.options['enableUnifiedMargin'], this.options['enableUnifiedAccount']];
            }
            const rawPromises = [this.privateGetV5UserQueryApi(params), this.privateGetV5AccountInfo(params)];
            const promises = await Promise.all(rawPromises);
            const response = promises[0];
            const accountInfo = promises[1];
            //
            //     {
            //         "retCode": 0,
            //         "retMsg": "",
            //         "result": {
            //             "id": "13770661",
            //             "note": "XXXXXX",
            //             "apiKey": "XXXXXX",
            //             "readOnly": 0,
            //             "secret": "",
            //             "permissions": {
            //                 "ContractTrade": [...],
            //                 "Spot": [...],
            //                 "Wallet": [...],
            //                 "Options": [...],
            //                 "Derivatives": [...],
            //                 "CopyTrading": [...],
            //                 "BlockTrade": [...],
            //                 "Exchange": [...],
            //                 "NFT": [...],
            //             },
            //             "ips": [...],
            //             "type": 1,
            //             "deadlineDay": 83,
            //             "expiredAt": "2023-05-15T03:21:05Z",
            //             "createdAt": "2022-10-16T02:24:40Z",
            //             "unified": 0,
            //             "uta": 0,
            //             "userID": 24600000,
            //             "inviterID": 0,
            //             "vipLevel": "No VIP",
            //             "mktMakerLevel": "0",
            //             "affiliateID": 0,
            //             "rsaPublicKey": "",
            //             "isMaster": false
            //         },
            //         "retExtInfo": {},
            //         "time": 1676891757649
            //     }
            // account info
            //     {
            //         "retCode": 0,
            //         "retMsg": "OK",
            //         "result": {
            //             "marginMode": "REGULAR_MARGIN",
            //             "updatedTime": "1697078946000",
            //             "unifiedMarginStatus": 4,
            //             "dcpStatus": "OFF",
            //             "timeWindow": 10,
            //             "smpGroup": 0,
            //             "isMasterTrader": false,
            //             "spotHedgingStatus": "OFF"
            //         }
            //     }
            //
            const result = this.safeDict(response, 'result', {});
            const accountResult = this.safeDict(accountInfo, 'result', {});
            this.options['enableUnifiedMargin'] = this.safeInteger(result, 'unified') === 1;
            this.options['enableUnifiedAccount'] = this.safeInteger(result, 'uta') === 1;
            this.options['unifiedMarginStatus'] = this.safeInteger(accountResult, 'unifiedMarginStatus', 6); // default to uta 2.0 pro if not found
        }
        return [this.options['enableUnifiedMargin'], this.options['enableUnifiedAccount']];
    }
    /**
     * @method
     * @name bybit#upgradeUnifiedTradeAccount
     * @description upgrades the account to unified trade account *warning* this is irreversible
     * @see https://bybit-exchange.github.io/docs/v5/account/upgrade-unified-account
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {any} nothing
     */
    async upgradeUnifiedTradeAccount(params = {}) {
        return await this.privatePostV5AccountUpgradeToUta(params);
    }
    createExpiredOptionMarket(symbol) {
        // support expired option contracts
        let quote = undefined;
        let settle = undefined;
        const optionParts = symbol.split('-');
        const symbolBase = symbol.split('/');
        let base = undefined;
        let expiry = undefined;
        if (symbol.indexOf('/') > -1) {
            base = this.safeString(symbolBase, 0);
            expiry = this.safeString(optionParts, 1);
            const symbolQuoteAndSettle = this.safeString(symbolBase, 1);
            const splitQuote = symbolQuoteAndSettle.split(':');
            const quoteAndSettle = this.safeString(splitQuote, 0);
            quote = quoteAndSettle;
            settle = quoteAndSettle;
        }
        else {
            base = this.safeString(optionParts, 0);
            expiry = this.convertMarketIdExpireDate(this.safeString(optionParts, 1));
            if (symbol.endsWith('-USDT')) {
                quote = 'USDT';
                settle = 'USDT';
            }
            else {
                quote = 'USDC';
                settle = 'USDC';
            }
        }
        const strike = this.safeString(optionParts, 2);
        const optionType = this.safeString(optionParts, 3);
        const datetime = this.convertExpireDate(expiry);
        const timestamp = this.parse8601(datetime);
        let amountPrecision = undefined;
        let pricePrecision = undefined;
        // hard coded amount and price precisions from fetchOptionMarkets
        if (base === 'BTC') {
            amountPrecision = this.parseNumber('0.01');
            pricePrecision = this.parseNumber('5');
        }
        else if (base === 'ETH') {
            amountPrecision = this.parseNumber('0.1');
            pricePrecision = this.parseNumber('0.1');
        }
        else if (base === 'SOL') {
            amountPrecision = this.parseNumber('1');
            pricePrecision = this.parseNumber('0.01');
        }
        return {
            'id': base + '-' + this.convertExpireDateToMarketIdDate(expiry) + '-' + strike + '-' + optionType,
            'symbol': base + '/' + quote + ':' + settle + '-' + expiry + '-' + strike + '-' + optionType,
            'base': base,
            'quote': quote,
            'settle': settle,
            'baseId': base,
            'quoteId': quote,
            'settleId': settle,
            'active': false,
            'type': 'option',
            'linear': undefined,
            'inverse': undefined,
            'spot': false,
            'swap': false,
            'future': false,
            'option': true,
            'margin': false,
            'contract': true,
            'contractSize': this.parseNumber('1'),
            'expiry': timestamp,
            'expiryDatetime': datetime,
            'optionType': (optionType === 'C') ? 'call' : 'put',
            'strike': this.parseNumber(strike),
            'precision': {
                'amount': amountPrecision,
                'price': pricePrecision,
            },
            'limits': {
                'amount': {
                    'min': undefined,
                    'max': undefined,
                },
                'price': {
                    'min': undefined,
                    'max': undefined,
                },
                'cost': {
                    'min': undefined,
                    'max': undefined,
                },
            },
            'info': undefined,
        };
    }
    safeMarket(marketId = undefined, market = undefined, delimiter = undefined, marketType = undefined) {
        const isOption = (marketId !== undefined) && ((marketId.indexOf('-C') > -1) || (marketId.indexOf('-P') > -1));
        if (isOption && !(marketId in this.markets_by_id)) {
            // handle expired option contracts
            return this.createExpiredOptionMarket(marketId);
        }
        return super.safeMarket(marketId, market, delimiter, marketType);
    }
    getBybitType(method, market, params = {}) {
        let type = undefined;
        [type, params] = this.handleMarketTypeAndParams(method, market, params);
        let subType = undefined;
        [subType, params] = this.handleSubTypeAndParams(method, market, params);
        if (type === 'option' || type === 'spot') {
            return [type, params];
        }
        return [subType, params];
    }
    getAmount(symbol, amount) {
        // some markets like options might not have the precision available
        // and we shouldn't crash in those cases
        const market = this.market(symbol);
        const emptyPrecisionAmount = (market['precision']['amount'] === undefined);
        const amountString = this.numberToString(amount);
        if (!emptyPrecisionAmount && (amountString !== '0')) {
            return this.amountToPrecision(symbol, amount);
        }
        return amountString;
    }
    getPrice(symbol, price) {
        if (price === undefined) {
            return price;
        }
        const market = this.market(symbol);
        const emptyPrecisionPrice = (market['precision']['price'] === undefined);
        if (!emptyPrecisionPrice) {
            return this.priceToPrecision(symbol, price);
        }
        return price;
    }
    getCost(symbol, cost) {
        const market = this.market(symbol);
        const emptyPrecisionPrice = (market['precision']['price'] === undefined);
        if (!emptyPrecisionPrice) {
            return this.costToPrecision(symbol, cost);
        }
        return cost;
    }
    /**
     * @method
     * @name bybit#fetchTime
     * @description fetches the current integer timestamp in milliseconds from the exchange server
     * @see https://bybit-exchange.github.io/docs/v5/market/time
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {int} the current integer timestamp in milliseconds from the exchange server
     */
    async fetchTime(params = {}) {
        const response = await this.publicGetV5MarketTime(params);
        //
        //    {
        //         "retCode": "0",
        //         "retMsg": "OK",
        //         "result": {
        //             "timeSecond": "1666879482",
        //             "timeNano": "1666879482792685914"
        //         },
        //         "retExtInfo": {},
        //         "time": "1666879482792"
        //     }
        //
        return this.safeInteger(response, 'time');
    }
    /**
     * @method
     * @name bybit#fetchCurrencies
     * @description fetches all available currencies on an exchange
     * @see https://bybit-exchange.github.io/docs/v5/asset/coin-info
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {object} an associative dictionary of currencies
     */
    async fetchCurrencies(params = {}) {
        if (!this.checkRequiredCredentials(false)) {
            return undefined;
        }
        if (this.options['enableDemoTrading']) {
            return undefined;
        }
        const response = await this.privateGetV5AssetCoinQueryInfo(params);
        //
        //     {
        //         "retCode": 0,
        //         "retMsg": "",
        //         "result": {
        //             "rows": [
        //                 {
        //                     "name": "BTC",
        //                     "coin": "BTC",
        //                     "remainAmount": "150",
        //                     "chains": [
        //                         {
        //                             "chainType": "BTC",
        //                             "confirmation": "10000",
        //                             "withdrawFee": "0.0005",
        //                             "depositMin": "0.0005",
        //                             "withdrawMin": "0.001",
        //                             "chain": "BTC",
        //                             "chainDeposit": "1",
        //                             "chainWithdraw": "1",
        //                             "minAccuracy": "8"
        //                         }
        //                     ]
        //                 }
        //             ]
        //         },
        //         "retExtInfo": {},
        //         "time": 1672194582264
        //     }
        //
        const data = this.safeDict(response, 'result', {});
        const rows = this.safeList(data, 'rows', []);
        const result = {};
        for (let i = 0; i < rows.length; i++) {
            const currency = rows[i];
            const currencyId = this.safeString(currency, 'coin');
            const code = this.safeCurrencyCode(currencyId);
            const name = this.safeString(currency, 'name');
            const chains = this.safeList(currency, 'chains', []);
            const networks = {};
            for (let j = 0; j < chains.length; j++) {
                const chain = chains[j];
                const networkId = this.safeString(chain, 'chain');
                const networkCode = this.networkIdToCode(networkId);
                networks[networkCode] = {
                    'info': chain,
                    'id': networkId,
                    'network': networkCode,
                    'active': undefined,
                    'deposit': this.safeInteger(chain, 'chainDeposit') === 1,
                    'withdraw': this.safeInteger(chain, 'chainWithdraw') === 1,
                    'fee': this.safeNumber(chain, 'withdrawFee'),
                    'precision': this.parseNumber(this.parsePrecision(this.safeString(chain, 'minAccuracy'))),
                    'limits': {
                        'withdraw': {
                            'min': this.safeNumber(chain, 'withdrawMin'),
                            'max': undefined,
                        },
                        'deposit': {
                            'min': this.safeNumber(chain, 'depositMin'),
                            'max': undefined,
                        },
                    },
                };
            }
            result[code] = this.safeCurrencyStructure({
                'info': currency,
                'code': code,
                'id': currencyId,
                'name': name,
                'active': undefined,
                'deposit': undefined,
                'withdraw': undefined,
                'fee': undefined,
                'precision': undefined,
                'limits': {
                    'amount': {
                        'min': undefined,
                        'max': undefined,
                    },
                    'withdraw': {
                        'min': undefined,
                        'max': undefined,
                    },
                    'deposit': {
                        'min': undefined,
                        'max': undefined,
                    },
                },
                'networks': networks,
                'type': 'crypto', // atm exchange api provides only cryptos
            });
        }
        return result;
    }
    /**
     * @method
     * @name bybit#fetchMarkets
     * @description retrieves data on all markets for bybit
     * @see https://bybit-exchange.github.io/docs/v5/market/instrument
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {object[]} an array of objects representing market data
     */
    async fetchMarkets(params = {}) {
        if (this.options['adjustForTimeDifference']) {
            await this.loadTimeDifference();
        }
        const promisesUnresolved = [];
        const fetchMarkets = this.safeList(this.options, 'fetchMarkets', ['spot', 'linear', 'inverse']);
        for (let i = 0; i < fetchMarkets.length; i++) {
            const marketType = fetchMarkets[i];
            if (marketType === 'spot') {
                promisesUnresolved.push(this.fetchSpotMarkets(params));
            }
            else if (marketType === 'linear') {
                promisesUnresolved.push(this.fetchFutureMarkets({ 'category': 'linear' }));
            }
            else if (marketType === 'inverse') {
                promisesUnresolved.push(this.fetchFutureMarkets({ 'category': 'inverse' }));
            }
            else if (marketType === 'option') {
                promisesUnresolved.push(this.fetchOptionMarkets({ 'baseCoin': 'BTC' }));
                promisesUnresolved.push(this.fetchOptionMarkets({ 'baseCoin': 'ETH' }));
                promisesUnresolved.push(this.fetchOptionMarkets({ 'baseCoin': 'SOL' }));
            }
            else {
                throw new errors.ExchangeError(this.id + ' fetchMarkets() this.options fetchMarkets "' + marketType + '" is not a supported market type');
            }
        }
        const promises = await Promise.all(promisesUnresolved);
        const spotMarkets = this.safeList(promises, 0, []);
        const linearMarkets = this.safeList(promises, 1, []);
        const inverseMarkets = this.safeList(promises, 2, []);
        const btcOptionMarkets = this.safeList(promises, 3, []);
        const ethOptionMarkets = this.safeList(promises, 4, []);
        const solOptionMarkets = this.safeList(promises, 5, []);
        const futureMarkets = this.arrayConcat(linearMarkets, inverseMarkets);
        let optionMarkets = this.arrayConcat(btcOptionMarkets, ethOptionMarkets);
        optionMarkets = this.arrayConcat(optionMarkets, solOptionMarkets);
        const derivativeMarkets = this.arrayConcat(futureMarkets, optionMarkets);
        return this.arrayConcat(spotMarkets, derivativeMarkets);
    }
    async fetchSpotMarkets(params) {
        const request = {
            'category': 'spot',
        };
        const usePrivateInstrumentsInfo = this.safeBool(this.options, 'usePrivateInstrumentsInfo', false);
        let response = undefined;
        if (usePrivateInstrumentsInfo) {
            response = await this.privateGetV5MarketInstrumentsInfo(this.extend(request, params));
        }
        else {
            response = await this.publicGetV5MarketInstrumentsInfo(this.extend(request, params));
        }
        //
        //     {
        //         "retCode": 0,
        //         "retMsg": "OK",
        //         "result": {
        //             "category": "spot",
        //             "list": [
        //                 {
        //                     "symbol": "BTCUSDT",
        //                     "baseCoin": "BTC",
        //                     "quoteCoin": "USDT",
        //                     "innovation": "0",
        //                     "status": "Trading",
        //                     "marginTrading": "both",
        //                     "lotSizeFilter": {
        //                         "basePrecision": "0.000001",
        //                         "quotePrecision": "0.00000001",
        //                         "minOrderQty": "0.00004",
        //                         "maxOrderQty": "63.01197227",
        //                         "minOrderAmt": "1",
        //                         "maxOrderAmt": "100000"
        //                     },
        //                     "priceFilter": {
        //                         "tickSize": "0.01"
        //                     }
        //                 }
        //             ]
        //         },
        //         "retExtInfo": {},
        //         "time": 1672712468011
        //     }
        //
        const responseResult = this.safeDict(response, 'result', {});
        const markets = this.safeList(responseResult, 'list', []);
        const result = [];
        const takerFee = this.parseNumber('0.001');
        const makerFee = this.parseNumber('0.001');
        for (let i = 0; i < markets.length; i++) {
            const market = markets[i];
            const id = this.safeString(market, 'symbol');
            const baseId = this.safeString(market, 'baseCoin');
            const quoteId = this.safeString(market, 'quoteCoin');
            const base = this.safeCurrencyCode(baseId);
            const quote = this.safeCurrencyCode(quoteId);
            const symbol = base + '/' + quote;
            const status = this.safeString(market, 'status');
            const active = (status === 'Trading');
            const lotSizeFilter = this.safeDict(market, 'lotSizeFilter');
            const priceFilter = this.safeDict(market, 'priceFilter');
            const quotePrecision = this.safeNumber(lotSizeFilter, 'quotePrecision');
            const marginTrading = this.safeString(market, 'marginTrading', 'none');
            const allowsMargin = marginTrading !== 'none';
            result.push(this.safeMarketStructure({
                'id': id,
                'symbol': symbol,
                'base': base,
                'quote': quote,
                'settle': undefined,
                'baseId': baseId,
                'quoteId': quoteId,
                'settleId': undefined,
                'type': 'spot',
                'spot': true,
                'margin': allowsMargin,
                'swap': false,
                'future': false,
                'option': false,
                'active': active,
                'contract': false,
                'linear': undefined,
                'inverse': undefined,
                'taker': takerFee,
                'maker': makerFee,
                'contractSize': undefined,
                'expiry': undefined,
                'expiryDatetime': undefined,
                'strike': undefined,
                'optionType': undefined,
                'precision': {
                    'amount': this.safeNumber(lotSizeFilter, 'basePrecision'),
                    'price': this.safeNumber(priceFilter, 'tickSize', quotePrecision),
                },
                'limits': {
                    'leverage': {
                        'min': this.parseNumber('1'),
                        'max': undefined,
                    },
                    'amount': {
                        'min': this.safeNumber(lotSizeFilter, 'minOrderQty'),
                        'max': this.safeNumber(lotSizeFilter, 'maxOrderQty'),
                    },
                    'price': {
                        'min': undefined,
                        'max': undefined,
                    },
                    'cost': {
                        'min': this.safeNumber(lotSizeFilter, 'minOrderAmt'),
                        'max': this.safeNumber(lotSizeFilter, 'maxOrderAmt'),
                    },
                },
                'created': undefined,
                'info': market,
            }));
        }
        return result;
    }
    async fetchFutureMarkets(params) {
        params = this.extend(params);
        params['limit'] = 1000; // minimize number of requests
        let preLaunchMarkets = [];
        const usePrivateInstrumentsInfo = this.safeBool(this.options, 'usePrivateInstrumentsInfo', false);
        let response = undefined;
        if (usePrivateInstrumentsInfo) {
            response = await this.privateGetV5MarketInstrumentsInfo(params);
        }
        else {
            const linearPromises = [
                this.publicGetV5MarketInstrumentsInfo(params),
                this.publicGetV5MarketInstrumentsInfo(this.extend(params, { 'status': 'PreLaunch' })),
            ];
            const promises = await Promise.all(linearPromises);
            response = this.safeDict(promises, 0, {});
            preLaunchMarkets = this.safeDict(promises, 1, {});
        }
        const data = this.safeDict(response, 'result', {});
        let markets = this.safeList(data, 'list', []);
        let paginationCursor = this.safeString(data, 'nextPageCursor');
        if (paginationCursor !== undefined) {
            while (paginationCursor !== undefined) {
                params['cursor'] = paginationCursor;
                let responseInner = undefined;
                if (usePrivateInstrumentsInfo) {
                    responseInner = await this.privateGetV5MarketInstrumentsInfo(params);
                }
                else {
                    responseInner = await this.publicGetV5MarketInstrumentsInfo(params);
                }
                const dataNew = this.safeDict(responseInner, 'result', {});
                const rawMarkets = this.safeList(dataNew, 'list', []);
                const rawMarketsLength = rawMarkets.length;
                if (rawMarketsLength === 0) {
                    break;
                }
                markets = this.arrayConcat(rawMarkets, markets);
                paginationCursor = this.safeString(dataNew, 'nextPageCursor');
            }
        }
        //
        //     {
        //         "retCode": 0,
        //         "retMsg": "OK",
        //         "result": {
        //             "category": "linear",
        //             "list": [
        //                 {
        //                     "symbol": "BTCUSDT",
        //                     "contractType": "LinearPerpetual",
        //                     "status": "Trading",
        //                     "baseCoin": "BTC",
        //                     "quoteCoin": "USDT",
        //                     "launchTime": "1585526400000",
        //                     "deliveryTime": "0",
        //                     "deliveryFeeRate": "",
        //                     "priceScale": "2",
        //                     "leverageFilter": {
        //                         "minLeverage": "1",
        //                         "maxLeverage": "100.00",
        //                         "leverageStep": "0.01"
        //                     },
        //                     "priceFilter": {
        //                         "minPrice": "0.50",
        //                         "maxPrice": "999999.00",
        //                         "tickSize": "0.50"
        //                     },
        //                     "lotSizeFilter": {
        //                         "maxOrderQty": "100.000",
        //                         "minOrderQty": "0.001",
        //                         "qtyStep": "0.001",
        //                         "postOnlyMaxOrderQty": "1000.000"
        //                     },
        //                     "unifiedMarginTrade": true,
        //                     "fundingInterval": 480,
        //                     "settleCoin": "USDT"
        //                 }
        //             ],
        //             "nextPageCursor": ""
        //         },
        //         "retExtInfo": {},
        //         "time": 1672712495660
        //     }
        //
        const preLaunchData = this.safeDict(preLaunchMarkets, 'result', {});
        const preLaunchMarketsList = this.safeList(preLaunchData, 'list', []);
        markets = this.arrayConcat(markets, preLaunchMarketsList);
        const result = [];
        let category = this.safeString(data, 'category');
        for (let i = 0; i < markets.length; i++) {
            const market = markets[i];
            if (category === undefined) {
                category = this.safeString(market, 'category');
            }
            const linear = (category === 'linear');
            const inverse = (category === 'inverse');
            const contractType = this.safeString(market, 'contractType');
            const inverseFutures = (contractType === 'InverseFutures');
            const linearFutures = (contractType === 'LinearFutures');
            const linearPerpetual = (contractType === 'LinearPerpetual');
            const inversePerpetual = (contractType === 'InversePerpetual');
            const id = this.safeString(market, 'symbol');
            const baseId = this.safeString(market, 'baseCoin');
            const quoteId = this.safeString(market, 'quoteCoin');
            const defaultSettledId = linear ? quoteId : baseId;
            const settleId = this.safeString(market, 'settleCoin', defaultSettledId);
            const base = this.safeCurrencyCode(baseId);
            const quote = this.safeCurrencyCode(quoteId);
            let settle = undefined;
            if (linearPerpetual && (settleId === 'USD')) {
                settle = 'USDC';
            }
            else {
                settle = this.safeCurrencyCode(settleId);
            }
            let symbol = base + '/' + quote;
            const lotSizeFilter = this.safeDict(market, 'lotSizeFilter', {});
            const priceFilter = this.safeDict(market, 'priceFilter', {});
            const leverage = this.safeDict(market, 'leverageFilter', {});
            const status = this.safeString(market, 'status');
            const swap = linearPerpetual || inversePerpetual;
            const future = inverseFutures || linearFutures;
            let type = undefined;
            if (swap) {
                type = 'swap';
            }
            else if (future) {
                type = 'future';
            }
            let expiry = undefined;
            // some swaps have deliveryTime meaning delisting time
            if (!swap) {
                expiry = this.omitZero(this.safeString(market, 'deliveryTime'));
                if (expiry !== undefined) {
                    expiry = parseInt(expiry);
                }
            }
            const expiryDatetime = this.iso8601(expiry);
            symbol = symbol + ':' + settle;
            if (expiry !== undefined) {
                symbol = symbol + '-' + this.yymmdd(expiry);
            }
            const contractSize = inverse ? this.safeNumber2(lotSizeFilter, 'minTradingQty', 'minOrderQty') : this.parseNumber('1');
            result.push(this.safeMarketStructure({
                'id': id,
                'symbol': symbol,
                'base': base,
                'quote': quote,
                'settle': settle,
                'baseId': baseId,
                'quoteId': quoteId,
                'settleId': settleId,
                'type': type,
                'spot': false,
                'margin': undefined,
                'swap': swap,
                'future': future,
                'option': false,
                'active': (status === 'Trading'),
                'contract': true,
                'linear': linear,
                'inverse': inverse,
                'taker': this.safeNumber(market, 'takerFee', this.parseNumber('0.0006')),
                'maker': this.safeNumber(market, 'makerFee', this.parseNumber('0.0001')),
                'contractSize': contractSize,
                'expiry': expiry,
                'expiryDatetime': expiryDatetime,
                'strike': undefined,
                'optionType': undefined,
                'precision': {
                    'amount': this.safeNumber(lotSizeFilter, 'qtyStep'),
                    'price': this.safeNumber(priceFilter, 'tickSize'),
                },
                'limits': {
                    'leverage': {
                        'min': this.safeNumber(leverage, 'minLeverage'),
                        'max': this.safeNumber(leverage, 'maxLeverage'),
                    },
                    'amount': {
                        'min': this.safeNumber2(lotSizeFilter, 'minTradingQty', 'minOrderQty'),
                        'max': this.safeNumber2(lotSizeFilter, 'maxTradingQty', 'maxOrderQty'),
                    },
                    'price': {
                        'min': this.safeNumber(priceFilter, 'minPrice'),
                        'max': this.safeNumber(priceFilter, 'maxPrice'),
                    },
                    'cost': {
                        'min': undefined,
                        'max': undefined,
                    },
                },
                'created': this.safeInteger(market, 'launchTime'),
                'info': market,
            }));
        }
        return result;
    }
    async fetchOptionMarkets(params) {
        const request = {
            'category': 'option',
        };
        const usePrivateInstrumentsInfo = this.safeBool(this.options, 'usePrivateInstrumentsInfo', false);
        let response = undefined;
        if (usePrivateInstrumentsInfo) {
            response = await this.privateGetV5MarketInstrumentsInfo(this.extend(request, params));
        }
        else {
            response = await this.publicGetV5MarketInstrumentsInfo(this.extend(request, params));
        }
        const data = this.safeDict(response, 'result', {});
        let markets = this.safeList(data, 'list', []);
        if (this.options['loadAllOptions']) {
            request['limit'] = 1000;
            let paginationCursor = this.safeString(data, 'nextPageCursor');
            if (paginationCursor !== undefined) {
                while (paginationCursor !== undefined) {
                    request['cursor'] = paginationCursor;
                    let responseInner = undefined;
                    if (usePrivateInstrumentsInfo) {
                        responseInner = await this.privateGetV5MarketInstrumentsInfo(this.extend(request, params));
                    }
                    else {
                        responseInner = await this.publicGetV5MarketInstrumentsInfo(this.extend(request, params));
                    }
                    const dataNew = this.safeDict(responseInner, 'result', {});
                    const rawMarkets = this.safeList(dataNew, 'list', []);
                    const rawMarketsLength = rawMarkets.length;
                    if (rawMarketsLength === 0) {
                        break;
                    }
                    markets = this.arrayConcat(rawMarkets, markets);
                    paginationCursor = this.safeString(dataNew, 'nextPageCursor');
                }
            }
        }
        //
        //     {
        //         "retCode": 0,
        //         "retMsg": "success",
        //         "result": {
        //             "category": "option",
        //             "nextPageCursor": "0%2C2",
        //             "list": [
        //                 {
        //                     "symbol": "BTC-29DEC23-80000-C",
        //                     "status": "Trading",
        //                     "baseCoin": "BTC",
        //                     "quoteCoin": "USD",
        //                     "settleCoin": "USDC",
        //                     "optionsType": "Call",
        //                     "launchTime": "1688630400000",
        //                     "deliveryTime": "1703836800000",
        //                     "deliveryFeeRate": "0.00015",
        //                     "priceFilter": {
        //                         "minPrice": "5",
        //                         "maxPrice": "10000000",
        //                         "tickSize": "5"
        //                     },
        //                     "lotSizeFilter": {
        //                         "maxOrderQty": "500",
        //                         "minOrderQty": "0.01",
        //                         "qtyStep": "0.01"
        //                     }
        //                 },
        //             ]
        //         },
        //         "retExtInfo": {},
        //         "time": 1688873094448
        //     }
        //
        const result = [];
        for (let i = 0; i < markets.length; i++) {
            const market = markets[i];
            const id = this.safeString(market, 'symbol');
            const baseId = this.safeString(market, 'baseCoin');
            const quoteId = this.safeString(market, 'quoteCoin');
            const settleId = this.safeString(market, 'settleCoin');
            const base = this.safeCurrencyCode(baseId);
            const quote = this.safeCurrencyCode(quoteId);
            const settle = this.safeCurrencyCode(settleId);
            const lotSizeFilter = this.safeDict(market, 'lotSizeFilter', {});
            const priceFilter = this.safeDict(market, 'priceFilter', {});
            const status = this.safeString(market, 'status');
            const expiry = this.safeInteger(market, 'deliveryTime');
            const splitId = id.split('-');
            const strike = this.safeString(splitId, 2);
            const optionLetter = this.safeString(splitId, 3);
            const isActive = (status === 'Trading');
            const isInverse = base === settle;
            if (isActive || (this.options['loadAllOptions']) || (this.options['loadExpiredOptions'])) {
                result.push(this.safeMarketStructure({
                    'id': id,
                    'symbol': base + '/' + quote + ':' + settle + '-' + this.yymmdd(expiry) + '-' + strike + '-' + optionLetter,
                    'base': base,
                    'quote': quote,
                    'settle': settle,
                    'baseId': baseId,
                    'quoteId': quoteId,
                    'settleId': settleId,
                    'type': 'option',
                    'subType': undefined,
                    'spot': false,
                    'margin': false,
                    'swap': false,
                    'future': false,
                    'option': true,
                    'active': isActive,
                    'contract': true,
                    'linear': !isInverse,
                    'inverse': isInverse,
                    'taker': this.safeNumber(market, 'takerFee', this.parseNumber('0.0006')),
                    'maker': this.safeNumber(market, 'makerFee', this.parseNumber('0.0001')),
                    'contractSize': this.parseNumber('1'),
                    'expiry': expiry,
                    'expiryDatetime': this.iso8601(expiry),
                    'strike': this.parseNumber(strike),
                    'optionType': this.safeStringLower(market, 'optionsType'),
                    'precision': {
                        'amount': this.safeNumber(lotSizeFilter, 'qtyStep'),
                        'price': this.safeNumber(priceFilter, 'tickSize'),
                    },
                    'limits': {
                        'leverage': {
                            'min': undefined,
                            'max': undefined,
                        },
                        'amount': {
                            'min': this.safeNumber(lotSizeFilter, 'minOrderQty'),
                            'max': this.safeNumber(lotSizeFilter, 'maxOrderQty'),
                        },
                        'price': {
                            'min': this.safeNumber(priceFilter, 'minPrice'),
                            'max': this.safeNumber(priceFilter, 'maxPrice'),
                        },
                        'cost': {
                            'min': undefined,
                            'max': undefined,
                        },
                    },
                    'created': this.safeInteger(market, 'launchTime'),
                    'info': market,
                }));
            }
        }
        return result;
    }
    parseTicker(ticker, market = undefined) {
        //
        // spot
        //
        //     {
        //         "symbol": "BTCUSDT",
        //         "bid1Price": "20517.96",
        //         "bid1Size": "2",
        //         "ask1Price": "20527.77",
        //         "ask1Size": "1.862172",
        //         "lastPrice": "20533.13",
        //         "prevPrice24h": "20393.48",
        //         "price24hPcnt": "0.0068",
        //         "highPrice24h": "21128.12",
        //         "lowPrice24h": "20318.89",
        //         "turnover24h": "243765620.65899866",
        //         "volume24h": "11801.27771",
        //         "usdIndexPrice": "20784.12009279"
        //     }
        //
        // linear/inverse
        //
        //     {
        //         "symbol": "BTCUSD",
        //         "lastPrice": "16597.00",
        //         "indexPrice": "16598.54",
        //         "markPrice": "16596.00",
        //         "prevPrice24h": "16464.50",
        //         "price24hPcnt": "0.008047",
        //         "highPrice24h": "30912.50",
        //         "lowPrice24h": "15700.00",
        //         "prevPrice1h": "16595.50",
        //         "openInterest": "373504107",
        //         "openInterestValue": "22505.67",
        //         "turnover24h": "2352.94950046",
        //         "volume24h": "49337318",
        //         "fundingRate": "-0.001034",
        //         "nextFundingTime": "1672387200000",
        //         "predictedDeliveryPrice": "",
        //         "basisRate": "",
        //         "deliveryFeeRate": "",
        //         "deliveryTime": "0",
        //         "ask1Size": "1",
        //         "bid1Price": "16596.00",
        //         "ask1Price": "16597.50",
        //         "bid1Size": "1"
        //     }
        //
        // option
        //
        //     {
        //         "symbol": "BTC-30DEC22-18000-C",
        //         "bid1Price": "0",
        //         "bid1Size": "0",
        //         "bid1Iv": "0",
        //         "ask1Price": "435",
        //         "ask1Size": "0.66",
        //         "ask1Iv": "5",
        //         "lastPrice": "435",
        //         "highPrice24h": "435",
        //         "lowPrice24h": "165",
        //         "markPrice": "0.00000009",
        //         "indexPrice": "16600.55",
        //         "markIv": "0.7567",
        //         "underlyingPrice": "16590.42",
        //         "openInterest": "6.3",
        //         "turnover24h": "2482.73",
        //         "volume24h": "0.15",
        //         "totalVolume": "99",
        //         "totalTurnover": "1967653",
        //         "delta": "0.00000001",
        //         "gamma": "0.00000001",
        //         "vega": "0.00000004",
        //         "theta": "-0.00000152",
        //         "predictedDeliveryPrice": "0",
        //         "change24h": "86"
        //     }
        //
        const isSpot = this.safeString(ticker, 'openInterestValue') === undefined;
        const timestamp = this.safeInteger(ticker, 'time');
        const marketId = this.safeString(ticker, 'symbol');
        const type = isSpot ? 'spot' : 'contract';
        market = this.safeMarket(marketId, market, undefined, type);
        const symbol = this.safeSymbol(marketId, market, undefined, type);
        const last = this.safeString(ticker, 'lastPrice');
        const open = this.safeString(ticker, 'prevPrice24h');
        let percentage = this.safeString(ticker, 'price24hPcnt');
        percentage = Precise["default"].stringMul(percentage, '100');
        const quoteVolume = this.safeString(ticker, 'turnover24h');
        const baseVolume = this.safeString(ticker, 'volume24h');
        const bid = this.safeString(ticker, 'bid1Price');
        const ask = this.safeString(ticker, 'ask1Price');
        const high = this.safeString(ticker, 'highPrice24h');
        const low = this.safeString(ticker, 'lowPrice24h');
        return this.safeTicker({
            'symbol': symbol,
            'timestamp': timestamp,
            'datetime': this.iso8601(timestamp),
            'high': high,
            'low': low,
            'bid': bid,
            'bidVolume': this.safeString2(ticker, 'bidSize', 'bid1Size'),
            'ask': ask,
            'askVolume': this.safeString2(ticker, 'askSize', 'ask1Size'),
            'vwap': undefined,
            'open': open,
            'close': last,
            'last': last,
            'previousClose': undefined,
            'change': undefined,
            'percentage': percentage,
            'average': undefined,
            'baseVolume': baseVolume,
            'quoteVolume': quoteVolume,
            'markPrice': this.safeString(ticker, 'markPrice'),
            'indexPrice': this.safeString(ticker, 'indexPrice'),
            'info': ticker,
        }, market);
    }
    /**
     * @method
     * @name bybit#fetchTicker
     * @description fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
     * @see https://bybit-exchange.github.io/docs/v5/market/tickers
     * @param {string} symbol unified symbol of the market to fetch the ticker for
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
     */
    async fetchTicker(symbol, params = {}) {
        if (symbol === undefined) {
            throw new errors.ArgumentsRequired(this.id + ' fetchTicker() requires a symbol argument');
        }
        await this.loadMarkets();
        const market = this.market(symbol);
        const request = {
            'symbol': market['id'],
            // 'baseCoin': '', Base coin. For option only
            // 'expDate': '', Expiry date. e.g., 25DEC22. For option only
        };
        let category = undefined;
        [category, params] = this.getBybitType('fetchTicker', market, params);
        request['category'] = category;
        const response = await this.publicGetV5MarketTickers(this.extend(request, params));
        //
        //     {
        //         "retCode": 0,
        //         "retMsg": "OK",
        //         "result": {
        //             "category": "inverse",
        //             "list": [
        //                 {
        //                     "symbol": "BTCUSD",
        //                     "lastPrice": "16597.00",
        //                     "indexPrice": "16598.54",
        //                     "markPrice": "16596.00",
        //                     "prevPrice24h": "16464.50",
        //                     "price24hPcnt": "0.008047",
        //                     "highPrice24h": "30912.50",
        //                     "lowPrice24h": "15700.00",
        //                     "prevPrice1h": "16595.50",
        //                     "openInterest": "373504107",
        //                     "openInterestValue": "22505.67",
        //                     "turnover24h": "2352.94950046",
        //                     "volume24h": "49337318",
        //                     "fundingRate": "-0.001034",
        //                     "nextFundingTime": "1672387200000",
        //                     "predictedDeliveryPrice": "",
        //                     "basisRate": "",
        //                     "deliveryFeeRate": "",
        //                     "deliveryTime": "0",
        //                     "ask1Size": "1",
        //                     "bid1Price": "16596.00",
        //                     "ask1Price": "16597.50",
        //                     "bid1Size": "1"
        //                 }
        //             ]
        //         },
        //         "retExtInfo": {},
        //         "time": 1672376496682
        //     }
        //
        const result = this.safeDict(response, 'result', {});
        const tickers = this.safeList(result, 'list', []);
        const rawTicker = this.safeDict(tickers, 0);
        return this.parseTicker(rawTicker, market);
    }
    /**
     * @method
     * @name bybit#fetchTickers
     * @description fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market
     * @see https://bybit-exchange.github.io/docs/v5/market/tickers
     * @param {string[]} symbols unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @param {string} [params.subType] *contract only* 'linear', 'inverse'
     * @param {string} [params.baseCoin] *option only* base coin, default is 'BTC'
     * @returns {object} an array of [ticker structures]{@link https://docs.ccxt.com/#/?id=ticker-structure}
     */
    async fetchTickers(symbols = undefined, params = {}) {
        await this.loadMarkets();
        let code = this.safeStringN(params, ['code', 'currency', 'baseCoin']);
        let market = undefined;
        let parsedSymbols = undefined;
        if (symbols !== undefined) {
            parsedSymbols = [];
            const marketTypeInfo = this.handleMarketTypeAndParams('fetchTickers', undefined, params);
            const defaultType = marketTypeInfo[0]; // don't omit here
            // we can't use marketSymbols here due to the conflicing ids between markets
            let currentType = undefined;
            for (let i = 0; i < symbols.length; i++) {
                const symbol = symbols[i];
                // using safeMarket here because if the user provides for instance BTCUSDT and "type": "spot" in params we should
                // infer the market type from the type provided and not from the conflicting id (BTCUSDT might be swap or spot)
                const isExchangeSpecificSymbol = (symbol.indexOf('/') === -1);
                if (isExchangeSpecificSymbol) {
                    market = this.safeMarket(symbol, undefined, undefined, defaultType);
                }
                else {
                    market = this.market(symbol);
                }
                if (currentType === undefined) {
                    currentType = market['type'];
                }
                else if (market['type'] !== currentType) {
                    throw new errors.BadRequest(this.id + ' fetchTickers can only accept a list of symbols of the same type');
                }
                if (market['option']) {
                    if (code !== undefined && code !== market['base']) {
                        throw new errors.BadRequest(this.id + ' fetchTickers the base currency must be the same for all symbols, this endpoint only supports one base currency at a time. Read more about it here: https://bybit-exchange.github.io/docs/v5/market/tickers');
                    }
                    if (code === undefined) {
                        code = market['base'];
                    }
                    params = this.omit(params, ['code', 'currency']);
                }
                parsedSymbols.push(market['symbol']);
            }
        }
        const request = {
        // 'symbol': market['id'],
        // 'baseCoin': '', // Base coin. For option only
        // 'expDate': '', // Expiry date. e.g., 25DEC22. For option only
        };
        let category = undefined;
        [category, params] = this.getBybitType('fetchTickers', market, params);
        request['category'] = category;
        if (category === 'option') {
            request['category'] = 'option';
            if (code === undefined) {
                code = 'BTC';
            }
            request['baseCoin'] = code;
        }
        const response = await this.publicGetV5MarketTickers(this.extend(request, params));
        //
        //     {
        //         "retCode": 0,
        //         "retMsg": "OK",
        //         "result": {
        //             "category": "inverse",
        //             "list": [
        //                 {
        //                     "symbol": "BTCUSD",
        //                     "lastPrice": "16597.00",
        //                     "indexPrice": "16598.54",
        //                     "markPrice": "16596.00",
        //                     "prevPrice24h": "16464.50",
        //                     "price24hPcnt": "0.008047",
        //                     "highPrice24h": "30912.50",
        //                     "lowPrice24h": "15700.00",
        //                     "prevPrice1h": "16595.50",
        //                     "openInterest": "373504107",
        //                     "openInterestValue": "22505.67",
        //                     "turnover24h": "2352.94950046",
        //                     "volume24h": "49337318",
        //                     "fundingRate": "-0.001034",
        //                     "nextFundingTime": "1672387200000",
        //                     "predictedDeliveryPrice": "",
        //                     "basisRate": "",
        //                     "deliveryFeeRate": "",
        //                     "deliveryTime": "0",
        //                     "ask1Size": "1",
        //                     "bid1Price": "16596.00",
        //                     "ask1Price": "16597.50",
        //                     "bid1Size": "1"
        //                 }
        //             ]
        //         },
        //         "retExtInfo": {},
        //         "time": 1672376496682
        //     }
        //
        const result = this.safeDict(response, 'result', {});
        const tickerList = this.safeList(result, 'list', []);
        return this.parseTickers(tickerList, parsedSymbols);
    }
    /**
     * @method
     * @name bybit#fetchBidsAsks
     * @description fetches the bid and ask price and volume for multiple markets
     * @see https://bybit-exchange.github.io/docs/v5/market/tickers
     * @param {string[]|undefined} symbols unified symbols of the markets to fetch the bids and asks for, all markets are returned if not assigned
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @param {string} [params.subType] *contract only* 'linear', 'inverse'
     * @param {string} [params.baseCoin] *option only* base coin, default is 'BTC'
     * @returns {object} a dictionary of [ticker structures]{@link https://docs.ccxt.com/#/?id=ticker-structure}
     */
    async fetchBidsAsks(symbols = undefined, params = {}) {
        return await this.fetchTickers(symbols, params);
    }
    parseOHLCV(ohlcv, market = undefined) {
        //
        //     [
        //         "1621162800",
        //         "49592.43",
        //         "49644.91",
        //         "49342.37",
        //         "49349.42",
        //         "1451.59",
        //         "2.4343353100000003"
        //     ]
        //
        const volumeIndex = (market['inverse']) ? 6 : 5;
        return [
            this.safeInteger(ohlcv, 0),
            this.safeNumber(ohlcv, 1),
            this.safeNumber(ohlcv, 2),
            this.safeNumber(ohlcv, 3),
            this.safeNumber(ohlcv, 4),
            this.safeNumber(ohlcv, volumeIndex),
        ];
    }
    /**
     * @method
     * @name bybit#fetchOHLCV
     * @description fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
     * @see https://bybit-exchange.github.io/docs/v5/market/kline
     * @see https://bybit-exchange.github.io/docs/v5/market/mark-kline
     * @see https://bybit-exchange.github.io/docs/v5/market/index-kline
     * @see https://bybit-exchange.github.io/docs/v5/market/preimum-index-kline
     * @param {string} symbol unified symbol of the market to fetch OHLCV data for
     * @param {string} 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 {object} [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.paginate] default false, when true will automatically paginate by calling this 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 as timestamp, open, high, low, close, volume
     */
    async fetchOHLCV(symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
        if (symbol === undefined) {
            throw new errors.ArgumentsRequired(this.id + ' fetchOHLCV() requires a symbol argument');
        }
        await this.loadMarkets();
        let paginate = false;
        [paginate, params] = this.handleOptionAndParams(params, 'fetchOHLCV', 'paginate');
        if (paginate) {
            return await this.fetchPaginatedCallDeterministic('fetchOHLCV', symbol, since, limit, timeframe, params, 1000);
        }
        const market = this.market(symbol);
        let request = {
            'symbol': market['id'],
        };
        if (limit === undefined) {
            limit = 200; // default is 200 when requested with `since`
        }
        if (since !== undefined) {
            request['start'] = since;
        }
        if (limit !== undefined) {
            request['limit'] = limit; // max 1000, default 1000
        }
        [request, params] = this.handleUntilOption('end', request, params);
        request['interval'] = this.safeString(this.timeframes, timeframe, timeframe);
        let response = undefined;
        if (market['spot']) {
            request['category'] = 'spot';
            response = await this.publicGetV5MarketKline(this.extend(request, params));
        }
        else {
            const price = this.safeString(params, 'price');
            params = this.omit(params, 'price');
            if (market['linear']) {
                request['category'] = 'linear';
            }
            else if (market['inverse']) {
                request['category'] = 'inverse';
            }
            else {
                throw new errors.NotSupported(this.id + ' fetchOHLCV() is not supported for option markets');
            }
            if (price === 'mark') {
                response = await this.publicGetV5MarketMarkPriceKline(this.extend(request, params));
            }
            else if (price === 'index') {
                response = await this.publicGetV5MarketIndexPriceKline(this.extend(request, params));
            }
            else if (price === 'premiumIndex') {
                response = await this.publicGetV5MarketPremiumIndexPriceKline(this.extend(request, params));
            }
            else {
                response = await this.publicGetV5MarketKline(this.extend(request, params));
            }
        }
        //
        //     {
        //         "retCode": 0,
        //         "retMsg": "OK",
        //         "result": {
        //             "symbol": "BTCUSD",
        //             "category": "inverse",
        //             "list": [
        //                 [
        //                     "1670608800000",
        //                     "17071",
        //                     "17073",
        //                     "17027",
        //                     "17055.5",
        //                     "268611",
        //                     "15.74462667"
        //                 ],
        //                 [
        //                     "1670605200000",
        //                     "17071.5",
        //                     "17071.5",
        //                     "17061",
        //                     "17071",
        //                     "4177",
        //                     "0.24469757"
        //                 ],
        //                 [
        //                     "1670601600000",
        //                     "17086.5",
        //                     "17088",
        //                     "16978",
        //                     "17071.5",
        //                     "6356",
        //                     "0.37288112"
        //                 ]
        //             ]
        //         },
        //         "retExtInfo": {},
        //         "time": 1672025956592
        //     }
        //
        const result = this.safeDict(response, 'result', {});
        const ohlcvs = this.safeList(result, 'list', []);
        return this.parseOHLCVs(ohlcvs, market, timeframe, since, limit);
    }
    parseFundingRate(ticker, market = undefined) {
        //
        //     {
        //         "symbol": "BTCUSDT",
        //         "bidPrice": "19255",
        //         "askPrice": "19255.5",
        //         "lastPrice": "19255.50",
        //         "lastTickDirection": "ZeroPlusTick",
        //         "prevPrice24h": "18634.50",
        //         "price24hPcnt": "0.033325",
        //         "highPrice24h": "19675.00",
        //         "lowPrice24h": "18610.00",
        //         "prevPrice1h": "19278.00",
        //         "markPrice": "19255.00",
        //         "indexPrice": "19260.68",
        //         "openInterest": "48069.549",
        //         "turnover24h": "4686694853.047006",
        //         "volume24h": "243730.252",
        //         "fundingRate": "0.0001",
        //         "nextFundingTime": "1663689600000",
        //         "predictedDeliveryPrice": "",
        //         "basisRate": "",
        //         "deliveryFeeRate": "",
        //         "deliveryTime": "0"
        //     }
        //
        const timestamp = this.safeInteger(ticker, 'timestamp'); // added artificially to avoid changing the signature
        ticker = this.omit(ticker, 'timestamp');
        const marketId = this.safeString(ticker, 'symbol');
        const symbol = this.safeSymbol(marketId, market, undefined, 'swap');
        const fundingRate = this.safeNumber(ticker, 'fundingRate');
        const fundingTimestamp = this.safeInteger(ticker, 'nextFundingTime');
        const markPrice = this.safeNumber(ticker, 'markPrice');
        const indexPrice = this.safeNumber(ticker, 'indexPrice');
        const info = this.safeDict(this.safeMarket(marketId, market, undefined, 'swap'), 'info');
        const fundingInterval = this.safeInteger(info, 'fundingInterval');
        let intervalString = undefined;
        if (fundingInterval !== undefined) {
            const interval = this.parseToInt(fundingInterval / 60);
            intervalString = interval.toString() + 'h';
        }
        return {
            'info': ticker,
            'symbol': symbol,
            'markPrice': markPrice,
            'indexPrice': indexPrice,
            'interestRate': undefined,
            'estimatedSettlePrice': undefined,
            'timestamp': timestamp,
            'datetime': this.iso8601(timestamp),
            'fundingRate': fundingRate,
            'fundingTimestamp': fundingTimestamp,
            'fundingDatetime': this.iso8601(fundingTimestamp),
            'nextFundingRate': undefined,
            'nextFundingTimestamp': undefined,
            'nextFundingDatetime': undefined,
            'previousFundingRate': undefined,
            'previousFundingTimestamp': undefined,
            'previousFundingDatetime': undefined,
            'interval': intervalString,
        };
    }
    /**
     * @method
     * @name bybit#fetchFundingRates
     * @description fetches funding rates for multiple markets
     * @see https://bybit-exchange.github.io/docs/v5/market/tickers
     * @param {string[]} symbols unified symbols of the markets to fetch the funding rates for, all market funding rates are returned if not assigned
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {object[]} a list of [funding rate structures]{@link https://docs.ccxt.com/#/?id=funding-rate-structure}
     */
    async fetchFundingRates(symbols = undefined, params = {}) {
        await this.loadMarkets();
        let market = undefined;
        const request = {};
        if (symbols !== undefined) {
            symbols = this.marketSymbols(symbols);
            market = this.market(symbols[0]);
            const symbolsLength = symbols.length;
            if (symbolsLength === 1) {
                request['symbol'] = market['id'];
            }
        }
        let type = undefined;
        [type, params] = this.handleMarketTypeAndParams('fetchFundingRates', market, params);
        if (type !== 'swap') {
            throw new errors.NotSupported(this.id + ' fetchFundingRates() does not support ' + type + ' markets');
        }
        else {
            let subType = undefined;
            [subType, params] = this.handleSubTypeAndParams('fetchFundingRates', market, params, 'linear');
            request['category'] = subType;
        }
        const response = await this.publicGetV5MarketTickers(this.extend(request, params));
        //
        //     {
        //         "retCode": 0,
        //         "retMsg": "OK",
        //         "result": {
        //             "category": "linear",
        //             "list": [
        //                 {
        //                     "symbol": "BTCUSDT",
        //                     "bidPrice": "19255",
        //                     "askPrice": "19255.5",
        //                     "lastPrice": "19255.50",
        //                     "lastTickDirection": "ZeroPlusTick",
        //                     "prevPrice24h": "18634.50",
        //                     "price24hPcnt": "0.033325",
        //                     "highPrice24h": "19675.00",
        //                     "lowPrice24h": "18610.00",
        //                     "prevPrice1h": "19278.00",
        //                     "markPrice": "19255.00",
        //                     "indexPrice": "19260.68",
        //                     "openInterest": "48069.549",
        //                     "turnover24h": "4686694853.047006",
        //                     "volume24h": "243730.252",
        //                     "fundingRate": "0.0001",
        //                     "nextFundingTime": "1663689600000",
        //                     "predictedDeliveryPrice": "",
        //                     "basisRate": "",
        //                     "deliveryFeeRate": "",
        //                     "deliveryTime": "0"
        //                 }
        //             ]
        //         },
        //         "retExtInfo": null,
        //         "time": 1663670053454
        //     }
        //
        const data = this.safeDict(response, 'result', {});
        const tickerList = this.safeList(data, 'list', []);
        const timestamp = this.safeInteger(response, 'time');
        for (let i = 0; i < tickerList.length; i++) {
            tickerList[i]['timestamp'] = timestamp; // will be removed inside the parser
        }
        return this.parseFundingRates(tickerList, symbols);
    }
    /**
     * @method
     * @name bybit#fetchFundingRateHistory
     * @description fetches historical funding rate prices
     * @see https://bybit-exchange.github.io/docs/v5/market/history-fund-rate
     * @param {string} 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]{@link https://docs.ccxt.com/#/?id=funding-rate-history-structure} to fetch
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @param {int} [params.until] timestamp in ms of the latest funding rate
     * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
     * @returns {object[]} a list of [funding rate structures]{@link https://docs.ccxt.com/#/?id=funding-rate-history-structure}
     */
    async fetchFundingRateHistory(symbol = undefined, since = undefined, limit = undefined, params = {}) {
        if (symbol === undefined) {
            throw new errors.ArgumentsRequired(this.id + ' fetchFundingRateHistory() requires a symbol argument');
        }
        await this.loadMarkets();
        let paginate = false;
        [paginate, params] = this.handleOptionAndParams(params, 'fetchFundingRateHistory', 'paginate');
        if (paginate) {
            return await this.fetchPaginatedCallDeterministic('fetchFundingRateHistory', symbol, since, limit, '8h', params, 200);
        }
        if (limit === undefined) {
            limit = 200;
        }
        const request = {
            // 'category': '', // Product type. linear,inverse
            // 'symbol': '', // Symbol name
            // 'startTime': 0, // The start timestamp (ms)
            // 'endTime': 0, // The end timestamp (ms)
            'limit': limit, // Limit for data size per page. [1, 200]. Default: 200
        };
        const market = this.market(symbol);
        symbol = market['symbol'];
        request['symbol'] = market['id'];
        let type = undefined;
        [type, params] = this.getBybitType('fetchFundingRateHistory', market, params);
        if (type === 'spot' || type === 'option') {
            throw new errors.NotSupported(this.id + ' fetchFundingRateHistory() only support linear and inverse market');
        }
        request['category'] = type;
        if (since !== undefined) {
            request['startTime'] = since;
        }
        const until = this.safeInteger(params, 'until'); // unified in milliseconds
        const endTime = this.safeInteger(params, 'endTime', until); // exchange-specific in milliseconds
        params = this.omit(params, ['endTime', 'until']);
        if (endTime !== undefined) {
            request['endTime'] = endTime;
        }
        else {
            if (since !== undefined) {
                // end time is required when since is not empty
                const fundingInterval = 60 * 60 * 8 * 1000;
                request['endTime'] = since + limit * fundingInterval;
            }
        }
        const response = await this.publicGetV5MarketFundingHistory(this.extend(request, params));
        //
        //     {
        //         "retCode": 0,
        //         "retMsg": "OK",
        //         "result": {
        //             "category": "linear",
        //             "list": [
        //                 {
        //                     "symbol": "ETHPERP",
        //                     "fundingRate": "0.0001",
        //                     "fundingRateTimestamp": "1672041600000"
        //                 }
        //             ]
        //         },
        //         "retExtInfo": {},
        //         "time": 1672051897447
        //     }
        //
        const rates = [];
        const result = this.safeDict(response, 'result');
        const resultList = this.safeList(result, 'list');
        for (let i = 0; i < resultList.length; i++) {
            const entry = resultList[i];
            const timestamp = this.safeInteger(entry, 'fundingRateTimestamp');
            rates.push({
                'info': entry,
                'symbol': this.safeSymbol(this.safeString(entry, 'symbol'), undefined, undefined, 'swap'),
                'fundingRate': this.safeNumber(entry, 'fundingRate'),
                'timestamp': timestamp,
                'datetime': this.iso8601(timestamp),
            });
        }
        const sorted = this.sortBy(rates, 'timestamp');
        return this.filterBySymbolSinceLimit(sorted, symbol, since, limit);
    }
    parseTrade(trade, market = undefined) {
        //
        // public https://bybit-exchange.github.io/docs/v5/market/recent-trade
        //
        //     {
        //         "execId": "666042b4-50c6-58f3-bd9c-89b2088663ff",
        //         "symbol": "ETHUSD",
        //         "price": "1162.95",
        //         "size": "1",
        //         "side": "Sell",
        //         "time": "1669191277315",
        //         "isBlockTrade": false
        //     }
        //
        // private trades classic spot https://bybit-exchange.github.io/docs/v5/position/execution
        //
        //     {
        //         "symbol": "QNTUSDT",
        //         "orderId": "1538686353240339712",
        //         "orderLinkId": "",
        //         "side": "Sell",
        //         "orderPrice": "",
        //         "orderQty": "",
        //         "leavesQty": "",
        //         "orderType": "Limit",
        //         "stopOrderType": "",
        //         "execFee": "0.040919",
        //         "execId": "2210000000097330907",
        //         "execPrice": "98.6",
        //         "execQty": "0.415",
        //         "execType": "",
        //         "execValue": "",
        //         "execTime": "1698161716634",
        //         "isMaker": true,
        //         "feeRate": "",
        //         "tradeIv": "",
        //         "markIv": "",
        //         "markPrice": "",
        //         "indexPrice": "",
        //         "underlyingPrice": "",
        //         "blockTradeId": ""
        //     }
        //
        // private trades unified https://bybit-exchange.github.io/docs/v5/position/execution
        //
        //     {
        //         "symbol": "QNTUSDT",
        //         "orderType": "Limit",
        //         "underlyingPrice": "",
        //         "orderLinkId": "1549452573428424449",
        //         "orderId": "1549452573428424448",
        //         "stopOrderType": "",
        //         "execTime": "1699445151998",
        //         "feeRate": "0.00025",
        //         "tradeIv": "",
        //         "blockTradeId": "",
        //         "markPrice": "",
        //         "execPrice": "102.8",
        //         "markIv": "",
        //         "orderQty": "3.652",
        //         "orderPrice": "102.8",
        //         "execValue": "1.028",
        //         "closedSize": "",
        //         "execType": "Trade",
        //         "seq": "19157444346",
        //         "side": "Buy",
        //         "indexPrice": "",
        //         "leavesQty": "3.642",
        //         "isMaker": true,
        //         "execFee": "0.0000025",
        //         "execId": "2210000000101610464",
        //         "execQty": "0.01",
        //         "nextPageCursor": "267951%3A0%2C38567%3A0"
        //     },
        //
        // private USDC settled trades
        //
        //     {
        //         "symbol": "ETHPERP",
        //         "orderLinkId": "",
        //         "side": "Buy",
        //         "orderId": "aad0ee44-ce12-4112-aeee-b7829f6c3a26",
        //         "execFee": "0.0210",
        //         "feeRate": "0.000600",
        //         "blockTradeId": "",
        //         "tradeTime": "1669196417930",
        //         "execPrice": "1162.15",
        //         "lastLiquidityInd": "TAKER",
        //         "execValue": "34.8645",
        //         "execType": "Trade",
        //         "execQty": "0.030",
        //         "tradeId": "0e94eaf5-b08e-5505-b43f-7f1f30b1ca80"
        //     }
        //
        const id = this.safeStringN(trade, ['execId', 'id', 'tradeId']);
        const marketId = this.safeString(trade, 'symbol');
        let marketType = ('createType' in trade) ? 'contract' : 'spot';
        if (market !== undefined) {
            marketType = market['type'];
        }
        const category = this.safeString(trade, 'category');
        if (category !== undefined) {
            if (category === 'spot') {
                marketType = 'spot';
            }
        }
        market = this.safeMarket(marketId, market, undefined, marketType);
        const symbol = market['symbol'];
        const amountString = this.safeStringN(trade, ['execQty', 'orderQty', 'size']);
        const priceString = this.safeStringN(trade, ['execPrice', 'orderPrice', 'price']);
        const costString = this.safeString(trade, 'execValue');
        const timestamp = this.safeIntegerN(trade, ['time', 'execTime', 'tradeTime']);
        let side = this.safeStringLower(trade, 'side');
        if (side === undefined) {
            const isBuyer = this.safeInteger(trade, 'isBuyer');
            if (isBuyer !== undefined) {
                side = isBuyer ? 'buy' : 'sell';
            }
        }
        const isMaker = this.safeBool(trade, 'isMaker');
        let takerOrMaker = undefined;
        if (isMaker !== undefined) {
            takerOrMaker = isMaker ? 'maker' : 'taker';
        }
        else {
            let lastLiquidityInd = this.safeString(trade, 'lastLiquidityInd');
            if (lastLiquidityInd === 'UNKNOWN') {
                lastLiquidityInd = undefined;
            }
            if (lastLiquidityInd !== undefined) {
                if ((lastLiquidityInd === 'TAKER') || (lastLiquidityInd === 'MAKER')) {
                    takerOrMaker = lastLiquidityInd.toLowerCase();
                }
                else {
                    takerOrMaker = (lastLiquidityInd === 'AddedLiquidity') ? 'maker' : 'taker';
                }
            }
        }
        let orderType = this.safeStringLower(trade, 'orderType');
        if (orderType === 'unknown') {
            orderType = undefined;
        }
        const feeCostString = this.safeString(trade, 'execFee');
        let fee = undefined;
        if (feeCostString !== undefined) {
            const feeRateString = this.safeString(trade, 'feeRate');
            let feeCurrencyCode = undefined;
            if (market['spot']) {
                if (Precise["default"].stringGt(feeCostString, '0')) {
                    if (side === 'buy') {
                        feeCurrencyCode = market['base'];
                    }
                    else {
                        feeCurrencyCode = market['quote'];
                    }
                }
                else {
                    if (side === 'buy') {
                        feeCurrencyCode = market['quote'];
                    }
                    else {
                        feeCurrencyCode = market['base'];
                    }
                }
            }
            else {
                feeCurrencyCode = market['inverse'] ? market['base'] : market['settle'];
            }
            fee = {
                'cost': feeCostString,
                'currency': feeCurrencyCode,
                'rate': feeRateString,
            };
        }
        return this.safeTrade({
            'id': id,
            'info': trade,
            'timestamp': timestamp,
            'datetime': this.iso8601(timestamp),
            'symbol': symbol,
            'order': this.safeString(trade, 'orderId'),
            'type': orderType,
            'side': side,
            'takerOrMaker': takerOrMaker,
            'price': priceString,
            'amount': amountString,
            'cost': costString,
            'fee': fee,
        }, market);
    }
    /**
     * @method
     * @name bybit#fetchTrades
     * @description get the list of most recent trades for a particular symbol
     * @see https://bybit-exchange.github.io/docs/v5/market/recent-trade
     * @param {string} 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 {object} [params] extra parameters specific to the exchange API endpoint
     * @param {string} [params.type] market type, ['swap', 'option', 'spot']
     * @param {string} [params.subType] market subType, ['linear', 'inverse']
     * @returns {Trade[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=public-trades}
     */
    async fetchTrades(symbol, since = undefined, limit = undefined, params = {}) {
        if (symbol === undefined) {
            throw new errors.ArgumentsRequired(this.id + ' fetchTrades() requires a symbol argument');
        }
        await this.loadMarkets();
        const market = this.market(symbol);
        const request = {
            'symbol': market['id'],
            // 'baseCoin': '', // Base coin. For option only. If not passed, return BTC data by default
            // 'optionType': 'Call', // Option type. Call or Put. For option only
        };
        if (limit !== undefined) {
            // spot: [1,60], default: 60.
            // others: [1,1000], default: 500
            request['limit'] = limit;
        }
        let type = undefined;
        [type, params] = this.getBybitType('fetchTrades', market, params);
        request['category'] = type;
        const response = await this.publicGetV5MarketRecentTrade(this.extend(request, params));
        //
        //     {
        //         "retCode": 0,
        //         "retMsg": "OK",
        //         "result": {
        //             "category": "spot",
        //             "list": [
        //                 {
        //                     "execId": "2100000000007764263",
        //                     "symbol": "BTCUSDT",
        //                     "price": "16618.49",
        //                     "size": "0.00012",
        //                     "side": "Buy",
        //                     "time": "1672052955758",
        //                     "isBlockTrade": false
        //                 }
        //             ]
        //         },
        //         "retExtInfo": {},
        //         "time": 1672053054358
        //     }
        //
        const result = this.safeDict(response, 'result', {});
        const trades = this.safeList(result, 'list', []);
        return this.parseTrades(trades, market, since, limit);
    }
    /**
     * @method
     * @name bybit#fetchOrderBook
     * @description fetches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
     * @see https://bybit-exchange.github.io/docs/v5/market/orderbook
     * @param {string} 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 {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols
     */
    async fetchOrderBook(symbol, limit = undefined, params = {}) {
        if (symbol === undefined) {
            throw new errors.ArgumentsRequired(this.id + ' fetchOrderBook() requires a symbol argument');
        }
        await this.loadMarkets();
        const market = this.market(symbol);
        const request = {
            'symbol': market['id'],
        };
        let defaultLimit = 25;
        if (market['spot']) {
            // limit: [1, 50]. Default: 1
            defaultLimit = 50;
            request['category'] = 'spot';
        }
        else {
            if (market['option']) {
                // limit: [1, 25]. Default: 1
                request['category'] = 'option';
            }
            else if (market['linear']) {
                // limit: [1, 500]. Default: 25
                request['category'] = 'linear';
            }
            else if (market['inverse']) {
                // limit: [1, 500]. Default: 25
                request['category'] = 'inverse';
            }
        }
        request['limit'] = (limit !== undefined) ? limit : defaultLimit;
        const response = await this.publicGetV5MarketOrderbook(this.extend(request, params));
        //
        //     {
        //         "retCode": 0,
        //         "retMsg": "OK",
        //         "result": {
        //             "s": "BTCUSDT",
        //             "a": [
        //                 [
        //                     "16638.64",
        //                     "0.008479"
        //                 ]
        //             ],
        //             "b": [
        //                 [
        //                     "16638.27",
        //                     "0.305749"
        //                 ]
        //             ],
        //             "ts": 1672765737733,
        //             "u": 5277055
        //         },
        //         "retExtInfo": {},
        //         "time": 1672765737734
        //     }
        //
        const result = this.safeDict(response, 'result', {});
        const timestamp = this.safeInteger(result, 'ts');
        return this.parseOrderBook(result, symbol, timestamp, 'b', 'a');
    }
    parseBalance(response) {
        //
        // cross
        //     {
        //         "retCode": 0,
        //         "retMsg": "success",
        //         "result": {
        //             "acctBalanceSum": "0.122995614474732872",
        //             "debtBalanceSum": "0.011734191124529754",
        //             "loanAccountList": [
        //                 {
        //                     "free": "0.001143855",
        //                     "interest": "0",
        //                     "loan": "0",
        //                     "locked": "0",
        //                     "tokenId": "BTC",
        //                     "total": "0.001143855"
        //                 },
        //                 {
        //                     "free": "200.00005568",
        //                     "interest": "0.0008391",
        //                     "loan": "200",
        //                     "locked": "0",
        //                     "tokenId": "USDT",
        //                     "total": "200.00005568"
        //                 },
        //             ],
        //             "riskRate": "0.0954",
        //             "status": 1
        //         },
        //         "retExtInfo": {},
        //         "time": 1669843584123
        //     }
        //
        // funding
        //     {
        //         "retCode": 0,
        //         "retMsg": "success",
        //         "result": {
        //             "memberId": "533285",
        //             "accountType": "FUND",
        //             "balance": [
        //                 {
        //                     "coin": "USDT",
        //                     "transferBalance": "1010",
        //                     "walletBalance": "1010",
        //                     "bonus": ""
        //                 },
        //                 {
        //                     "coin": "USDC",
        //                     "transferBalance": "0",
        //                     "walletBalance": "0",
        //                     "bonus": ""
        //                 }
        //             ]
        //         },
        //         "retExtInfo": {},
        //         "time": 1675865290069
        //     }
        //
        //  spot & swap
        //     {
        //         "retCode": 0,
        //         "retMsg": "OK",
        //         "result": {
        //             "list": [
        //                 {
        //                     "totalEquity": "18070.32797922",
        //                     "accountIMRate": "0.0101",
        //                     "totalMarginBalance": "18070.32797922",
        //                     "totalInitialMargin": "182.60183684",
        //                     "accountType": "UNIFIED",
        //                     "totalAvailableBalance": "17887.72614237",
        //                     "accountMMRate": "0",
        //                     "totalPerpUPL": "-0.11001349",
        //                     "totalWalletBalance": "18070.43799271",
        //                     "accountLTV": "0.017",
        //                     "totalMaintenanceMargin": "0.38106773",
        //                     "coin": [
        //                         {
        //                             "availableToBorrow": "2.5",
        //                             "bonus": "0",
        //                             "accruedInterest": "0",
        //                             "availableToWithdraw": "0.805994",
        //                             "totalOrderIM": "0",
        //                             "equity": "0.805994",
        //                             "totalPositionMM": "0",
        //                             "usdValue": "12920.95352538",
        //                             "unrealisedPnl": "0",
        //                             "borrowAmount": "0",
        //                             "totalPositionIM": "0",
        //                             "walletBalance": "0.805994",
        //                             "cumRealisedPnl": "0",
        //                             "coin": "BTC"
        //                         }
        //                     ]
        //                 }
        //             ]
        //         },
        //         "retExtInfo": {},
        //         "time": 1672125441042
        //     }
        //
        const timestamp = this.safeInteger(response, 'time');
        const result = {
            'info': response,
            'timestamp': timestamp,
            'datetime': this.iso8601(timestamp),
        };
        const responseResult = this.safeDict(response, 'result', {});
        const currencyList = this.safeListN(responseResult, ['loanAccountList', 'list', 'balance']);
        if (currencyList === undefined) {
            // usdc wallet
            const code = 'USDC';
            const account = this.account();
            account['free'] = this.safeString(responseResult, 'availableBalance');
            account['total'] = this.safeString(responseResult, 'walletBalance');
            result[code] = account;
        }
        else {
            for (let i = 0; i < currencyList.length; i++) {
                const entry = currencyList[i];
                const accountType = this.safeString(entry, 'accountType');
                if (accountType === 'UNIFIED' || accountType === 'CONTRACT' || accountType === 'SPOT') {
                    const coins = this.safeList(entry, 'coin');
                    for (let j = 0; j < coins.length; j++) {
                        const account = this.account();
                        const coinEntry = coins[j];
                        const loan = this.safeString(coinEntry, 'borrowAmount');
                        const interest = this.safeString(coinEntry, 'accruedInterest');
                        if ((loan !== undefined) && (interest !== undefined)) {
                            account['debt'] = Precise["default"].stringAdd(loan, interest);
                        }
                        account['total'] = this.safeString(coinEntry, 'walletBalance');
                        const free = this.safeString2(coinEntry, 'availableToWithdraw', 'free');
                        if (free !== undefined) {
                            account['free'] = free;
                        }
                        else {
                            const locked = this.safeString(coinEntry, 'locked', '0');
                            const totalPositionIm = this.safeString(coinEntry, 'totalPositionIM', '0');
                            const totalOrderIm = this.safeString(coinEntry, 'totalOrderIM', '0');
                            let totalUsed = Precise["default"].stringAdd(locked, totalPositionIm);
                            totalUsed = Precise["default"].stringAdd(totalUsed, totalOrderIm);
                            account['used'] = totalUsed;
                        }
                        // account['used'] = this.safeString (coinEntry, 'locked');
                        const currencyId = this.safeString(coinEntry, 'coin');
                        const code = this.safeCurrencyCode(currencyId);
                        result[code] = account;
                    }
                }
                else {
                    const account = this.account();
                    const loan = this.safeString(entry, 'loan');
                    const interest = this.safeString(entry, 'interest');
                    if ((loan !== undefined) && (interest !== undefined)) {
                        account['debt'] = Precise["default"].stringAdd(loan, interest);
                    }
                    account['total'] = this.safeString2(entry, 'total', 'walletBalance');
                    account['free'] = this.safeStringN(entry, ['free', 'availableBalanceWithoutConvert', 'availableBalance', 'transferBalance']);
                    account['used'] = this.safeString(entry, 'locked');
                    const currencyId = this.safeStringN(entry, ['tokenId', 'coin', 'currencyCoin']);
                    const code = this.safeCurrencyCode(currencyId);
                    result[code] = account;
                }
            }
        }
        return this.safeBalance(result);
    }
    /**
     * @method
     * @name bybit#fetchBalance
     * @description query for balance and get the amount of funds available for trading or funds locked in orders
     * @see https://bybit-exchange.github.io/docs/v5/spot-margin-normal/account-info
     * @see https://bybit-exchange.github.io/docs/v5/asset/all-balance
     * @see https://bybit-exchange.github.io/docs/v5/account/wallet-balance
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @param {string} [params.type] wallet type, ['spot', 'swap', 'funding']
     * @returns {object} a [balance structure]{@link https://docs.ccxt.com/#/?id=balance-structure}
     */
    async fetchBalance(params = {}) {
        await this.loadMarkets();
        const request = {};
        const [enableUnifiedMargin, enableUnifiedAccount] = await this.isUnifiedEnabled();
        const isUnifiedAccount = (enableUnifiedMargin || enableUnifiedAccount);
        let type = undefined;
        // don't use getBybitType here
        [type, params] = this.handleMarketTypeAndParams('fetchBalance', undefined, params);
        let subType = undefined;
        [subType, params] = this.handleSubTypeAndParams('fetchBalance', undefined, params);
        if ((type === 'swap') || (type === 'future')) {
            type = subType;
        }
        const lowercaseRawType = (type !== undefined) ? type.toLowerCase() : undefined;
        const isSpot = (type === 'spot');
        const isLinear = (type === 'linear');
        const isInverse = (type === 'inverse');
        const isFunding = (lowercaseRawType === 'fund') || (lowercaseRawType === 'funding');
        if (isUnifiedAccount) {
            const unifiedMarginStatus = this.safeInteger(this.options, 'unifiedMarginStatus', 6);
            if (unifiedMarginStatus < 5) {
                // it's not uta.20 where inverse are unified
                if (isInverse) {
                    type = 'contract';
                }
                else {
                    type = 'unified';
                }
            }
            else {
                type = 'unified'; // uta.20 where inverse are unified
            }
        }
        else {
            if (isLinear || isInverse) {
                type = 'contract';
            }
        }
        const accountTypes = this.safeDict(this.options, 'accountsByType', {});
        const unifiedType = this.safeStringUpper(accountTypes, type, type);
        let marginMode = undefined;
        [marginMode, params] = this.handleMarginModeAndParams('fetchBalance', params);
        let response = undefined;
        if (isSpot && (marginMode !== undefined)) {
            response = await this.privateGetV5SpotCrossMarginTradeAccount(this.extend(request, params));
        }
        else if (isFunding) {
            // use this endpoint only we have no other choice
            // because it requires transfer permission
            request['accountType'] = 'FUND';
            response = await this.privateGetV5AssetTransferQueryAccountCoinsBalance(this.extend(request, params));
        }
        else {
            request['accountType'] = unifiedType;
            response = await this.privateGetV5AccountWalletBalance(this.extend(request, params));
        }
        //
        // cross
        //     {
        //         "retCode": 0,
        //         "retMsg": "success",
        //         "result": {
        //             "acctBalanceSum": "0.122995614474732872",
        //             "debtBalanceSum": "0.011734191124529754",
        //             "loanAccountList": [
        //                 {
        //                     "free": "0.001143855",
        //                     "interest": "0",
        //                     "loan": "0",
        //                     "locked": "0",
        //                     "tokenId": "BTC",
        //                     "total": "0.001143855"
        //                 },
        //                 {
        //                     "free": "200.00005568",
        //                     "interest": "0.0008391",
        //                     "loan": "200",
        //                     "locked": "0",
        //                     "tokenId": "USDT",
        //                     "total": "200.00005568"
        //                 },
        //             ],
        //             "riskRate": "0.0954",
        //             "status": 1
        //         },
        //         "retExtInfo": {},
        //         "time": 1669843584123
        //     }
        //
        // funding
        //     {
        //         "retCode": 0,
        //         "retMsg": "success",
        //         "result": {
        //             "memberId": "533285",
        //             "accountType": "FUND",
        //             "balance": [
        //                 {
        //                     "coin": "USDT",
        //                     "transferBalance": "1010",
        //                     "walletBalance": "1010",
        //                     "bonus": ""
        //                 },
        //                 {
        //                     "coin": "USDC",
        //                     "transferBalance": "0",
        //                     "walletBalance": "0",
        //                     "bonus": ""
        //                 }
        //             ]
        //         },
        //         "retExtInfo": {},
        //         "time": 1675865290069
        //     }
        //
        //  spot & swap
        //     {
        //         "retCode": 0,
        //         "retMsg": "OK",
        //         "result": {
        //             "list": [
        //                 {
        //                     "totalEquity": "18070.32797922",
        //                     "accountIMRate": "0.0101",
        //                     "totalMarginBalance": "18070.32797922",
        //                     "totalInitialMargin": "182.60183684",
        //                     "accountType": "UNIFIED",
        //                     "totalAvailableBalance": "17887.72614237",
        //                     "accountMMRate": "0",
        //                     "totalPerpUPL": "-0.11001349",
        //                     "totalWalletBalance": "18070.43799271",
        //                     "accountLTV": "0.017",
        //                     "totalMaintenanceMargin": "0.38106773",
        //                     "coin": [
        //                         {
        //                             "availableToBorrow": "2.5",
        //                             "bonus": "0",
        //                             "accruedInterest": "0",
        //                             "availableToWithdraw": "0.805994",
        //                             "totalOrderIM": "0",
        //                             "equity": "0.805994",
        //                             "totalPositionMM": "0",
        //                             "usdValue": "12920.95352538",
        //                             "unrealisedPnl": "0",
        //                             "borrowAmount": "0",
        //                             "totalPositionIM": "0",
        //                             "walletBalance": "0.805994",
        //                             "cumRealisedPnl": "0",
        //                             "coin": "BTC"
        //                         }
        //                     ]
        //                 }
        //             ]
        //         },
        //         "retExtInfo": {},
        //         "time": 1672125441042
        //     }
        //
        return this.parseBalance(response);
    }
    parseOrderStatus(status) {
        const statuses = {
            // v3 spot
            'NEW': 'open',
            'PARTIALLY_FILLED': 'open',
            'FILLED': 'closed',
            'CANCELED': 'canceled',
            'PENDING_CANCEL': 'open',
            'PENDING_NEW': 'open',
            'REJECTED': 'rejected',
            'PARTIALLY_FILLED_CANCELLED': 'closed',
            // v3 contract / unified margin / unified account
            'Created': 'open',
            'New': 'open',
            'Rejected': 'rejected',
            'PartiallyFilled': 'open',
            'PartiallyFilledCanceled': 'closed',
            'Filled': 'closed',
            'PendingCancel': 'open',
            'Cancelled': 'canceled',
            // below this line the status only pertains to conditional orders
            'Untriggered': 'open',
            'Deactivated': 'canceled',
            'Triggered': 'open',
            'Active': 'open',
        };
        return this.safeString(statuses, status, status);
    }
    parseTimeInForce(timeInForce) {
        const timeInForces = {
            'GoodTillCancel': 'GTC',
            'ImmediateOrCancel': 'IOC',
            'FillOrKill': 'FOK',
            'PostOnly': 'PO',
        };
        return this.safeString(timeInForces, timeInForce, timeInForce);
    }
    parseOrder(order, market = undefined) {
        //
        // v1 for usdc normal account
        //     {
        //         "symbol": "BTCPERP",
        //         "orderType": "Market",
        //         "orderLinkId": "",
        //         "orderId": "36190ad3-de08-4b83-9ad3-56942f684b79",
        //         "cancelType": "UNKNOWN",
        //         "stopOrderType": "UNKNOWN",
        //         "orderStatus": "Filled",
        //         "updateTimeStamp": "1692769133267",
        //         "takeProfit": "0.0000",
        //         "cumExecValue": "259.6830",
        //         "createdAt": "1692769133261",
        //         "blockTradeId": "",
        //         "orderPnl": "",
        //         "price": "24674.7",
        //         "tpTriggerBy": "UNKNOWN",
        //         "timeInForce": "ImmediateOrCancel",
        //         "updatedAt": "1692769133267",
        //         "basePrice": "0.0",
        //         "realisedPnl": "0.0000",
        //         "side": "Sell",
        //         "triggerPrice": "0.0",
        //         "cumExecFee": "0.1429",
        //         "leavesQty": "0.000",
        //         "cashFlow": "",
        //         "slTriggerBy": "UNKNOWN",
        //         "iv": "",
        //         "closeOnTrigger": "UNKNOWN",
        //         "cumExecQty": "0.010",
        //         "reduceOnly": 0,
        //         "qty": "0.010",
        //         "stopLoss": "0.0000",
        //         "triggerBy": "UNKNOWN",
        //         "orderIM": ""
        //     }
        //
        // v5
        //     {
        //         "orderId": "14bad3a1-6454-43d8-bcf2-5345896cf74d",
        //         "orderLinkId": "YLxaWKMiHU",
        //         "blockTradeId": "",
        //         "symbol": "BTCUSDT",
        //         "price": "26864.40",
        //         "qty": "0.003",
        //         "side": "Buy",
        //         "isLeverage": "",
        //         "positionIdx": 1,
        //         "orderStatus": "Cancelled",
        //         "cancelType": "UNKNOWN",
        //         "rejectReason": "EC_PostOnlyWillTakeLiquidity",
        //         "avgPrice": "0",
        //         "leavesQty": "0.000",
        //         "leavesValue": "0",
        //         "cumExecQty": "0.000",
        //         "cumExecValue": "0",
        //         "cumExecFee": "0",
        //         "timeInForce": "PostOnly",
        //         "orderType": "Limit",
        //         "stopOrderType": "UNKNOWN",
        //         "orderIv": "",
        //         "triggerPrice": "0.00",
        //         "takeProfit": "0.00",
        //         "stopLoss": "0.00",
        //         "tpTriggerBy": "UNKNOWN",
        //         "slTriggerBy": "UNKNOWN",
        //         "triggerDirection": 0,
        //         "triggerBy": "UNKNOWN",
        //         "lastPriceOnCreated": "0.00",
        //         "reduceOnly": false,
        //         "closeOnTrigger": false,
        //         "smpType": "None",
        //         "smpGroup": 0,
        //         "smpOrderId": "",
        //         "tpslMode": "",
        //         "tpLimitPrice": "",
        //         "slLimitPrice": "",
        //         "placeType": "",
        //         "createdTime": "1684476068369",
        //         "updatedTime": "1684476068372"
        //     }
        // createOrders failed order
        //    {
        //        "category": "linear",
        //        "symbol": "LTCUSDT",
        //        "orderId": '',
        //        "orderLinkId": '',
        //        "createAt": '',
        //        "code": "10001",
        //        "msg": "The number of contracts exceeds maximum limit allowed: too large"
        //    }
        //
        const code = this.safeString(order, 'code');
        if (code !== undefined) {
            if (code !== '0') {
                const category = this.safeString(order, 'category');
                const inferredMarketType = (category === 'spot') ? 'spot' : 'contract';
                return this.safeOrder({
                    'info': order,
                    'status': 'rejected',
                    'id': this.safeString(order, 'orderId'),
                    'clientOrderId': this.safeString(order, 'orderLinkId'),
                    'symbol': this.safeSymbol(this.safeString(order, 'symbol'), undefined, undefined, inferredMarketType),
                });
            }
        }
        const marketId = this.safeString(order, 'symbol');
        const isContract = ('tpslMode' in order);
        let marketType = undefined;
        if (market !== undefined) {
            marketType = market['type'];
        }
        else {
            marketType = isContract ? 'contract' : 'spot';
        }
        market = this.safeMarket(marketId, market, undefined, marketType);
        const symbol = market['symbol'];
        const timestamp = this.safeInteger2(order, 'createdTime', 'createdAt');
        const marketUnit = this.safeString(order, 'marketUnit', 'baseCoin');
        const id = this.safeString(order, 'orderId');
        const type = this.safeStringLower(order, 'orderType');
        const price = this.safeString(order, 'price');
        let amount = undefined;
        let cost = undefined;
        if (marketUnit === 'baseCoin') {
            amount = this.safeString(order, 'qty');
            cost = this.safeString(order, 'cumExecValue');
        }
        else {
            cost = this.safeString(order, 'cumExecValue');
        }
        const filled = this.safeString(order, 'cumExecQty');
        const remaining = this.safeString(order, 'leavesQty');
        const lastTradeTimestamp = this.safeInteger2(order, 'updatedTime', 'updatedAt');
        const rawStatus = this.safeString(order, 'orderStatus');
        const status = this.parseOrderStatus(rawStatus);
        const side = this.safeStringLower(order, 'side');
        let fee = undefined;
        const feeCostString = this.safeString(order, 'cumExecFee');
        if (feeCostString !== undefined) {
            let feeCurrencyCode = undefined;
            if (market['spot']) {
                if (Precise["default"].stringGt(feeCostString, '0')) {
                    if (side === 'buy') {
                        feeCurrencyCode = market['base'];
                    }
                    else {
                        feeCurrencyCode = market['quote'];
                    }
                }
                else {
                    if (side === 'buy') {
                        feeCurrencyCode = market['quote'];
                    }
                    else {
                        feeCurrencyCode = market['base'];
                    }
                }
            }
            else {
                feeCurrencyCode = market['inverse'] ? market['base'] : market['settle'];
            }
            fee = {
                'cost': this.parseNumber(feeCostString),
                'currency': feeCurrencyCode,
            };
        }
        let clientOrderId = this.safeString(order, 'orderLinkId');
        if ((clientOrderId !== undefined) && (clientOrderId.length < 1)) {
            clientOrderId = undefined;
        }
        const avgPrice = this.omitZero(this.safeString(order, 'avgPrice'));
        const rawTimeInForce = this.safeString(order, 'timeInForce');
        const timeInForce = this.parseTimeInForce(rawTimeInForce);
        const triggerPrice = this.omitZero(this.safeString(order, 'triggerPrice'));
        const reduceOnly = this.safeBool(order, 'reduceOnly');
        let takeProfitPrice = this.omitZero(this.safeString(order, 'takeProfit'));
        let stopLossPrice = this.omitZero(this.safeString(order, 'stopLoss'));
        const triggerDirection = this.safeString(order, 'triggerDirection');
        const isAscending = (triggerDirection === '1');
        const isStopOrderType2 = (triggerPrice !== undefined) && reduceOnly;
        if ((stopLossPrice === undefined) && isStopOrderType2) {
            // check if order is stop order type 2 - stopLossPrice
            if (isAscending && (side === 'buy')) {
                // stopLoss order against short position
                stopLossPrice = triggerPrice;
            }
            if (!isAscending && (side === 'sell')) {
                // stopLoss order against a long position
                stopLossPrice = triggerPrice;
            }
        }
        if ((takeProfitPrice === undefined) && isStopOrderType2) {
            // check if order is stop order type 2 - takeProfitPrice
            if (isAscending && (side === 'sell')) {
                // takeprofit order against a long position
                takeProfitPrice = triggerPrice;
            }
            if (!isAscending && (side === 'buy')) {
                // takeprofit order against a short position
                takeProfitPrice = triggerPrice;
            }
        }
        return this.safeOrder({
            'info': order,
            'id': id,
            'clientOrderId': clientOrderId,
            'timestamp': timestamp,
            'datetime': this.iso8601(timestamp),
            'lastTradeTimestamp': lastTradeTimestamp,
            'lastUpdateTimestamp': lastTradeTimestamp,
            'symbol': symbol,
            'type': type,
            'timeInForce': timeInForce,
            'postOnly': undefined,
            'reduceOnly': this.safeBool(order, 'reduceOnly'),
            'side': side,
            'price': price,
            'triggerPrice': triggerPrice,
            'takeProfitPrice': takeProfitPrice,
            'stopLossPrice': stopLossPrice,
            'amount': amount,
            'cost': cost,
            'average': avgPrice,
            'filled': filled,
            'remaining': remaining,
            'status': status,
            'fee': fee,
            'trades': undefined,
        }, market);
    }
    /**
     * @method
     * @name bybit#createMarketBuyOrderWithCost
     * @description create a market buy order by providing the symbol and cost
     * @see https://bybit-exchange.github.io/docs/v5/order/create-order
     * @param {string} 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 {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
     */
    async createMarketBuyOrderWithCost(symbol, cost, params = {}) {
        await this.loadMarkets();
        const market = this.market(symbol);
        if (!market['spot']) {
            throw new errors.NotSupported(this.id + ' createMarketBuyOrderWithCost() supports spot orders only');
        }
        const req = {
            'cost': cost,
        };
        return await this.createOrder(symbol, 'market', 'buy', -1, undefined, this.extend(req, params));
    }
    /**
     * @method
     * @name bybit#createMarkeSellOrderWithCost
     * @description create a market sell order by providing the symbol and cost
     * @see https://bybit-exchange.github.io/docs/v5/order/create-order
     * @param {string} 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 {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
     */
    async createMarketSellOrderWithCost(symbol, cost, params = {}) {
        await this.loadMarkets();
        const types = await this.isUnifiedEnabled();
        const enableUnifiedAccount = types[1];
        if (!enableUnifiedAccount) {
            throw new errors.NotSupported(this.id + ' createMarketSellOrderWithCost() supports UTA accounts only');
        }
        const market = this.market(symbol);
        if (!market['spot']) {
            throw new errors.NotSupported(this.id + ' createMarketSellOrderWithCost() supports spot orders only');
        }
        const req = {
            'cost': cost,
        };
        return await this.createOrder(symbol, 'market', 'sell', -1, undefined, this.extend(req, params));
    }
    /**
     * @method
     * @name bybit#createOrder
     * @description create a trade order
     * @see https://bybit-exchange.github.io/docs/v5/order/create-order
     * @see https://bybit-exchange.github.io/docs/v5/position/trading-stop
     * @param {string} symbol unified symbol of the market to create an order in
     * @param {string} type 'market' or 'limit'
     * @param {string} side 'buy' or 'sell'
     * @param {float} amount how much of currency you want to trade in units of base currency
     * @param {float} [price] the price at which the order is to be fulfilled, in units of the quote currency, ignored in market orders
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @param {string} [params.timeInForce] "GTC", "IOC", "FOK"
     * @param {bool} [params.postOnly] true or false whether the order is post-only
     * @param {bool} [params.reduceOnly] true or false whether the order is reduce-only
     * @param {string} [params.positionIdx] *contracts only* 0 for one-way mode, 1 buy side of hedged mode, 2 sell side of hedged mode
     * @param {bool} [params.hedged] *contracts only* true for hedged mode, false for one way mode, default is false
     * @param {int} [params.isLeverage] *unified spot only* false then spot trading true then margin trading
     * @param {string} [params.tpslMode] *contract only* 'full' or 'partial'
     * @param {string} [params.mmp] *option only* market maker protection
     * @param {string} [params.triggerDirection] *contract only* the direction for trigger orders, 'above' or 'below'
     * @param {float} [params.triggerPrice] The price at which a trigger order is triggered at
     * @param {float} [params.stopLossPrice] The price at which a stop loss order is triggered at
     * @param {float} [params.takeProfitPrice] The price at which a take profit order is triggered at
     * @param {object} [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 {object} [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 {string} [params.trailingAmount] the quote amount to trail away from the current market price
     * @param {string} [params.trailingTriggerPrice] the price to trigger a trailing order, default uses the price argument
     * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
     */
    async createOrder(symbol, type, side, amount, price = undefined, params = {}) {
        await this.loadMarkets();
        const market = this.market(symbol);
        const parts = await this.isUnifiedEnabled();
        const enableUnifiedAccount = parts[1];
        const trailingAmount = this.safeString2(params, 'trailingAmount', 'trailingStop');
        const stopLossPrice = this.safeString(params, 'stopLossPrice');
        const takeProfitPrice = this.safeString(params, 'takeProfitPrice');
        const isTrailingAmountOrder = trailingAmount !== undefined;
        const isStopLoss = stopLossPrice !== undefined;
        const isTakeProfit = takeProfitPrice !== undefined;
        const orderRequest = this.createOrderRequest(symbol, type, side, amount, price, params, enableUnifiedAccount);
        let defaultMethod = undefined;
        if (isTrailingAmountOrder || isStopLoss || isTakeProfit) {
            defaultMethod = 'privatePostV5PositionTradingStop';
        }
        else {
            defaultMethod = 'privatePostV5OrderCreate';
        }
        let method = undefined;
        [method, params] = this.handleOptionAndParams(params, 'createOrder', 'method', defaultMethod);
        let response = undefined;
        if (method === 'privatePostV5PositionTradingStop') {
            response = await this.privatePostV5PositionTradingStop(orderRequest);
        }
        else {
            response = await this.privatePostV5OrderCreate(orderRequest); // already extended inside createOrderRequest
        }
        //
        //     {
        //         "retCode": 0,
        //         "retMsg": "OK",
        //         "result": {
        //             "orderId": "1321003749386327552",
        //             "orderLinkId": "spot-test-postonly"
        //         },
        //         "retExtInfo": {},
        //         "time": 1672211918471
        //     }
        //
        const order = this.safeDict(response, 'result', {});
        return this.parseOrder(order, market);
    }
    createOrderRequest(symbol, type, side, amount, price = undefined, params = {}, isUTA = true) {
        const market = this.market(symbol);
        symbol = market['symbol'];
        const lowerCaseType = type.toLowerCase();
        if ((price === undefined) && (lowerCaseType === 'limit')) {
            throw new errors.ArgumentsRequired(this.id + ' createOrder requires a price argument for limit orders');
        }
        const request = {
            'symbol': market['id'],
            // 'side': this.capitalize (side),
            // 'orderType': this.capitalize (lowerCaseType), // limit or market
            // 'timeInForce': 'GTC', // IOC, FOK, PostOnly
            // 'takeProfit': 123.45, // take profit price, only take effect upon opening the position
            // 'stopLoss': 123.45, // stop loss price, only take effect upon opening the position
            // 'reduceOnly': false, // reduce only, required for linear orders
            // when creating a closing order, bybit recommends a True value for
            //  closeOnTrigger to avoid failing due to insufficient available margin
            // 'closeOnTrigger': false, required for linear orders
            // 'orderLinkId': 'string', // unique client order id, max 36 characters
            // 'triggerPrice': 123.46, // trigger price, required for conditional orders
            // 'triggerBy': 'MarkPrice', // IndexPrice, MarkPrice, LastPrice
            // 'tpTriggerby': 'MarkPrice', // IndexPrice, MarkPrice, LastPrice
            // 'slTriggerBy': 'MarkPrice', // IndexPrice, MarkPrice, LastPrice
            // 'mmp': false // market maker protection
            // 'positionIdx': 0, // Position mode. Unified account has one-way mode only (0)
            // 'triggerDirection': 1, // Conditional order param. Used to identify the expected direction of the conditional order. 1: triggered when market price rises to triggerPrice 2: triggered when market price falls to triggerPrice
            // Valid for spot only.
            // 'isLeverage': 0, // Whether to borrow. 0(default): false, 1: true
            // 'orderFilter': 'Order' // Order,tpslOrder. If not passed, Order by default
            // Valid for option only.
            // 'orderIv': '0', // Implied volatility; parameters are passed according to the real value; for example, for 10%, 0.1 is passed
        };
        const hedged = this.safeBool(params, 'hedged', false);
        const reduceOnly = this.safeBool(params, 'reduceOnly');
        let triggerPrice = this.safeValue2(params, 'triggerPrice', 'stopPrice');
        const stopLossTriggerPrice = this.safeValue(params, 'stopLossPrice');
        const takeProfitTriggerPrice = this.safeValue(params, 'takeProfitPrice');
        const stopLoss = this.safeValue(params, 'stopLoss');
        const takeProfit = this.safeValue(params, 'takeProfit');
        const trailingTriggerPrice = this.safeString2(params, 'trailingTriggerPrice', 'activePrice', this.numberToString(price));
        const trailingAmount = this.safeString2(params, 'trailingAmount', 'trailingStop');
        const isTrailingAmountOrder = trailingAmount !== undefined;
        const isTriggerOrder = triggerPrice !== undefined;
        const isStopLossTriggerOrder = stopLossTriggerPrice !== undefined;
        const isTakeProfitTriggerOrder = takeProfitTriggerPrice !== undefined;
        const isStopLoss = stopLoss !== undefined;
        const isTakeProfit = takeProfit !== undefined;
        const isMarket = lowerCaseType === 'market';
        const isLimit = lowerCaseType === 'limit';
        const isBuy = side === 'buy';
        let defaultMethod = undefined;
        if (isTrailingAmountOrder || isStopLossTriggerOrder || isTakeProfitTriggerOrder) {
            defaultMethod = 'privatePostV5PositionTradingStop';
        }
        else {
            defaultMethod = 'privatePostV5OrderCreate';
        }
        let method = undefined;
        [method, params] = this.handleOptionAndParams(params, 'createOrder', 'method', defaultMethod);
        const isAlternativeEndpoint = method === 'privatePostV5PositionTradingStop';
        const amountString = this.getAmount(symbol, amount);
        const priceString = (price !== undefined) ? this.getPrice(symbol, this.numberToString(price)) : undefined;
        if (isTrailingAmountOrder || isAlternativeEndpoint) {
            if (isStopLoss || isTakeProfit || isTriggerOrder || market['spot']) {
                throw new errors.InvalidOrder(this.id + ' the API endpoint used only supports contract trailingAmount, stopLossPrice and takeProfitPrice orders');
            }
            if (isStopLossTriggerOrder || isTakeProfitTriggerOrder) {
                if (isStopLossTriggerOrder) {
                    request['stopLoss'] = this.getPrice(symbol, stopLossTriggerPrice);
                    if (isLimit) {
                        request['tpslMode'] = 'Partial';
                        request['slOrderType'] = 'Limit';
                        request['slLimitPrice'] = priceString;
                        request['slSize'] = amountString;
                    }
                }
                else if (isTakeProfitTriggerOrder) {
                    request['takeProfit'] = this.getPrice(symbol, takeProfitTriggerPrice);
                    if (isLimit) {
                        request['tpslMode'] = 'Partial';
                        request['tpOrderType'] = 'Limit';
                        request['tpLimitPrice'] = priceString;
                        request['tpSize'] = amountString;
                    }
                }
            }
        }
        else {
            request['side'] = this.capitalize(side);
            request['orderType'] = this.capitalize(lowerCaseType);
            const timeInForce = this.safeStringLower(params, 'timeInForce'); // this is same as exchange specific param
            let postOnly = undefined;
            [postOnly, params] = this.handlePostOnly(isMarket, timeInForce === 'postonly', params);
            if (postOnly) {
                request['timeInForce'] = 'PostOnly';
            }
            else if (timeInForce === 'gtc') {
                request['timeInForce'] = 'GTC';
            }
            else if (timeInForce === 'fok') {
                request['timeInForce'] = 'FOK';
            }
            else if (timeInForce === 'ioc') {
                request['timeInForce'] = 'IOC';
            }
            if (market['spot']) {
                // only works for spot market
                if (triggerPrice !== undefined) {
                    request['orderFilter'] = 'StopOrder';
                }
                else if (stopLossTriggerPrice !== undefined || takeProfitTriggerPrice !== undefined || isStopLoss || isTakeProfit) {
                    request['orderFilter'] = 'tpslOrder';
                }
            }
            const clientOrderId = this.safeString(params, 'clientOrderId');
            if (clientOrderId !== undefined) {
                request['orderLinkId'] = clientOrderId;
            }
            else if (market['option']) {
                // mandatory field for options
                request['orderLinkId'] = this.uuid16();
            }
            if (isLimit) {
                request['price'] = priceString;
            }
        }
        let category = undefined;
        [category, params] = this.getBybitType('createOrderRequest', market, params);
        request['category'] = category;
        const cost = this.safeString(params, 'cost');
        params = this.omit(params, 'cost');
        // if the cost is inferable, let's keep the old logic and ignore marketUnit, to minimize the impact of the changes
        const isMarketBuyAndCostInferable = (lowerCaseType === 'market') && (side === 'buy') && ((price !== undefined) || (cost !== undefined));
        if (market['spot'] && (type === 'market') && isUTA && !isMarketBuyAndCostInferable) {
            // UTA account can specify the cost of the order on both sides
            if ((cost !== undefined) || (price !== undefined)) {
                request['marketUnit'] = 'quoteCoin';
                let orderCost = undefined;
                if (cost !== undefined) {
                    orderCost = cost;
                }
                else {
                    const quoteAmount = Precise["default"].stringMul(amountString, priceString);
                    orderCost = quoteAmount;
                }
                request['qty'] = this.getCost(symbol, orderCost);
            }
            else {
                request['marketUnit'] = 'baseCoin';
                request['qty'] = amountString;
            }
        }
        else if (market['spot'] && (type === 'market') && (side === 'buy')) {
            // classic accounts
            // for market buy it requires the amount of quote currency to spend
            let createMarketBuyOrderRequiresPrice = true;
            [createMarketBuyOrderRequiresPrice, params] = this.handleOptionAndParams(params, 'createOrder', 'createMarketBuyOrderRequiresPrice');
            if (createMarketBuyOrderRequiresPrice) {
                if ((price === undefined) && (cost === undefined)) {
                    throw new errors.InvalidOrder(this.id + ' createOrder() requires the price argument for market buy orders to calculate the total cost to spend (amount * price), alternatively set the createMarketBuyOrderRequiresPrice option or param to false and pass the cost to spend in the amount argument');
                }
                else {
                    const quoteAmount = Precise["default"].stringMul(this.numberToString(amount), priceString);
                    const costRequest = (cost !== undefined) ? cost : quoteAmount;
                    request['qty'] = this.getCost(symbol, costRequest);
                }
            }
            else {
                if (cost !== undefined) {
                    request['qty'] = this.getCost(symbol, this.numberToString(cost));
                }
                else if (price !== undefined) {
                    request['qty'] = this.getCost(symbol, Precise["default"].stringMul(amountString, priceString));
                }
                else {
                    request['qty'] = amountString;
                }
            }
        }
        else {
            if (!isTrailingAmountOrder && !isAlternativeEndpoint) {
                request['qty'] = amountString;
            }
        }
        if (isTrailingAmountOrder) {
            if (trailingTriggerPrice !== undefined) {
                request['activePrice'] = this.getPrice(symbol, trailingTriggerPrice);
            }
            request['trailingStop'] = trailingAmount;
        }
        else if (isTriggerOrder && !isAlternativeEndpoint) {
            const triggerDirection = this.safeString(params, 'triggerDirection');
            params = this.omit(params, ['triggerPrice', 'stopPrice', 'triggerDirection']);
            if (market['spot']) {
                if (triggerDirection !== undefined) {
                    throw new errors.NotSupported(this.id + ' createOrder() : trigger order does not support triggerDirection for spot markets yet');
                }
            }
            else {
                if (triggerDirection === undefined) {
                    throw new errors.ArgumentsRequired(this.id + ' stop/trigger orders require a triggerDirection parameter, either "above" or "below" to determine the direction of the trigger.');
                }
                const isAsending = ((triggerDirection === 'above') || (triggerDirection === '1'));
                request['triggerDirection'] = isAsending ? 1 : 2;
            }
            request['triggerPrice'] = this.getPrice(symbol, triggerPrice);
        }
        else if ((isStopLossTriggerOrder || isTakeProfitTriggerOrder) && !isAlternativeEndpoint) {
            if (isBuy) {
                request['triggerDirection'] = isStopLossTriggerOrder ? 1 : 2;
            }
            else {
                request['triggerDirection'] = isStopLossTriggerOrder ? 2 : 1;
            }
            triggerPrice = isStopLossTriggerOrder ? stopLossTriggerPrice : takeProfitTriggerPrice;
            request['triggerPrice'] = this.getPrice(symbol, triggerPrice);
            request['reduceOnly'] = true;
        }
        if ((isStopLoss || isTakeProfit) && !isAlternativeEndpoint) {
            if (isStopLoss) {
                const slTriggerPrice = this.safeValue2(stopLoss, 'triggerPrice', 'stopPrice', stopLoss);
                request['stopLoss'] = this.getPrice(symbol, slTriggerPrice);
                const slLimitPrice = this.safeValue(stopLoss, 'price');
                if (slLimitPrice !== undefined) {
                    request['tpslMode'] = 'Partial';
                    request['slOrderType'] = 'Limit';
                    request['slLimitPrice'] = this.getPrice(symbol, slLimitPrice);
                }
            }
            if (isTakeProfit) {
                const tpTriggerPrice = this.safeValue2(takeProfit, 'triggerPrice', 'stopPrice', takeProfit);
                request['takeProfit'] = this.getPrice(symbol, tpTriggerPrice);
                const tpLimitPrice = this.safeValue(takeProfit, 'price');
                if (tpLimitPrice !== undefined) {
                    request['tpslMode'] = 'Partial';
                    request['tpOrderType'] = 'Limit';
                    request['tpLimitPrice'] = this.getPrice(symbol, tpLimitPrice);
                }
            }
        }
        if (!market['spot'] && hedged) {
            if (reduceOnly) {
                params = this.omit(params, 'reduceOnly');
                side = (side === 'buy') ? 'sell' : 'buy';
            }
            request['positionIdx'] = (side === 'buy') ? 1 : 2;
        }
        params = this.omit(params, ['stopPrice', 'timeInForce', 'stopLossPrice', 'takeProfitPrice', 'postOnly', 'clientOrderId', 'triggerPrice', 'stopLoss', 'takeProfit', 'trailingAmount', 'trailingTriggerPrice', 'hedged']);
        return this.extend(request, params);
    }
    /**
     * @method
     * @name bybit#createOrders
     * @description create a list of trade orders
     * @see https://bybit-exchange.github.io/docs/v5/order/batch-place
     * @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 {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
     */
    async createOrders(orders, params = {}) {
        await this.loadMarkets();
        const accounts = await this.isUnifiedEnabled();
        const isUta = accounts[1];
        const ordersRequests = [];
        const orderSymbols = [];
        for (let i = 0; i < orders.length; i++) {
            const rawOrder = orders[i];
            const marketId = this.safeString(rawOrder, 'symbol');
            orderSymbols.push(marketId);
            const type = this.safeString(rawOrder, 'type');
            const side = this.safeString(rawOrder, 'side');
            const amount = this.safeValue(rawOrder, 'amount');
            const price = this.safeValue(rawOrder, 'price');
            const orderParams = this.safeDict(rawOrder, 'params', {});
            const orderRequest = this.createOrderRequest(marketId, type, side, amount, price, orderParams, isUta);
            delete orderRequest['category'];
            ordersRequests.push(orderRequest);
        }
        const symbols = this.marketSymbols(orderSymbols, undefined, false, true, true);
        const market = this.market(symbols[0]);
        const unifiedMarginStatus = this.safeInteger(this.options, 'unifiedMarginStatus', 6);
        let category = undefined;
        [category, params] = this.getBybitType('createOrders', market, params);
        if ((category === 'inverse') && (unifiedMarginStatus < 5)) {
            throw new errors.NotSupported(this.id + ' createOrders does not allow inverse orders for non UTA2.0 account');
        }
        const request = {
            'category': category,
            'request': ordersRequests,
        };
        const response = await this.privatePostV5OrderCreateBatch(this.extend(request, params));
        const result = this.safeDict(response, 'result', {});
        const data = this.safeList(result, 'list', []);
        const retInfo = this.safeDict(response, 'retExtInfo', {});
        const codes = this.safeList(retInfo, 'list', []);
        // extend the error with the unsuccessful orders
        for (let i = 0; i < codes.length; i++) {
            const code = codes[i];
            const retCode = this.safeInteger(code, 'code');
            if (retCode !== 0) {
                data[i] = this.extend(data[i], code);
            }
        }
        //
        // {
        //     "retCode":0,
        //     "retMsg":"OK",
        //     "result":{
        //        "list":[
        //           {
        //              "category":"linear",
        //              "symbol":"LTCUSDT",
        //              "orderId":"",
        //              "orderLinkId":"",
        //              "createAt":""
        //           },
        //           {
        //              "category":"linear",
        //              "symbol":"LTCUSDT",
        //              "orderId":"3c9f65b6-01ad-4ac0-9741-df17e02a4223",
        //              "orderLinkId":"",
        //              "createAt":"1698075516029"
        //           }
        //        ]
        //     },
        //     "retExtInfo":{
        //        "list":[
        //           {
        //              "code":10001,
        //              "msg":"The number of contracts exceeds maximum limit allowed: too large"
        //           },
        //           {
        //              "code":0,
        //              "msg":"OK"
        //           }
        //        ]
        //     },
        //     "time":1698075516029
        // }
        //
        return this.parseOrders(data);
    }
    editOrderRequest(id, symbol, type, side, amount = undefined, price = undefined, params = {}) {
        const market = this.market(symbol);
        const request = {
            'symbol': market['id'],
            'orderId': id,
            // 'orderLinkId': 'string', // unique client order id, max 36 characters
            // 'takeProfit': 123.45, // take profit price, only take effect upon opening the position
            // 'stopLoss': 123.45, // stop loss price, only take effect upon opening the position
            // 'triggerPrice': 123.45, // trigger price, required for conditional orders
            // 'triggerBy': 'MarkPrice', // IndexPrice, MarkPrice, LastPrice
            // 'tpTriggerby': 'MarkPrice', // IndexPrice, MarkPrice, LastPrice
            // 'slTriggerBy': 'MarkPrice', // IndexPrice, MarkPrice, LastPrice
            // Valid for option only.
            // 'orderIv': '0', // Implied volatility; parameters are passed according to the real value; for example, for 10%, 0.1 is passed
        };
        let category = undefined;
        [category, params] = this.getBybitType('editOrderRequest', market, params);
        request['category'] = category;
        if (amount !== undefined) {
            request['qty'] = this.getAmount(symbol, amount);
        }
        if (price !== undefined) {
            request['price'] = this.getPrice(symbol, this.numberToString(price));
        }
        let triggerPrice = this.safeString2(params, 'triggerPrice', 'stopPrice');
        const stopLossTriggerPrice = this.safeString(params, 'stopLossPrice');
        const takeProfitTriggerPrice = this.safeString(params, 'takeProfitPrice');
        const stopLoss = this.safeValue(params, 'stopLoss');
        const takeProfit = this.safeValue(params, 'takeProfit');
        const isStopLossTriggerOrder = stopLossTriggerPrice !== undefined;
        const isTakeProfitTriggerOrder = takeProfitTriggerPrice !== undefined;
        const isStopLoss = stopLoss !== undefined;
        const isTakeProfit = takeProfit !== undefined;
        if (isStopLossTriggerOrder || isTakeProfitTriggerOrder) {
            triggerPrice = isStopLossTriggerOrder ? stopLossTriggerPrice : takeProfitTriggerPrice;
        }
        if (triggerPrice !== undefined) {
            const triggerPriceRequest = (triggerPrice === '0') ? triggerPrice : this.getPrice(symbol, triggerPrice);
            request['triggerPrice'] = triggerPriceRequest;
            const triggerBy = this.safeString(params, 'triggerBy', 'LastPrice');
            request['triggerBy'] = triggerBy;
        }
        if (isStopLoss || isTakeProfit) {
            if (isStopLoss) {
                const slTriggerPrice = this.safeString2(stopLoss, 'triggerPrice', 'stopPrice', stopLoss);
                const stopLossRequest = (slTriggerPrice === '0') ? slTriggerPrice : this.getPrice(symbol, slTriggerPrice);
                request['stopLoss'] = stopLossRequest;
                const slTriggerBy = this.safeString(params, 'slTriggerBy', 'LastPrice');
                request['slTriggerBy'] = slTriggerBy;
            }
            if (isTakeProfit) {
                const tpTriggerPrice = this.safeString2(takeProfit, 'triggerPrice', 'stopPrice', takeProfit);
                const takeProfitRequest = (tpTriggerPrice === '0') ? tpTriggerPrice : this.getPrice(symbol, tpTriggerPrice);
                request['takeProfit'] = takeProfitRequest;
                const tpTriggerBy = this.safeString(params, 'tpTriggerBy', 'LastPrice');
                request['tpTriggerBy'] = tpTriggerBy;
            }
        }
        const clientOrderId = this.safeString(params, 'clientOrderId');
        if (clientOrderId !== undefined) {
            request['orderLinkId'] = clientOrderId;
        }
        params = this.omit(params, ['stopPrice', 'stopLossPrice', 'takeProfitPrice', 'triggerPrice', 'clientOrderId', 'stopLoss', 'takeProfit']);
        return request;
    }
    /**
     * @method
     * @name bybit#editOrder
     * @description edit a trade order
     * @see https://bybit-exchange.github.io/docs/v5/order/amend-order
     * @see https://bybit-exchange.github.io/docs/derivatives/unified/replace-order
     * @see https://bybit-exchange.github.io/docs/api-explorer/derivatives/trade/contract/replace-order
     * @param {string} id cancel order id
     * @param {string} symbol unified symbol of the market to create an order in
     * @param {string} type 'market' or 'limit'
     * @param {string} side 'buy' or 'sell'
     * @param {float} amount how much of currency you want to trade in units of base currency
     * @param {float} price the price at which the order is to be fulfilled, in units of the quote currency, ignored in market orders
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @param {float} [params.triggerPrice] The price that a trigger order is triggered at
     * @param {float} [params.stopLossPrice] The price that a stop loss order is triggered at
     * @param {float} [params.takeProfitPrice] The price that a take profit order is triggered at
     * @param {object} [params.takeProfit] *takeProfit object in params* containing the triggerPrice that the attached take profit order will be triggered
     * @param {float} [params.takeProfit.triggerPrice] take profit trigger price
     * @param {object} [params.stopLoss] *stopLoss object in params* containing the triggerPrice that the attached stop loss order will be triggered
     * @param {float} [params.stopLoss.triggerPrice] stop loss trigger price
     * @param {string} [params.triggerBy] 'IndexPrice', 'MarkPrice' or 'LastPrice', default is 'LastPrice', required if no initial value for triggerPrice
     * @param {string} [params.slTriggerBy] 'IndexPrice', 'MarkPrice' or 'LastPrice', default is 'LastPrice', required if no initial value for stopLoss
     * @param {string} [params.tpTriggerby] 'IndexPrice', 'MarkPrice' or 'LastPrice', default is 'LastPrice', required if no initial value for takeProfit
     * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
     */
    async editOrder(id, symbol, type, side, amount = undefined, price = undefined, params = {}) {
        await this.loadMarkets();
        if (symbol === undefined) {
            throw new errors.ArgumentsRequired(this.id + ' editOrder() requires a symbol argument');
        }
        const request = this.editOrderRequest(id, symbol, type, side, amount, price, params);
        const response = await this.privatePostV5OrderAmend(this.extend(request, params));
        //
        //     {
        //         "retCode": 0,
        //         "retMsg": "OK",
        //         "result": {
        //             "orderId": "c6f055d9-7f21-4079-913d-e6523a9cfffa",
        //             "orderLinkId": "linear-004"
        //         },
        //         "retExtInfo": {},
        //         "time": 1672217093461
        //     }
        //
        const result = this.safeDict(response, 'result', {});
        return this.safeOrder({
            'info': response,
            'id': this.safeString(result, 'orderId'),
        });
    }
    /**
     * @method
     * @name bybit#editOrders
     * @description edit a list of trade orders
     * @see https://bybit-exchange.github.io/docs/v5/order/batch-amend
     * @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 {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
     */
    async editOrders(orders, params = {}) {
        await this.loadMarkets();
        const ordersRequests = [];
        let orderSymbols = [];
        for (let i = 0; i < orders.length; i++) {
            const rawOrder = orders[i];
            const symbol = this.safeString(rawOrder, 'symbol');
            orderSymbols.push(symbol);
            const id = this.safeString(rawOrder, 'id');
            const type = this.safeString(rawOrder, 'type');
            const side = this.safeString(rawOrder, 'side');
            const amount = this.safeValue(rawOrder, 'amount');
            const price = this.safeValue(rawOrder, 'price');
            const orderParams = this.safeDict(rawOrder, 'params', {});
            const orderRequest = this.editOrderRequest(id, symbol, type, side, amount, price, orderParams);
            delete orderRequest['category'];
            ordersRequests.push(orderRequest);
        }
        orderSymbols = this.marketSymbols(orderSymbols, undefined, false, true, true);
        const market = this.market(orderSymbols[0]);
        const unifiedMarginStatus = this.safeInteger(this.options, 'unifiedMarginStatus', 6);
        let category = undefined;
        [category, params] = this.getBybitType('editOrders', market, params);
        if ((category === 'inverse') && (unifiedMarginStatus < 5)) {
            throw new errors.NotSupported(this.id + ' editOrders does not allow inverse orders for non UTA2.0 account');
        }
        const request = {
            'category': category,
            'request': ordersRequests,
        };
        const response = await this.privatePostV5OrderAmendBatch(this.extend(request, params));
        const result = this.safeDict(response, 'result', {});
        const data = this.safeList(result, 'list', []);
        const retInfo = this.safeDict(response, 'retExtInfo', {});
        const codes = this.safeList(retInfo, 'list', []);
        // extend the error with the unsuccessful orders
        for (let i = 0; i < codes.length; i++) {
            const code = codes[i];
            const retCode = this.safeInteger(code, 'code');
            if (retCode !== 0) {
                data[i] = this.extend(data[i], code);
            }
        }
        //
        // {
        //     "retCode": 0,
        //     "retMsg": "OK",
        //     "result": {
        //         "list": [
        //             {
        //                 "category": "option",
        //                 "symbol": "ETH-30DEC22-500-C",
        //                 "orderId": "b551f227-7059-4fb5-a6a6-699c04dbd2f2",
        //                 "orderLinkId": ""
        //             },
        //             {
        //                 "category": "option",
        //                 "symbol": "ETH-30DEC22-700-C",
        //                 "orderId": "fa6a595f-1a57-483f-b9d3-30e9c8235a52",
        //                 "orderLinkId": ""
        //             }
        //         ]
        //     },
        //     "retExtInfo": {
        //         "list": [
        //             {
        //                 "code": 0,
        //                 "msg": "OK"
        //             },
        //             {
        //                 "code": 0,
        //                 "msg": "OK"
        //             }
        //         ]
        //     },
        //     "time": 1672222808060
        // }
        //
        return this.parseOrders(data);
    }
    cancelOrderRequest(id, symbol = undefined, params = {}) {
        const market = this.market(symbol);
        const request = {
            'symbol': market['id'],
            // 'orderLinkId': 'string',
            // 'orderId': id,
            // conditional orders
            // 'orderFilter': '', // Valid for spot only. Order,tpslOrder. If not passed, Order by default
        };
        if (market['spot']) {
            // only works for spot market
            const isTrigger = this.safeBool2(params, 'stop', 'trigger', false);
            params = this.omit(params, ['stop', 'trigger']);
            request['orderFilter'] = isTrigger ? 'StopOrder' : 'Order';
        }
        if (id !== undefined) { // The user can also use argument params["orderLinkId"]
            request['orderId'] = id;
        }
        let category = undefined;
        [category, params] = this.getBybitType('cancelOrderRequest', market, params);
        request['category'] = category;
        return this.extend(request, params);
    }
    /**
     * @method
     * @name bybit#cancelOrder
     * @description cancels an open order
     * @see https://bybit-exchange.github.io/docs/v5/order/cancel-order
     * @param {string} id order id
     * @param {string} symbol unified symbol of the market the order was made in
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @param {boolean} [params.trigger] *spot only* whether the order is a trigger order
     * @param {boolean} [params.stop] alias for trigger
     * @param {string} [params.orderFilter] *spot only* 'Order' or 'StopOrder' or 'tpslOrder'
     * @returns {object} An [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
     */
    async cancelOrder(id, symbol = undefined, params = {}) {
        if (symbol === undefined) {
            throw new errors.ArgumentsRequired(this.id + ' cancelOrder() requires a symbol argument');
        }
        await this.loadMarkets();
        const market = this.market(symbol);
        const requestExtended = this.cancelOrderRequest(id, symbol, params);
        const response = await this.privatePostV5OrderCancel(requestExtended);
        //
        //     {
        //         "retCode": 0,
        //         "retMsg": "OK",
        //         "result": {
        //             "orderId": "c6f055d9-7f21-4079-913d-e6523a9cfffa",
        //             "orderLinkId": "linear-004"
        //         },
        //         "retExtInfo": {},
        //         "time": 1672217377164
        //     }
        //
        const result = this.safeDict(response, 'result', {});
        return this.parseOrder(result, market);
    }
    /**
     * @method
     * @name bybit#cancelOrders
     * @description cancel multiple orders
     * @see https://bybit-exchange.github.io/docs/v5/order/batch-cancel
     * @param {string[]} ids order ids
     * @param {string} symbol unified symbol of the market the order was made in
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @param {string[]} [params.clientOrderIds] client order ids
     * @returns {object} an list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
     */
    async cancelOrders(ids, symbol = undefined, params = {}) {
        if (symbol === undefined) {
            throw new errors.ArgumentsRequired(this.id + ' cancelOrders() requires a symbol argument');
        }
        await this.loadMarkets();
        const market = this.market(symbol);
        const types = await this.isUnifiedEnabled();
        const enableUnifiedAccount = types[1];
        if (!enableUnifiedAccount) {
            throw new errors.NotSupported(this.id + ' cancelOrders() supports UTA accounts only');
        }
        let category = undefined;
        [category, params] = this.getBybitType('cancelOrders', market, params);
        if (category === 'inverse') {
            throw new errors.NotSupported(this.id + ' cancelOrders does not allow inverse orders');
        }
        const ordersRequests = [];
        const clientOrderIds = this.safeList2(params, 'clientOrderIds', 'clientOids', []);
        params = this.omit(params, ['clientOrderIds', 'clientOids']);
        for (let i = 0; i < clientOrderIds.length; i++) {
            ordersRequests.push({
                'symbol': market['id'],
                'orderLinkId': this.safeString(clientOrderIds, i),
            });
        }
        for (let i = 0; i < ids.length; i++) {
            ordersRequests.push({
                'symbol': market['id'],
                'orderId': this.safeString(ids, i),
            });
        }
        const request = {
            'category': category,
            'request': ordersRequests,
        };
        const response = await this.privatePostV5OrderCancelBatch(this.extend(request, params));
        //
        //     {
        //         "retCode": "0",
        //         "retMsg": "OK",
        //         "result": {
        //             "list": [
        //                 {
        //                     "category": "spot",
        //                     "symbol": "BTCUSDT",
        //                     "orderId": "1636282505818800896",
        //                     "orderLinkId": "1636282505818800897"
        //                 },
        //                 {
        //                     "category": "spot",
        //                     "symbol": "BTCUSDT",
        //                     "orderId": "1636282505818800898",
        //                     "orderLinkId": "1636282505818800899"
        //                 }
        //             ]
        //         },
        //         "retExtInfo": {
        //             "list": [
        //                 {
        //                     "code": "0",
        //                     "msg": "OK"
        //                 },
        //                 {
        //                     "code": "0",
        //                     "msg": "OK"
        //                 }
        //             ]
        //         },
        //         "time": "1709796158501"
        //     }
        //
        const result = this.safeDict(response, 'result', {});
        const row = this.safeList(result, 'list', []);
        return this.parseOrders(row, market);
    }
    /**
     * @method
     * @name bybit#cancelAllOrdersAfter
     * @description dead man's switch, cancel all orders after the given timeout
     * @see https://bybit-exchange.github.io/docs/v5/order/dcp
     * @param {number} timeout time in milliseconds
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @param {string} [params.product] OPTIONS, DERIVATIVES, SPOT, default is 'DERIVATIVES'
     * @returns {object} the api result
     */
    async cancelAllOrdersAfter(timeout, params = {}) {
        await this.loadMarkets();
        const request = {
            'timeWindow': this.parseToInt(timeout / 1000),
        };
        let type = undefined;
        [type, params] = this.handleMarketTypeAndParams('cancelAllOrdersAfter', undefined, params, 'swap');
        const productMap = {
            'spot': 'SPOT',
            'swap': 'DERIVATIVES',
            'option': 'OPTIONS',
        };
        const product = this.safeString(productMap, type, type);
        request['product'] = product;
        const response = await this.privatePostV5OrderDisconnectedCancelAll(this.extend(request, params));
        //
        // {
        //     "retCode": 0,
        //     "retMsg": "success"
        // }
        //
        return response;
    }
    /**
     * @method
     * @name bybit#cancelOrdersForSymbols
     * @description cancel multiple orders for multiple symbols
     * @see https://bybit-exchange.github.io/docs/v5/order/batch-cancel
     * @param {CancellationRequest[]} orders list of order ids with symbol, example [{"id": "a", "symbol": "BTC/USDT"}, {"id": "b", "symbol": "ETH/USDT"}]
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {object} an list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
     */
    async cancelOrdersForSymbols(orders, params = {}) {
        await this.loadMarkets();
        const types = await this.isUnifiedEnabled();
        const enableUnifiedAccount = types[1];
        if (!enableUnifiedAccount) {
            throw new errors.NotSupported(this.id + ' cancelOrdersForSymbols() supports UTA accounts only');
        }
        const ordersRequests = [];
        let category = undefined;
        for (let i = 0; i < orders.length; i++) {
            const order = orders[i];
            const symbol = this.safeString(order, 'symbol');
            const market = this.market(symbol);
            let currentCategory = undefined;
            [currentCategory, params] = this.getBybitType('cancelOrders', market, params);
            if (currentCategory === 'inverse') {
                throw new errors.NotSupported(this.id + ' cancelOrdersForSymbols does not allow inverse orders');
            }
            if ((category !== undefined) && (category !== currentCategory)) {
                throw new errors.ExchangeError(this.id + ' cancelOrdersForSymbols requires all orders to be of the same category (linear, spot or option))');
            }
            category = currentCategory;
            const id = this.safeString(order, 'id');
            const clientOrderId = this.safeString(order, 'clientOrderId');
            let idKey = 'orderId';
            if (clientOrderId !== undefined) {
                idKey = 'orderLinkId';
            }
            const orderItem = {
                'symbol': market['id'],
            };
            orderItem[idKey] = (idKey === 'orderId') ? id : clientOrderId;
            ordersRequests.push(orderItem);
        }
        const request = {
            'category': category,
            'request': ordersRequests,
        };
        const response = await this.privatePostV5OrderCancelBatch(this.extend(request, params));
        //
        //     {
        //         "retCode": "0",
        //         "retMsg": "OK",
        //         "result": {
        //             "list": [
        //                 {
        //                     "category": "spot",
        //                     "symbol": "BTCUSDT",
        //                     "orderId": "1636282505818800896",
        //                     "orderLinkId": "1636282505818800897"
        //                 },
        //                 {
        //                     "category": "spot",
        //                     "symbol": "BTCUSDT",
        //                     "orderId": "1636282505818800898",
        //                     "orderLinkId": "1636282505818800899"
        //                 }
        //             ]
        //         },
        //         "retExtInfo": {
        //             "list": [
        //                 {
        //                     "code": "0",
        //                     "msg": "OK"
        //                 },
        //                 {
        //                     "code": "0",
        //                     "msg": "OK"
        //                 }
        //             ]
        //         },
        //         "time": "1709796158501"
        //     }
        //
        const result = this.safeDict(response, 'result', {});
        const row = this.safeList(result, 'list', []);
        return this.parseOrders(row, undefined);
    }
    /**
     * @method
     * @name bybit#cancelAllOrders
     * @description cancel all open orders
     * @see https://bybit-exchange.github.io/docs/v5/order/cancel-all
     * @param {string} symbol unified market symbol, only orders in the market of this symbol are cancelled when symbol is not undefined
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @param {boolean} [params.trigger] true if trigger order
     * @param {boolean} [params.stop] alias for trigger
     * @param {string} [params.type] market type, ['swap', 'option', 'spot']
     * @param {string} [params.subType] market subType, ['linear', 'inverse']
     * @param {string} [params.baseCoin] Base coin. Supports linear, inverse & option
     * @param {string} [params.settleCoin] Settle coin. Supports linear, inverse & option
     * @returns {object[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
     */
    async cancelAllOrders(symbol = undefined, params = {}) {
        await this.loadMarkets();
        const [enableUnifiedMargin, enableUnifiedAccount] = await this.isUnifiedEnabled();
        const isUnifiedAccount = (enableUnifiedMargin || enableUnifiedAccount);
        let market = undefined;
        const request = {};
        if (symbol !== undefined) {
            market = this.market(symbol);
            request['symbol'] = market['id'];
        }
        let type = undefined;
        [type, params] = this.getBybitType('cancelAllOrders', market, params);
        request['category'] = type;
        if ((type === 'option') && !isUnifiedAccount) {
            throw new errors.NotSupported(this.id + ' cancelAllOrders() Normal Account not support ' + type + ' market');
        }
        if ((type === 'linear') || (type === 'inverse')) {
            const baseCoin = this.safeString(params, 'baseCoin');
            if (symbol === undefined && baseCoin === undefined) {
                const defaultSettle = this.safeString(this.options, 'defaultSettle', 'USDT');
                request['settleCoin'] = this.safeString(params, 'settleCoin', defaultSettle);
            }
        }
        const isTrigger = this.safeBool2(params, 'stop', 'trigger', false);
        params = this.omit(params, ['stop', 'trigger']);
        if (isTrigger) {
            request['orderFilter'] = 'StopOrder';
        }
        const response = await this.privatePostV5OrderCancelAll(this.extend(request, params));
        //
        // linear / inverse / option
        //     {
        //         "retCode": 0,
        //         "retMsg": "OK",
        //         "result": {
        //             "list": [
        //                 {
        //                     "orderId": "f6a73e1f-39b5-4dee-af21-1460b2e3b27c",
        //                     "orderLinkId": "a001"
        //                 }
        //             ]
        //         },
        //         "retExtInfo": {},
        //         "time": 1672219780463
        //     }
        //
        // spot
        //     {
        //         "retCode": 0,
        //         "retMsg": "OK",
        //         "result": {
        //             "success": "1"
        //         },
        //         "retExtInfo": {},
        //         "time": 1676962409398
        //     }
        //
        const result = this.safeDict(response, 'result', {});
        const orders = this.safeList(result, 'list');
        if (!Array.isArray(orders)) {
            return response;
        }
        return this.parseOrders(orders, market);
    }
    /**
     * @method
     * @name bybit#fetchOrderClassic
     * @description fetches information on an order made by the user *classic accounts only*
     * @see https://bybit-exchange.github.io/docs/v5/order/order-list
     * @param {string} id the order id
     * @param {string} symbol unified symbol of the market the order was made in
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {object} An [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
     */
    async fetchOrderClassic(id, symbol = undefined, params = {}) {
        if (symbol === undefined) {
            throw new errors.ArgumentsRequired(this.id + ' fetchOrder() requires a symbol argument');
        }
        await this.loadMarkets();
        const market = this.market(symbol);
        if (market['spot']) {
            throw new errors.NotSupported(this.id + ' fetchOrder() is not supported for spot markets');
        }
        const request = {
            'orderId': id,
        };
        const result = await this.fetchOrders(symbol, undefined, undefined, this.extend(request, params));
        const length = result.length;
        if (length === 0) {
            const isTrigger = this.safeBoolN(params, ['trigger', 'stop'], false);
            const extra = isTrigger ? '' : ' If you are trying to fetch SL/TP conditional order, you might try setting params["trigger"] = true';
            throw new errors.OrderNotFound('Order ' + id.toString() + ' was not found.' + extra);
        }
        if (length > 1) {
            throw new errors.InvalidOrder(this.id + ' returned more than one order');
        }
        return this.safeValue(result, 0);
    }
    /**
     * @method
     * @name bybit#fetchOrder
     * @description  *classic accounts only/ spot not supported*  fetches information on an order made by the user *classic accounts only*
     * @see https://bybit-exchange.github.io/docs/v5/order/order-list
     * @param {string} id the order id
     * @param {string} symbol unified symbol of the market the order was made in
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @param {object} [params.acknowledged] to suppress the warning, set to true
     * @returns {object} An [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
     */
    async fetchOrder(id, symbol = undefined, params = {}) {
        await this.loadMarkets();
        const [enableUnifiedMargin, enableUnifiedAccount] = await this.isUnifiedEnabled();
        const isUnifiedAccount = (enableUnifiedMargin || enableUnifiedAccount);
        if (!isUnifiedAccount) {
            return await this.fetchOrderClassic(id, symbol, params);
        }
        let acknowledge = false;
        [acknowledge, params] = this.handleOptionAndParams(params, 'fetchOrder', 'acknowledged');
        if (!acknowledge) {
            throw new errors.ArgumentsRequired(this.id + ' fetchOrder() can only access an order if it is in last 500 orders (of any status) for your account. Set params["acknowledged"] = true to hide this warning. Alternatively, we suggest to use fetchOpenOrder or fetchClosedOrder');
        }
        const market = this.market(symbol);
        let marketType = undefined;
        [marketType, params] = this.getBybitType('fetchOrder', market, params);
        const request = {
            'symbol': market['id'],
            'orderId': id,
            'category': marketType,
        };
        let isTrigger = undefined;
        [isTrigger, params] = this.handleParamBool2(params, 'trigger', 'stop', false);
        if (isTrigger) {
            request['orderFilter'] = 'StopOrder';
        }
        const response = await this.privateGetV5OrderRealtime(this.extend(request, params));
        //
        //     {
        //         "retCode": 0,
        //         "retMsg": "OK",
        //         "result": {
        //             "nextPageCursor": "1321052653536515584%3A1672217748287%2C1321052653536515584%3A1672217748287",
        //             "category": "spot",
        //             "list": [
        //                 {
        //                     "symbol": "ETHUSDT",
        //                     "orderType": "Limit",
        //                     "orderLinkId": "1672217748277652",
        //                     "orderId": "1321052653536515584",
        //                     "cancelType": "UNKNOWN",
        //                     "avgPrice": "",
        //                     "stopOrderType": "tpslOrder",
        //                     "lastPriceOnCreated": "",
        //                     "orderStatus": "Cancelled",
        //                     "takeProfit": "",
        //                     "cumExecValue": "0",
        //                     "triggerDirection": 0,
        //                     "isLeverage": "0",
        //                     "rejectReason": "",
        //                     "price": "1000",
        //                     "orderIv": "",
        //                     "createdTime": "1672217748287",
        //                     "tpTriggerBy": "",
        //                     "positionIdx": 0,
        //                     "timeInForce": "GTC",
        //                     "leavesValue": "500",
        //                     "updatedTime": "1672217748287",
        //                     "side": "Buy",
        //                     "triggerPrice": "1500",
        //                     "cumExecFee": "0",
        //                     "leavesQty": "0",
        //                     "slTriggerBy": "",
        //                     "closeOnTrigger": false,
        //                     "cumExecQty": "0",
        //                     "reduceOnly": false,
        //                     "qty": "0.5",
        //                     "stopLoss": "",
        //                     "triggerBy": "1192.5"
        //                 }
        //             ]
        //         },
        //         "retExtInfo": {},
        //         "time": 1672219526294
        //     }
        //
        const result = this.safeDict(response, 'result', {});
        const innerList = this.safeList(result, 'list', []);
        if (innerList.length === 0) {
            const extra = isTrigger ? '' : ' If you are trying to fetch SL/TP conditional order, you might try setting params["trigger"] = true';
            throw new errors.OrderNotFound('Order ' + id.toString() + ' was not found.' + extra);
        }
        const order = this.safeDict(innerList, 0, {});
        return this.parseOrder(order, market);
    }
    async fetchOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
        const res = await this.isUnifiedEnabled();
        /**
         * @method
         * @name bybit#fetchOrders
         * @description *classic accounts only/ spot not supported* fetches information on multiple orders made by the user *classic accounts only/ spot not supported*
         * @see https://bybit-exchange.github.io/docs/v5/order/order-list
         * @param {string} 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 {object} [params] extra parameters specific to the exchange API endpoint
         * @param {boolean} [params.trigger] true if trigger order
         * @param {boolean} [params.stop] alias for trigger
         * @param {string} [params.type] market type, ['swap', 'option']
         * @param {string} [params.subType] market subType, ['linear', 'inverse']
         * @param {string} [params.orderFilter] 'Order' or 'StopOrder' or 'tpslOrder'
         * @param {int} [params.until] the latest time in ms to fetch entries for
         * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
         * @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
         */
        const enableUnifiedAccount = this.safeBool(res, 1);
        if (enableUnifiedAccount) {
            throw new errors.NotSupported(this.id + ' fetchOrders() is not supported after the 5/02 update for UTA accounts, please use fetchOpenOrders, fetchClosedOrders or fetchCanceledOrders');
        }
        return await this.fetchOrdersClassic(symbol, since, limit, params);
    }
    /**
     * @method
     * @name bybit#fetchOrdersClassic
     * @description fetches information on multiple orders made by the user *classic accounts only*
     * @see https://bybit-exchange.github.io/docs/v5/order/order-list
     * @param {string} 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 {object} [params] extra parameters specific to the exchange API endpoint
     * @param {boolean} [params.trigger] true if trigger order
     * @param {boolean} [params.stop] alias for trigger
     * @param {string} [params.type] market type, ['swap', 'option', 'spot']
     * @param {string} [params.subType] market subType, ['linear', 'inverse']
     * @param {string} [params.orderFilter] 'Order' or 'StopOrder' or 'tpslOrder'
     * @param {int} [params.until] the latest time in ms to fetch entries for
     * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
     * @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
     */
    async fetchOrdersClassic(symbol = undefined, since = undefined, limit = undefined, params = {}) {
        await this.loadMarkets();
        let paginate = false;
        [paginate, params] = this.handleOptionAndParams(params, 'fetchOrders', 'paginate');
        if (paginate) {
            return await this.fetchPaginatedCallCursor('fetchOrders', symbol, since, limit, params, 'nextPageCursor', 'cursor', undefined, 50);
        }
        const request = {};
        let market = undefined;
        if (symbol !== undefined) {
            market = this.market(symbol);
            request['symbol'] = market['id'];
        }
        let type = undefined;
        [type, params] = this.getBybitType('fetchOrders', market, params);
        if (type === 'spot') {
            throw new errors.NotSupported(this.id + ' fetchOrders() is not supported for spot markets');
        }
        request['category'] = type;
        const isTrigger = this.safeBoolN(params, ['trigger', 'stop'], false);
        params = this.omit(params, ['trigger', 'stop']);
        if (isTrigger) {
            request['orderFilter'] = 'StopOrder';
        }
        if (limit !== undefined) {
            request['limit'] = limit;
        }
        if (since !== undefined) {
            request['startTime'] = since;
        }
        const until = this.safeInteger(params, 'until'); // unified in milliseconds
        const endTime = this.safeInteger(params, 'endTime', until); // exchange-specific in milliseconds
        params = this.omit(params, ['endTime', 'until']);
        if (endTime !== undefined) {
            request['endTime'] = endTime;
        }
        const response = await this.privateGetV5OrderHistory(this.extend(request, params));
        //
        //     {
        //         "retCode": 0,
        //         "retMsg": "OK",
        //         "result": {
        //             "nextPageCursor": "03234de9-1332-41eb-b805-4a9f42c136a3%3A1672220109387%2C03234de9-1332-41eb-b805-4a9f42c136a3%3A1672220109387",
        //             "category": "linear",
        //             "list": [
        //                 {
        //                     "symbol": "BTCUSDT",
        //                     "orderType": "Limit",
        //                     "orderLinkId": "test-001",
        //                     "orderId": "03234de9-1332-41eb-b805-4a9f42c136a3",
        //                     "cancelType": "CancelByUser",
        //                     "avgPrice": "0",
        //                     "stopOrderType": "UNKNOWN",
        //                     "lastPriceOnCreated": "16656.5",
        //                     "orderStatus": "Cancelled",
        //                     "takeProfit": "",
        //                     "cumExecValue": "0",
        //                     "triggerDirection": 0,
        //                     "blockTradeId": "",
        //                     "rejectReason": "EC_PerCancelRequest",
        //                     "isLeverage": "",
        //                     "price": "18000",
        //                     "orderIv": "",
        //                     "createdTime": "1672220109387",
        //                     "tpTriggerBy": "UNKNOWN",
        //                     "positionIdx": 0,
        //                     "timeInForce": "GoodTillCancel",
        //                     "leavesValue": "0",
        //                     "updatedTime": "1672220114123",
        //                     "side": "Sell",
        //                     "triggerPrice": "",
        //                     "cumExecFee": "0",
        //                     "slTriggerBy": "UNKNOWN",
        //                     "leavesQty": "0",
        //                     "closeOnTrigger": false,
        //                     "cumExecQty": "0",
        //                     "reduceOnly": false,
        //                     "qty": "0.1",
        //                     "stopLoss": "",
        //                     "triggerBy": "UNKNOWN"
        //                 }
        //             ]
        //         },
        //         "retExtInfo": {},
        //         "time": 1672221263862
        //     }
        //
        const data = this.addPaginationCursorToResult(response);
        return this.parseOrders(data, market, since, limit);
    }
    /**
     * @method
     * @name bybit#fetchClosedOrder
     * @description fetches information on a closed order made by the user
     * @see https://bybit-exchange.github.io/docs/v5/order/order-list
     * @param {string} id order id
     * @param {string} [symbol] unified symbol of the market the order was made in
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @param {boolean} [params.trigger] set to true for fetching a closed trigger order
     * @param {boolean} [params.stop] alias for trigger
     * @param {string} [params.type] market type, ['swap', 'option', 'spot']
     * @param {string} [params.subType] market subType, ['linear', 'inverse']
     * @param {string} [params.orderFilter] 'Order' or 'StopOrder' or 'tpslOrder'
     * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
     */
    async fetchClosedOrder(id, symbol = undefined, params = {}) {
        await this.loadMarkets();
        const request = {
            'orderId': id,
        };
        const result = await this.fetchClosedOrders(symbol, undefined, undefined, this.extend(request, params));
        const length = result.length;
        if (length === 0) {
            const isTrigger = this.safeBoolN(params, ['trigger', 'stop'], false);
            const extra = isTrigger ? '' : ' If you are trying to fetch SL/TP conditional order, you might try setting params["trigger"] = true';
            throw new errors.OrderNotFound('Order ' + id.toString() + ' was not found.' + extra);
        }
        if (length > 1) {
            throw new errors.InvalidOrder(this.id + ' returned more than one order');
        }
        return this.safeValue(result, 0);
    }
    /**
     * @method
     * @name bybit#fetchOpenOrder
     * @description fetches information on an open order made by the user
     * @see https://bybit-exchange.github.io/docs/v5/order/open-order
     * @param {string} id order id
     * @param {string} [symbol] unified symbol of the market the order was made in
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @param {boolean} [params.trigger] set to true for fetching an open trigger order
     * @param {boolean} [params.stop] alias for trigger
     * @param {string} [params.type] market type, ['swap', 'option', 'spot']
     * @param {string} [params.subType] market subType, ['linear', 'inverse']
     * @param {string} [params.baseCoin] Base coin. Supports linear, inverse & option
     * @param {string} [params.settleCoin] Settle coin. Supports linear, inverse & option
     * @param {string} [params.orderFilter] 'Order' or 'StopOrder' or 'tpslOrder'
     * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
     */
    async fetchOpenOrder(id, symbol = undefined, params = {}) {
        await this.loadMarkets();
        const request = {
            'orderId': id,
        };
        const result = await this.fetchOpenOrders(symbol, undefined, undefined, this.extend(request, params));
        const length = result.length;
        if (length === 0) {
            const isTrigger = this.safeBoolN(params, ['trigger', 'stop'], false);
            const extra = isTrigger ? '' : ' If you are trying to fetch SL/TP conditional order, you might try setting params["trigger"] = true';
            throw new errors.OrderNotFound('Order ' + id.toString() + ' was not found.' + extra);
        }
        if (length > 1) {
            throw new errors.InvalidOrder(this.id + ' returned more than one order');
        }
        return this.safeValue(result, 0);
    }
    /**
     * @method
     * @name bybit#fetchCanceledAndClosedOrders
     * @description fetches information on multiple canceled and closed orders made by the user
     * @see https://bybit-exchange.github.io/docs/v5/order/order-list
     * @param {string} [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 {object} [params] extra parameters specific to the exchange API endpoint
     * @param {boolean} [params.trigger] set to true for fetching trigger orders
     * @param {boolean} [params.stop] alias for trigger
     * @param {string} [params.type] market type, ['swap', 'option', 'spot']
     * @param {string} [params.subType] market subType, ['linear', 'inverse']
     * @param {string} [params.orderFilter] 'Order' or 'StopOrder' or 'tpslOrder'
     * @param {int} [params.until] the latest time in ms to fetch entries for
     * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [available parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
     * @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
     */
    async fetchCanceledAndClosedOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
        await this.loadMarkets();
        let paginate = false;
        [paginate, params] = this.handleOptionAndParams(params, 'fetchCanceledAndClosedOrders', 'paginate');
        if (paginate) {
            return await this.fetchPaginatedCallCursor('fetchCanceledAndClosedOrders', symbol, since, limit, params, 'nextPageCursor', 'cursor', undefined, 50);
        }
        const request = {};
        let market = undefined;
        if (symbol !== undefined) {
            market = this.market(symbol);
            request['symbol'] = market['id'];
        }
        let type = undefined;
        [type, params] = this.getBybitType('fetchCanceledAndClosedOrders', market, params);
        request['category'] = type;
        const isTrigger = this.safeBoolN(params, ['trigger', 'stop'], false);
        params = this.omit(params, ['trigger', 'stop']);
        if (isTrigger) {
            request['orderFilter'] = 'StopOrder';
        }
        if (limit !== undefined) {
            request['limit'] = limit;
        }
        if (since !== undefined) {
            request['startTime'] = since;
        }
        const until = this.safeInteger(params, 'until'); // unified in milliseconds
        const endTime = this.safeInteger(params, 'endTime', until); // exchange-specific in milliseconds
        params = this.omit(params, ['endTime', 'until']);
        if (endTime !== undefined) {
            request['endTime'] = endTime;
        }
        const response = await this.privateGetV5OrderHistory(this.extend(request, params));
        //
        //     {
        //         "retCode": 0,
        //         "retMsg": "OK",
        //         "result": {
        //             "nextPageCursor": "03234de9-1332-41eb-b805-4a9f42c136a3%3A1672220109387%2C03234de9-1332-41eb-b805-4a9f42c136a3%3A1672220109387",
        //             "category": "linear",
        //             "list": [
        //                 {
        //                     "symbol": "BTCUSDT",
        //                     "orderType": "Limit",
        //                     "orderLinkId": "test-001",
        //                     "orderId": "03234de9-1332-41eb-b805-4a9f42c136a3",
        //                     "cancelType": "CancelByUser",
        //                     "avgPrice": "0",
        //                     "stopOrderType": "UNKNOWN",
        //                     "lastPriceOnCreated": "16656.5",
        //                     "orderStatus": "Cancelled",
        //                     "takeProfit": "",
        //                     "cumExecValue": "0",
        //                     "triggerDirection": 0,
        //                     "blockTradeId": "",
        //                     "rejectReason": "EC_PerCancelRequest",
        //                     "isLeverage": "",
        //                     "price": "18000",
        //                     "orderIv": "",
        //                     "createdTime": "1672220109387",
        //                     "tpTriggerBy": "UNKNOWN",
        //                     "positionIdx": 0,
        //                     "timeInForce": "GoodTillCancel",
        //                     "leavesValue": "0",
        //                     "updatedTime": "1672220114123",
        //                     "side": "Sell",
        //                     "triggerPrice": "",
        //                     "cumExecFee": "0",
        //                     "slTriggerBy": "UNKNOWN",
        //                     "leavesQty": "0",
        //                     "closeOnTrigger": false,
        //                     "cumExecQty": "0",
        //                     "reduceOnly": false,
        //                     "qty": "0.1",
        //                     "stopLoss": "",
        //                     "triggerBy": "UNKNOWN"
        //                 }
        //             ]
        //         },
        //         "retExtInfo": {},
        //         "time": 1672221263862
        //     }
        //
        const data = this.addPaginationCursorToResult(response);
        return this.parseOrders(data, market, since, limit);
    }
    /**
     * @method
     * @name bybit#fetchClosedOrders
     * @description fetches information on multiple closed orders made by the user
     * @see https://bybit-exchange.github.io/docs/v5/order/order-list
     * @param {string} [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 {object} [params] extra parameters specific to the exchange API endpoint
     * @param {boolean} [params.trigger] set to true for fetching closed trigger orders
     * @param {boolean} [params.stop] alias for trigger
     * @param {string} [params.type] market type, ['swap', 'option', 'spot']
     * @param {string} [params.subType] market subType, ['linear', 'inverse']
     * @param {string} [params.orderFilter] 'Order' or 'StopOrder' or 'tpslOrder'
     * @param {int} [params.until] the latest time in ms to fetch entries for
     * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [available parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
     * @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
     */
    async fetchClosedOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
        await this.loadMarkets();
        const request = {
            'orderStatus': 'Filled',
        };
        return await this.fetchCanceledAndClosedOrders(symbol, since, limit, this.extend(request, params));
    }
    /**
     * @method
     * @name bybit#fetchCanceledOrders
     * @description fetches information on multiple canceled orders made by the user
     * @see https://bybit-exchange.github.io/docs/v5/order/order-list
     * @param {string} [symbol] unified market symbol of the market orders were made in
     * @param {int} [since] timestamp in ms of the earliest order, default is undefined
     * @param {int} [limit] max number of orders to return, default is undefined
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @param {boolean} [params.trigger] true if trigger order
     * @param {boolean} [params.stop] alias for trigger
     * @param {string} [params.type] market type, ['swap', 'option', 'spot']
     * @param {string} [params.subType] market subType, ['linear', 'inverse']
     * @param {string} [params.orderFilter] 'Order' or 'StopOrder' or 'tpslOrder'
     * @param {int} [params.until] the latest time in ms to fetch entries for
     * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [available parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
     * @returns {object} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
     */
    async fetchCanceledOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
        await this.loadMarkets();
        const request = {
            'orderStatus': 'Cancelled',
        };
        return await this.fetchCanceledAndClosedOrders(symbol, since, limit, this.extend(request, params));
    }
    /**
     * @method
     * @name bybit#fetchOpenOrders
     * @description fetch all unfilled currently open orders
     * @see https://bybit-exchange.github.io/docs/v5/order/open-order
     * @param {string} symbol unified market symbol
     * @param {int} [since] the earliest time in ms to fetch open orders for
     * @param {int} [limit] the maximum number of open orders structures to retrieve
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @param {boolean} [params.trigger] set to true for fetching open trigger orders
     * @param {boolean} [params.stop] alias for trigger
     * @param {string} [params.type] market type, ['swap', 'option', 'spot']
     * @param {string} [params.subType] market subType, ['linear', 'inverse']
     * @param {string} [params.baseCoin] Base coin. Supports linear, inverse & option
     * @param {string} [params.settleCoin] Settle coin. Supports linear, inverse & option
     * @param {string} [params.orderFilter] 'Order' or 'StopOrder' or 'tpslOrder'
     * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
     * @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
     */
    async fetchOpenOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
        await this.loadMarkets();
        let paginate = false;
        [paginate, params] = this.handleOptionAndParams(params, 'fetchOpenOrders', 'paginate');
        if (paginate) {
            return await this.fetchPaginatedCallCursor('fetchOpenOrders', symbol, since, limit, params, 'nextPageCursor', 'cursor', undefined, 50);
        }
        const request = {};
        let market = undefined;
        if (symbol !== undefined) {
            market = this.market(symbol);
            request['symbol'] = market['id'];
        }
        let type = undefined;
        [type, params] = this.getBybitType('fetchOpenOrders', market, params);
        if (type === 'linear' || type === 'inverse') {
            const baseCoin = this.safeString(params, 'baseCoin');
            if (symbol === undefined && baseCoin === undefined) {
                const defaultSettle = this.safeString(this.options, 'defaultSettle', 'USDT');
                const settleCoin = this.safeString(params, 'settleCoin', defaultSettle);
                request['settleCoin'] = settleCoin;
            }
        }
        request['category'] = type;
        const isTrigger = this.safeBool2(params, 'stop', 'trigger', false);
        params = this.omit(params, ['stop', 'trigger']);
        if (isTrigger) {
            request['orderFilter'] = 'StopOrder';
        }
        if (limit !== undefined) {
            request['limit'] = limit;
        }
        const response = await this.privateGetV5OrderRealtime(this.extend(request, params));
        //
        //     {
        //         "retCode": 0,
        //         "retMsg": "OK",
        //         "result": {
        //             "nextPageCursor": "1321052653536515584%3A1672217748287%2C1321052653536515584%3A1672217748287",
        //             "category": "spot",
        //             "list": [
        //                 {
        //                     "symbol": "ETHUSDT",
        //                     "orderType": "Limit",
        //                     "orderLinkId": "1672217748277652",
        //                     "orderId": "1321052653536515584",
        //                     "cancelType": "UNKNOWN",
        //                     "avgPrice": "",
        //                     "stopOrderType": "tpslOrder",
        //                     "lastPriceOnCreated": "",
        //                     "orderStatus": "Cancelled",
        //                     "takeProfit": "",
        //                     "cumExecValue": "0",
        //                     "triggerDirection": 0,
        //                     "isLeverage": "0",
        //                     "rejectReason": "",
        //                     "price": "1000",
        //                     "orderIv": "",
        //                     "createdTime": "1672217748287",
        //                     "tpTriggerBy": "",
        //                     "positionIdx": 0,
        //                     "timeInForce": "GTC",
        //                     "leavesValue": "500",
        //                     "updatedTime": "1672217748287",
        //                     "side": "Buy",
        //                     "triggerPrice": "1500",
        //                     "cumExecFee": "0",
        //                     "leavesQty": "0",
        //                     "slTriggerBy": "",
        //                     "closeOnTrigger": false,
        //                     "cumExecQty": "0",
        //                     "reduceOnly": false,
        //                     "qty": "0.5",
        //                     "stopLoss": "",
        //                     "triggerBy": "1192.5"
        //                 }
        //             ]
        //         },
        //         "retExtInfo": {},
        //         "time": 1672219526294
        //     }
        //
        const data = this.addPaginationCursorToResult(response);
        return this.parseOrders(data, market, since, limit);
    }
    /**
     * @method
     * @name bybit#fetchOrderTrades
     * @description fetch all the trades made from a single order
     * @see https://bybit-exchange.github.io/docs/v5/position/execution
     * @param {string} id order id
     * @param {string} symbol unified market symbol
     * @param {int} [since] the earliest time in ms to fetch trades for
     * @param {int} [limit] the maximum number of trades to retrieve
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=trade-structure}
     */
    async fetchOrderTrades(id, symbol = undefined, since = undefined, limit = undefined, params = {}) {
        const request = {};
        const clientOrderId = this.safeString2(params, 'clientOrderId', 'orderLinkId');
        if (clientOrderId !== undefined) {
            request['orderLinkId'] = clientOrderId;
        }
        else {
            request['orderId'] = id;
        }
        params = this.omit(params, ['clientOrderId', 'orderLinkId']);
        return await this.fetchMyTrades(symbol, since, limit, this.extend(request, params));
    }
    /**
     * @method
     * @name bybit#fetchMyTrades
     * @description fetch all trades made by the user
     * @see https://bybit-exchange.github.io/docs/api-explorer/v5/position/execution
     * @param {string} 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 {object} [params] extra parameters specific to the exchange API endpoint
     * @param {string} [params.type] market type, ['swap', 'option', 'spot']
     * @param {string} [params.subType] market subType, ['linear', 'inverse']
     * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
     * @returns {Trade[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=trade-structure}
     */
    async fetchMyTrades(symbol = undefined, since = undefined, limit = undefined, params = {}) {
        await this.loadMarkets();
        let paginate = false;
        [paginate, params] = this.handleOptionAndParams(params, 'fetchMyTrades', 'paginate');
        if (paginate) {
            return await this.fetchPaginatedCallCursor('fetchMyTrades', symbol, since, limit, params, 'nextPageCursor', 'cursor', undefined, 100);
        }
        let request = {
            'execType': 'Trade',
        };
        let market = undefined;
        if (symbol !== undefined) {
            market = this.market(symbol);
            request['symbol'] = market['id'];
        }
        let type = undefined;
        [type, params] = this.getBybitType('fetchMyTrades', market, params);
        request['category'] = type;
        if (limit !== undefined) {
            request['limit'] = limit;
        }
        if (since !== undefined) {
            request['startTime'] = since;
        }
        [request, params] = this.handleUntilOption('endTime', request, params);
        const response = await this.privateGetV5ExecutionList(this.extend(request, params));
        //
        //     {
        //         "retCode": 0,
        //         "retMsg": "OK",
        //         "result": {
        //             "nextPageCursor": "132766%3A2%2C132766%3A2",
        //             "category": "linear",
        //             "list": [
        //                 {
        //                     "symbol": "ETHPERP",
        //                     "orderType": "Market",
        //                     "underlyingPrice": "",
        //                     "orderLinkId": "",
        //                     "side": "Buy",
        //                     "indexPrice": "",
        //                     "orderId": "8c065341-7b52-4ca9-ac2c-37e31ac55c94",
        //                     "stopOrderType": "UNKNOWN",
        //                     "leavesQty": "0",
        //                     "execTime": "1672282722429",
        //                     "isMaker": false,
        //                     "execFee": "0.071409",
        //                     "feeRate": "0.0006",
        //                     "execId": "e0cbe81d-0f18-5866-9415-cf319b5dab3b",
        //                     "tradeIv": "",
        //                     "blockTradeId": "",
        //                     "markPrice": "1183.54",
        //                     "execPrice": "1190.15",
        //                     "markIv": "",
        //                     "orderQty": "0.1",
        //                     "orderPrice": "1236.9",
        //                     "execValue": "119.015",
        //                     "execType": "Trade",
        //                     "execQty": "0.1"
        //                 }
        //             ]
        //         },
        //         "retExtInfo": {},
        //         "time": 1672283754510
        //     }
        //
        const trades = this.addPaginationCursorToResult(response);
        return this.parseTrades(trades, market, since, limit);
    }
    parseDepositAddress(depositAddress, currency = undefined) {
        //
        //     {
        //         "chainType": "ERC20",
        //         "addressDeposit": "0xf56297c6717c1d1c42c30324468ed50a9b7402ee",
        //         "tagDeposit": '',
        //         "chain": "ETH"
        //     }
        //
        const address = this.safeString(depositAddress, 'addressDeposit');
        const tag = this.safeString(depositAddress, 'tagDeposit');
        const code = this.safeString(currency, 'code');
        this.checkAddress(address);
        return {
            'info': depositAddress,
            'currency': code,
            'network': this.networkIdToCode(this.safeString(depositAddress, 'chain'), code),
            'address': address,
            'tag': tag,
        };
    }
    /**
     * @method
     * @name bybit#fetchDepositAddressesByNetwork
     * @description fetch a dictionary of addresses for a currency, indexed by network
     * @see https://bybit-exchange.github.io/docs/v5/asset/master-deposit-addr
     * @param {string} code unified currency code of the currency for the deposit address
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {object} a dictionary of [address structures]{@link https://docs.ccxt.com/#/?id=address-structure} indexed by the network
     */
    async fetchDepositAddressesByNetwork(code, params = {}) {
        await this.loadMarkets();
        let currency = this.currency(code);
        const request = {
            'coin': currency['id'],
        };
        let networkCode = undefined;
        [networkCode, params] = this.handleNetworkCodeAndParams(params);
        if (networkCode !== undefined) {
            request['chainType'] = this.networkCodeToId(networkCode, code);
        }
        const response = await this.privateGetV5AssetDepositQueryAddress(this.extend(request, params));
        //
        //     {
        //         "retCode": 0,
        //         "retMsg": "success",
        //         "result": {
        //             "coin": "USDT",
        //             "chains": [
        //                 {
        //                     "chainType": "ERC20",
        //                     "addressDeposit": "0xd9e1cd77afa0e50b452a62fbb68a3340602286c3",
        //                     "tagDeposit": "",
        //                     "chain": "ETH"
        //                 }
        //             ]
        //         },
        //         "retExtInfo": {},
        //         "time": 1672192792860
        //     }
        //
        const result = this.safeDict(response, 'result', {});
        const chains = this.safeList(result, 'chains', []);
        const coin = this.safeString(result, 'coin');
        currency = this.currency(coin);
        const parsed = this.parseDepositAddresses(chains, [currency['code']], false, {
            'currency': currency['code'],
        });
        return this.indexBy(parsed, 'network');
    }
    /**
     * @method
     * @name bybit#fetchDepositAddress
     * @description fetch the deposit address for a currency associated with this account
     * @see https://bybit-exchange.github.io/docs/v5/asset/master-deposit-addr
     * @param {string} code unified currency code
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {object} an [address structure]{@link https://docs.ccxt.com/#/?id=address-structure}
     */
    async fetchDepositAddress(code, params = {}) {
        await this.loadMarkets();
        const currency = this.currency(code);
        const [networkCode, paramsOmited] = this.handleNetworkCodeAndParams(params);
        const indexedAddresses = await this.fetchDepositAddressesByNetwork(code, paramsOmited);
        const selectedNetworkCode = this.selectNetworkCodeFromUnifiedNetworks(currency['code'], networkCode, indexedAddresses);
        return indexedAddresses[selectedNetworkCode];
    }
    /**
     * @method
     * @name bybit#fetchDeposits
     * @description fetch all deposits made to an account
     * @see https://bybit-exchange.github.io/docs/v5/asset/deposit-record
     * @param {string} code unified currency code
     * @param {int} [since] the earliest time in ms to fetch deposits for, default = 30 days before the current time
     * @param {int} [limit] the maximum number of deposits structures to retrieve, default = 50, max = 50
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @param {int} [params.until] the latest time in ms to fetch deposits for, default = 30 days after since
     * EXCHANGE SPECIFIC PARAMETERS
     * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
     * @param {string} [params.cursor] used for pagination
     * @returns {object[]} a list of [transaction structures]{@link https://docs.ccxt.com/#/?id=transaction-structure}
     */
    async fetchDeposits(code = undefined, since = undefined, limit = undefined, params = {}) {
        await this.loadMarkets();
        let paginate = false;
        [paginate, params] = this.handleOptionAndParams(params, 'fetchDeposits', 'paginate');
        if (paginate) {
            return await this.fetchPaginatedCallCursor('fetchDeposits', code, since, limit, params, 'nextPageCursor', 'cursor', undefined, 50);
        }
        let request = {
        // 'coin': currency['id'],
        // 'limit': 20, // max 50
        // 'cursor': '',
        };
        let currency = undefined;
        if (code !== undefined) {
            currency = this.currency(code);
            request['coin'] = currency['id'];
        }
        if (since !== undefined) {
            request['startTime'] = since;
        }
        if (limit !== undefined) {
            request['limit'] = limit;
        }
        [request, params] = this.handleUntilOption('endTime', request, params);
        const response = await this.privateGetV5AssetDepositQueryRecord(this.extend(request, params));
        //
        //     {
        //         "retCode": 0,
        //         "retMsg": "success",
        //         "result": {
        //             "rows": [
        //                 {
        //                     "coin": "USDT",
        //                     "chain": "ETH",
        //                     "amount": "10000",
        //                     "txID": "skip-notification-scene-test-amount-202212270944-533285-USDT",
        //                     "status": 3,
        //                     "toAddress": "test-amount-address",
        //                     "tag": "",
        //                     "depositFee": "",
        //                     "successAt": "1672134274000",
        //                     "confirmations": "10000",
        //                     "txIndex": "",
        //                     "blockHash": ""
        //                 }
        //             ],
        //             "nextPageCursor": "eyJtaW5JRCI6MTA0NjA0MywibWF4SUQiOjEwNDYwNDN9"
        //         },
        //         "retExtInfo": {},
        //         "time": 1672191992512
        //     }
        //
        const data = this.addPaginationCursorToResult(response);
        return this.parseTransactions(data, currency, since, limit);
    }
    /**
     * @method
     * @name bybit#fetchWithdrawals
     * @description fetch all withdrawals made from an account
     * @see https://bybit-exchange.github.io/docs/v5/asset/withdraw-record
     * @param {string} 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 {object} [params] extra parameters specific to the exchange API endpoint
     * @param {int} [params.until] the latest time in ms to fetch entries for
     * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
     * @returns {object[]} a list of [transaction structures]{@link https://docs.ccxt.com/#/?id=transaction-structure}
     */
    async fetchWithdrawals(code = undefined, since = undefined, limit = undefined, params = {}) {
        await this.loadMarkets();
        let paginate = false;
        [paginate, params] = this.handleOptionAndParams(params, 'fetchWithdrawals', 'paginate');
        if (paginate) {
            return await this.fetchPaginatedCallCursor('fetchWithdrawals', code, since, limit, params, 'nextPageCursor', 'cursor', undefined, 50);
        }
        let request = {
        // 'coin': currency['id'],
        // 'limit': 20, // max 50
        // 'cusor': '',
        };
        let currency = undefined;
        if (code !== undefined) {
            currency = this.currency(code);
            request['coin'] = currency['id'];
        }
        if (since !== undefined) {
            request['startTime'] = since;
        }
        if (limit !== undefined) {
            request['limit'] = limit;
        }
        [request, params] = this.handleUntilOption('endTime', request, params);
        const response = await this.privateGetV5AssetWithdrawQueryRecord(this.extend(request, params));
        //
        //     {
        //         "retCode": 0,
        //         "retMsg": "success",
        //         "result": {
        //             "rows": [
        //                 {
        //                     "coin": "USDT",
        //                     "chain": "ETH",
        //                     "amount": "77",
        //                     "txID": "",
        //                     "status": "SecurityCheck",
        //                     "toAddress": "0x99ced129603abc771c0dabe935c326ff6c86645d",
        //                     "tag": "",
        //                     "withdrawFee": "10",
        //                     "createTime": "1670922217000",
        //                     "updateTime": "1670922217000",
        //                     "withdrawId": "9976",
        //                     "withdrawType": 0
        //                 },
        //                 {
        //                     "coin": "USDT",
        //                     "chain": "ETH",
        //                     "amount": "26",
        //                     "txID": "",
        //                     "status": "success",
        //                     "toAddress": "15638072681@163.com",
        //                     "tag": "",
        //                     "withdrawFee": "0",
        //                     "createTime": "1669711121000",
        //                     "updateTime": "1669711380000",
        //                     "withdrawId": "9801",
        //                     "withdrawType": 1
        //                 }
        //             ],
        //             "nextPageCursor": "eyJtaW5JRCI6OTgwMSwibWF4SUQiOjk5NzZ9"
        //         },
        //         "retExtInfo": {},
        //         "time": 1672194949928
        //     }
        //
        const data = this.addPaginationCursorToResult(response);
        return this.parseTransactions(data, currency, since, limit);
    }
    parseTransactionStatus(status) {
        const statuses = {
            // v3 deposit status
            '0': 'unknown',
            '1': 'pending',
            '2': 'processing',
            '3': 'ok',
            '4': 'fail',
            // v3 withdrawal status
            'SecurityCheck': 'pending',
            'Pending': 'pending',
            'success': 'ok',
            'CancelByUser': 'canceled',
            'Reject': 'rejected',
            'Fail': 'failed',
            'BlockchainConfirmed': 'ok',
        };
        return this.safeString(statuses, status, status);
    }
    parseTransaction(transaction, currency = undefined) {
        //
        // fetchWithdrawals
        //
        //     {
        //         "coin": "USDT",
        //         "chain": "TRX",
        //         "amount": "12.34",
        //         "txID": "de5ea0a2f2e59dc9a714837dd3ddc6d5e151b56ec5d786d351c4f52336f80d3c",
        //         "status": "success",
        //         "toAddress": "TQdmFKUoe1Lk2iwZuwRJEHJreTUBoN3BAw",
        //         "tag": "",
        //         "withdrawFee": "0.5",
        //         "createTime": "1665144183000",
        //         "updateTime": "1665144256000",
        //         "withdrawId": "8839035"
        //     }
        //
        // fetchDeposits
        //
        //     {
        //         "coin": "USDT",
        //         "chain": "TRX",
        //         "amount": "44",
        //         "txID": "0b038ea12fa1575e2d66693db3c346b700d4b28347afc39f80321cf089acc960",
        //         "status": "3",
        //         "toAddress": "TC6NCAC5WSVCCiaD3kWZXyW91ZKKhLm53b",
        //         "tag": "",
        //         "depositFee": "",
        //         "successAt": "1665142507000",
        //         "confirmations": "100",
        //         "txIndex": "0",
        //         "blockHash": "0000000002ac3b1064aee94bca1bd0b58c4c09c65813b084b87a2063d961129e"
        //     }
        //
        // withdraw
        //
        //     {
        //         "id": "9377266"
        //     }
        //
        const currencyId = this.safeString(transaction, 'coin');
        const code = this.safeCurrencyCode(currencyId, currency);
        const timestamp = this.safeInteger2(transaction, 'createTime', 'successAt');
        const updated = this.safeInteger(transaction, 'updateTime');
        const status = this.parseTransactionStatus(this.safeString(transaction, 'status'));
        const feeCost = this.safeNumber2(transaction, 'depositFee', 'withdrawFee');
        const type = ('depositFee' in transaction) ? 'deposit' : 'withdrawal';
        let fee = undefined;
        if (feeCost !== undefined) {
            fee = {
                'cost': feeCost,
                'currency': code,
            };
        }
        const toAddress = this.safeString(transaction, 'toAddress');
        return {
            'info': transaction,
            'id': this.safeString2(transaction, 'id', 'withdrawId'),
            'txid': this.safeString(transaction, 'txID'),
            'timestamp': timestamp,
            'datetime': this.iso8601(timestamp),
            'network': this.networkIdToCode(this.safeString(transaction, 'chain')),
            'address': undefined,
            'addressTo': toAddress,
            'addressFrom': undefined,
            'tag': this.safeString(transaction, 'tag'),
            'tagTo': undefined,
            'tagFrom': undefined,
            'type': type,
            'amount': this.safeNumber(transaction, 'amount'),
            'currency': code,
            'status': status,
            'updated': updated,
            'fee': fee,
            'internal': undefined,
            'comment': undefined,
        };
    }
    /**
     * @method
     * @name bybit#fetchLedger
     * @description fetch the history of changes, actions done by the user or operations that altered the balance of the user
     * @see https://bybit-exchange.github.io/docs/v5/account/transaction-log
     * @see https://bybit-exchange.github.io/docs/v5/account/contract-transaction-log
     * @param {string} [code] unified currency code, default is undefined
     * @param {int} [since] timestamp in ms of the earliest ledger entry, default is undefined
     * @param {int} [limit] max number of ledger entries to return, default is undefined
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [available parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
     * @param {string} [params.subType] if inverse will use v5/account/contract-transaction-log
     * @returns {object} a [ledger structure]{@link https://docs.ccxt.com/#/?id=ledger}
     */
    async fetchLedger(code = undefined, since = undefined, limit = undefined, params = {}) {
        await this.loadMarkets();
        let paginate = false;
        [paginate, params] = this.handleOptionAndParams(params, 'fetchLedger', 'paginate');
        if (paginate) {
            return await this.fetchPaginatedCallCursor('fetchLedger', code, since, limit, params, 'nextPageCursor', 'cursor', undefined, 50);
        }
        const request = {
        // 'coin': currency['id'],
        // 'currency': currency['id'], // alias
        // 'start_date': this.iso8601 (since),
        // 'end_date': this.iso8601 (until),
        // 'wallet_fund_type': 'Deposit', // Withdraw, RealisedPNL, Commission, Refund, Prize, ExchangeOrderWithdraw, ExchangeOrderDeposit
        // 'page': 1,
        // 'limit': 20, // max 50
        // v5 transaction log
        // 'accountType': '', Account Type. UNIFIED
        // 'category': '', Product type. spot,linear,option
        // 'currency': '', Currency
        // 'baseCoin': '', BaseCoin. e.g., BTC of BTCPERP
        // 'type': '', Types of transaction logs
        // 'startTime': 0, The start timestamp (ms)
        // 'endTime': 0, The end timestamp (ms)
        // 'limit': 0, Limit for data size per page. [1, 50]. Default: 20
        // 'cursor': '', Cursor. Used for pagination
        };
        const enableUnified = await this.isUnifiedEnabled();
        let currency = undefined;
        let currencyKey = 'coin';
        if (enableUnified[1]) {
            currencyKey = 'currency';
            if (since !== undefined) {
                request['startTime'] = since;
            }
        }
        else {
            if (since !== undefined) {
                request['start_date'] = this.yyyymmdd(since);
            }
        }
        if (code !== undefined) {
            currency = this.currency(code);
            request[currencyKey] = currency['id'];
        }
        if (limit !== undefined) {
            request['limit'] = limit;
        }
        let subType = undefined;
        [subType, params] = this.handleSubTypeAndParams('fetchLedger', undefined, params);
        let response = undefined;
        if (enableUnified[1]) {
            const unifiedMarginStatus = this.safeInteger(this.options, 'unifiedMarginStatus', 5); // 3/4 uta 1.0, 5/6 uta 2.0
            if (subType === 'inverse' && (unifiedMarginStatus < 5)) {
                response = await this.privateGetV5AccountContractTransactionLog(this.extend(request, params));
            }
            else {
                response = await this.privateGetV5AccountTransactionLog(this.extend(request, params));
            }
        }
        else {
            response = await this.privateGetV5AccountContractTransactionLog(this.extend(request, params));
        }
        //
        //     {
        //         "ret_code": 0,
        //         "ret_msg": "ok",
        //         "ext_code": "",
        //         "result": {
        //             "data": [
        //                 {
        //                     "id": 234467,
        //                     "user_id": 1,
        //                     "coin": "BTC",
        //                     "wallet_id": 27913,
        //                     "type": "Realized P&L",
        //                     "amount": "-0.00000006",
        //                     "tx_id": "",
        //                     "address": "BTCUSD",
        //                     "wallet_balance": "0.03000330",
        //                     "exec_time": "2019-12-09T00:00:25.000Z",
        //                     "cross_seq": 0
        //                 }
        //             ]
        //         },
        //         "ext_info": null,
        //         "time_now": "1577481867.115552",
        //         "rate_limit_status": 119,
        //         "rate_limit_reset_ms": 1577481867122,
        //         "rate_limit": 120
        //     }
        //
        // v5 transaction log
        //
        //     {
        //         "retCode": 0,
        //         "retMsg": "OK",
        //         "result": {
        //             "nextPageCursor": "21963%3A1%2C14954%3A1",
        //             "list": [
        //                 {
        //                     "symbol": "XRPUSDT",
        //                     "side": "Buy",
        //                     "funding": "-0.003676",
        //                     "orderLinkId": "",
        //                     "orderId": "1672128000-8-592324-1-2",
        //                     "fee": "0.00000000",
        //                     "change": "-0.003676",
        //                     "cashFlow": "0",
        //                     "transactionTime": "1672128000000",
        //                     "type": "SETTLEMENT",
        //                     "feeRate": "0.0001",
        //                     "size": "100",
        //                     "qty": "100",
        //                     "cashBalance": "5086.55825002",
        //                     "currency": "USDT",
        //                     "category": "linear",
        //                     "tradePrice": "0.3676",
        //                     "tradeId": "534c0003-4bf7-486f-aa02-78cee36825e4"
        //                 },
        //                 {
        //                     "symbol": "XRPUSDT",
        //                     "side": "Buy",
        //                     "funding": "",
        //                     "orderLinkId": "linear-order",
        //                     "orderId": "592b7e41-78fd-42e2-9aa3-91e1835ef3e1",
        //                     "fee": "0.01908720",
        //                     "change": "-0.0190872",
        //                     "cashFlow": "0",
        //                     "transactionTime": "1672121182224",
        //                     "type": "TRADE",
        //                     "feeRate": "0.0006",
        //                     "size": "100",
        //                     "qty": "88",
        //                     "cashBalance": "5086.56192602",
        //                     "currency": "USDT",
        //                     "category": "linear",
        //                     "tradePrice": "0.3615",
        //                     "tradeId": "5184f079-88ec-54c7-8774-5173cafd2b4e"
        //                 },
        //                 {
        //                     "symbol": "XRPUSDT",
        //                     "side": "Buy",
        //                     "funding": "",
        //                     "orderLinkId": "linear-order",
        //                     "orderId": "592b7e41-78fd-42e2-9aa3-91e1835ef3e1",
        //                     "fee": "0.00260280",
        //                     "change": "-0.0026028",
        //                     "cashFlow": "0",
        //                     "transactionTime": "1672121182224",
        //                     "type": "TRADE",
        //                     "feeRate": "0.0006",
        //                     "size": "12",
        //                     "qty": "12",
        //                     "cashBalance": "5086.58101322",
        //                     "currency": "USDT",
        //                     "category": "linear",
        //                     "tradePrice": "0.3615",
        //                     "tradeId": "8569c10f-5061-5891-81c4-a54929847eb3"
        //                 }
        //             ]
        //         },
        //         "retExtInfo": {},
        //         "time": 1672132481405
        //     }
        //
        const data = this.addPaginationCursorToResult(response);
        return this.parseLedger(data, currency, since, limit);
    }
    parseLedgerEntry(item, currency = undefined) {
        //
        //     {
        //         "id": 234467,
        //         "user_id": 1,
        //         "coin": "BTC",
        //         "wallet_id": 27913,
        //         "type": "Realized P&L",
        //         "amount": "-0.00000006",
        //         "tx_id": "",
        //         "address": "BTCUSD",
        //         "wallet_balance": "0.03000330",
        //         "exec_time": "2019-12-09T00:00:25.000Z",
        //         "cross_seq": 0
        //     }
        //
        //     {
        //         "symbol": "XRPUSDT",
        //         "side": "Buy",
        //         "funding": "",
        //         "orderLinkId": "linear-order",
        //         "orderId": "592b7e41-78fd-42e2-9aa3-91e1835ef3e1",
        //         "fee": "0.00260280",
        //         "change": "-0.0026028",
        //         "cashFlow": "0",
        //         "transactionTime": "1672121182224",
        //         "type": "TRADE",
        //         "feeRate": "0.0006",
        //         "size": "12",
        //         "qty": "12",
        //         "cashBalance": "5086.58101322",
        //         "currency": "USDT",
        //         "category": "linear",
        //         "tradePrice": "0.3615",
        //         "tradeId": "8569c10f-5061-5891-81c4-a54929847eb3"
        //     }
        //
        const currencyId = this.safeString2(item, 'coin', 'currency');
        const code = this.safeCurrencyCode(currencyId, currency);
        currency = this.safeCurrency(currencyId, currency);
        const amountString = this.safeString2(item, 'amount', 'change');
        const afterString = this.safeString2(item, 'wallet_balance', 'cashBalance');
        const direction = Precise["default"].stringLt(amountString, '0') ? 'out' : 'in';
        let before = undefined;
        let after = undefined;
        let amount = undefined;
        if (afterString !== undefined && amountString !== undefined) {
            const difference = (direction === 'out') ? amountString : Precise["default"].stringNeg(amountString);
            before = this.parseToNumeric(Precise["default"].stringAdd(afterString, difference));
            after = this.parseToNumeric(afterString);
            amount = this.parseToNumeric(Precise["default"].stringAbs(amountString));
        }
        let timestamp = this.parse8601(this.safeString(item, 'exec_time'));
        if (timestamp === undefined) {
            timestamp = this.safeInteger(item, 'transactionTime');
        }
        return this.safeLedgerEntry({
            'info': item,
            'id': this.safeString(item, 'id'),
            'direction': direction,
            'account': this.safeString(item, 'wallet_id'),
            'referenceId': this.safeString(item, 'tx_id'),
            'referenceAccount': undefined,
            'type': this.parseLedgerEntryType(this.safeString(item, 'type')),
            'currency': code,
            'amount': amount,
            'timestamp': timestamp,
            'datetime': this.iso8601(timestamp),
            'before': before,
            'after': after,
            'status': 'ok',
            'fee': {
                'currency': code,
                'cost': this.safeNumber(item, 'fee'),
            },
        }, currency);
    }
    parseLedgerEntryType(type) {
        const types = {
            'Deposit': 'transaction',
            'Withdraw': 'transaction',
            'RealisedPNL': 'trade',
            'Commission': 'fee',
            'Refund': 'cashback',
            'Prize': 'prize',
            'ExchangeOrderWithdraw': 'transaction',
            'ExchangeOrderDeposit': 'transaction',
            // v5
            'TRANSFER_IN': 'transaction',
            'TRANSFER_OUT': 'transaction',
            'TRADE': 'trade',
            'SETTLEMENT': 'trade',
            'DELIVERY': 'trade',
            'LIQUIDATION': 'trade',
            'BONUS': 'Prize',
            'FEE_REFUND': 'cashback',
            'INTEREST': 'transaction',
            'CURRENCY_BUY': 'trade',
            'CURRENCY_SELL': 'trade',
        };
        return this.safeString(types, type, type);
    }
    /**
     * @method
     * @name bybit#withdraw
     * @description make a withdrawal
     * @see https://bybit-exchange.github.io/docs/v5/asset/withdraw
     * @param {string} code unified currency code
     * @param {float} amount the amount to withdraw
     * @param {string} address the address to withdraw to
     * @param {string} tag
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {object} a [transaction structure]{@link https://docs.ccxt.com/#/?id=transaction-structure}
     */
    async withdraw(code, amount, address, tag = undefined, params = {}) {
        [tag, params] = this.handleWithdrawTagAndParams(tag, params);
        let accountType = undefined;
        [accountType, params] = this.handleOptionAndParams(params, 'withdraw', 'accountType', 'SPOT');
        await this.loadMarkets();
        this.checkAddress(address);
        const currency = this.currency(code);
        const request = {
            'coin': currency['id'],
            'amount': this.numberToString(amount),
            'address': address,
            'timestamp': this.milliseconds(),
            'accountType': accountType,
        };
        if (tag !== undefined) {
            request['tag'] = tag;
        }
        const [networkCode, query] = this.handleNetworkCodeAndParams(params);
        const networkId = this.networkCodeToId(networkCode);
        if (networkId !== undefined) {
            request['chain'] = networkId.toUpperCase();
        }
        const response = await this.privatePostV5AssetWithdrawCreate(this.extend(request, query));
        //
        //    {
        //         "retCode": "0",
        //         "retMsg": "success",
        //         "result": {
        //             "id": "9377266"
        //         },
        //         "retExtInfo": {},
        //         "time": "1666892894902"
        //     }
        //
        const result = this.safeDict(response, 'result', {});
        return this.parseTransaction(result, currency);
    }
    /**
     * @method
     * @name bybit#fetchPosition
     * @description fetch data on a single open contract trade position
     * @see https://bybit-exchange.github.io/docs/v5/position
     * @param {string} symbol unified market symbol of the market the position is held in, default is undefined
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {object} a [position structure]{@link https://docs.ccxt.com/#/?id=position-structure}
     */
    async fetchPosition(symbol, params = {}) {
        if (symbol === undefined) {
            throw new errors.ArgumentsRequired(this.id + ' fetchPosition() requires a symbol argument');
        }
        await this.loadMarkets();
        const market = this.market(symbol);
        const request = {
            'symbol': market['id'],
        };
        let response = undefined;
        let type = undefined;
        [type, params] = this.getBybitType('fetchPosition', market, params);
        request['category'] = type;
        response = await this.privateGetV5PositionList(this.extend(request, params));
        //
        //     {
        //         "retCode": 0,
        //         "retMsg": "OK",
        //         "result": {
        //             "nextPageCursor": "updateAt%3D1672279322668",
        //             "category": "linear",
        //             "list": [
        //                 {
        //                     "symbol": "XRPUSDT",
        //                     "leverage": "10",
        //                     "avgPrice": "0.3615",
        //                     "liqPrice": "0.0001",
        //                     "riskLimitValue": "200000",
        //                     "takeProfit": "",
        //                     "positionValue": "36.15",
        //                     "tpslMode": "Full",
        //                     "riskId": 41,
        //                     "trailingStop": "0",
        //                     "unrealisedPnl": "-1.83",
        //                     "markPrice": "0.3432",
        //                     "cumRealisedPnl": "0.48805876",
        //                     "positionMM": "0.381021",
        //                     "createdTime": "1672121182216",
        //                     "positionIdx": 0,
        //                     "positionIM": "3.634521",
        //                     "updatedTime": "1672279322668",
        //                     "side": "Buy",
        //                     "bustPrice": "",
        //                     "size": "100",
        //                     "positionStatus": "Normal",
        //                     "stopLoss": "",
        //                     "tradeMode": 0
        //                 }
        //             ]
        //         },
        //         "retExtInfo": {},
        //         "time": 1672280219169
        //     }
        //
        const result = this.safeDict(response, 'result', {});
        const positions = this.safeList2(result, 'list', 'dataList', []);
        const timestamp = this.safeInteger(response, 'time');
        const first = this.safeDict(positions, 0, {});
        const position = this.parsePosition(first, market);
        position['timestamp'] = timestamp;
        position['datetime'] = this.iso8601(timestamp);
        return position;
    }
    /**
     * @method
     * @name bybit#fetchPositions
     * @description fetch all open positions
     * @see https://bybit-exchange.github.io/docs/v5/position
     * @param {string[]} symbols list of unified market symbols
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @param {string} [params.type] market type, ['swap', 'option', 'spot']
     * @param {string} [params.subType] market subType, ['linear', 'inverse']
     * @param {string} [params.baseCoin] Base coin. Supports linear, inverse & option
     * @param {string} [params.settleCoin] Settle coin. Supports linear, inverse & option
     * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times
     * @returns {object[]} a list of [position structure]{@link https://docs.ccxt.com/#/?id=position-structure}
     */
    async fetchPositions(symbols = undefined, params = {}) {
        await this.loadMarkets();
        let paginate = false;
        [paginate, params] = this.handleOptionAndParams(params, 'fetchPositions', 'paginate');
        if (paginate) {
            return await this.fetchPaginatedCallCursor('fetchPositions', symbols, undefined, undefined, params, 'nextPageCursor', 'cursor', undefined, 200);
        }
        let symbol = undefined;
        if ((symbols !== undefined) && Array.isArray(symbols)) {
            const symbolsLength = symbols.length;
            if (symbolsLength > 1) {
                throw new errors.ArgumentsRequired(this.id + ' fetchPositions() does not accept an array with more than one symbol');
            }
            else if (symbolsLength === 1) {
                symbol = symbols[0];
            }
            symbols = this.marketSymbols(symbols);
        }
        else if (symbols !== undefined) {
            symbol = symbols;
            symbols = [this.symbol(symbol)];
        }
        const request = {};
        let market = undefined;
        if (symbol !== undefined) {
            market = this.market(symbol);
            symbol = market['symbol'];
            request['symbol'] = market['id'];
        }
        let type = undefined;
        [type, params] = this.getBybitType('fetchPositions', market, params);
        if (type === 'linear' || type === 'inverse') {
            const baseCoin = this.safeString(params, 'baseCoin');
            if (type === 'linear') {
                if (symbol === undefined && baseCoin === undefined) {
                    const defaultSettle = this.safeString(this.options, 'defaultSettle', 'USDT');
                    const settleCoin = this.safeString(params, 'settleCoin', defaultSettle);
                    request['settleCoin'] = settleCoin;
                }
            }
            else {
                // inverse
                if (symbol === undefined && baseCoin === undefined) {
                    request['category'] = 'inverse';
                }
            }
        }
        if (this.safeInteger(params, 'limit') === undefined) {
            request['limit'] = 200; // max limit
        }
        params = this.omit(params, ['type']);
        request['category'] = type;
        const response = await this.privateGetV5PositionList(this.extend(request, params));
        //
        //     {
        //         "retCode": 0,
        //         "retMsg": "Success",
        //         "result": {
        //             "nextPageCursor": "0%3A1657711949945%2C0%3A1657711949945",
        //             "category": "linear",
        //             "list": [
        //                 {
        //                     "symbol": "ETHUSDT",
        //                     "leverage": "10",
        //                     "updatedTime": 1657711949945,
        //                     "side": "Buy",
        //                     "positionValue": "536.92500000",
        //                     "takeProfit": "",
        //                     "tpslMode": "Full",
        //                     "riskId": 11,
        //                     "trailingStop": "",
        //                     "entryPrice": "1073.85000000",
        //                     "unrealisedPnl": "",
        //                     "markPrice": "1080.65000000",
        //                     "size": "0.5000",
        //                     "positionStatus": "normal",
        //                     "stopLoss": "",
        //                     "cumRealisedPnl": "-0.32215500",
        //                     "positionMM": "2.97456450",
        //                     "createdTime": 1657711949928,
        //                     "positionIdx": 0,
        //                     "positionIM": "53.98243950"
        //                 }
        //             ]
        //         },
        //         "time": 1657713693182
        //     }
        //
        const positions = this.addPaginationCursorToResult(response);
        const results = [];
        for (let i = 0; i < positions.length; i++) {
            let rawPosition = positions[i];
            if (('data' in rawPosition) && ('is_valid' in rawPosition)) {
                // futures only
                rawPosition = this.safeDict(rawPosition, 'data');
            }
            results.push(this.parsePosition(rawPosition));
        }
        return this.filterByArrayPositions(results, 'symbol', symbols, false);
    }
    parsePosition(position, market = undefined) {
        //
        // linear swap
        //
        //     {
        //         "positionIdx": 0,
        //         "riskId": "11",
        //         "symbol": "ETHUSDT",
        //         "side": "Buy",
        //         "size": "0.10",
        //         "positionValue": "119.845",
        //         "entryPrice": "1198.45",
        //         "tradeMode": 1,
        //         "autoAddMargin": 0,
        //         "leverage": "4.2",
        //         "positionBalance": "28.58931118",
        //         "liqPrice": "919.10",
        //         "bustPrice": "913.15",
        //         "takeProfit": "0.00",
        //         "stopLoss": "0.00",
        //         "trailingStop": "0.00",
        //         "unrealisedPnl": "0.083",
        //         "createdTime": "1669097244192",
        //         "updatedTime": "1669413126190",
        //         "tpSlMode": "Full",
        //         "riskLimitValue": "900000",
        //         "activePrice": "0.00"
        //     }
        //
        // usdc
        //    {
        //       "symbol":"BTCPERP",
        //       "leverage":"1.00",
        //       "occClosingFee":"0.0000",
        //       "liqPrice":"",
        //       "positionValue":"30.8100",
        //       "takeProfit":"0.0",
        //       "riskId":"10001",
        //       "trailingStop":"0.0000",
        //       "unrealisedPnl":"0.0000",
        //       "createdAt":"1652451795305",
        //       "markPrice":"30809.41",
        //       "cumRealisedPnl":"0.0000",
        //       "positionMM":"0.1541",
        //       "positionIM":"30.8100",
        //       "updatedAt":"1652451795305",
        //       "tpSLMode":"UNKNOWN",
        //       "side":"Buy",
        //       "bustPrice":"",
        //       "deleverageIndicator":"0",
        //       "entryPrice":"30810.0",
        //       "size":"0.001",
        //       "sessionRPL":"0.0000",
        //       "positionStatus":"NORMAL",
        //       "sessionUPL":"-0.0006",
        //       "stopLoss":"0.0",
        //       "orderMargin":"0.0000",
        //       "sessionAvgPrice":"30810.0"
        //    }
        //
        // unified margin
        //
        //     {
        //         "symbol": "ETHUSDT",
        //         "leverage": "10",
        //         "updatedTime": 1657711949945,
        //         "side": "Buy",
        //         "positionValue": "536.92500000",
        //         "takeProfit": "",
        //         "tpslMode": "Full",
        //         "riskId": 11,
        //         "trailingStop": "",
        //         "entryPrice": "1073.85000000",
        //         "unrealisedPnl": "",
        //         "markPrice": "1080.65000000",
        //         "size": "0.5000",
        //         "positionStatus": "normal",
        //         "stopLoss": "",
        //         "cumRealisedPnl": "-0.32215500",
        //         "positionMM": "2.97456450",
        //         "createdTime": 1657711949928,
        //         "positionIdx": 0,
        //         "positionIM": "53.98243950"
        //     }
        //
        // unified account
        //
        //     {
        //         "symbol": "XRPUSDT",
        //         "leverage": "10",
        //         "avgPrice": "0.3615",
        //         "liqPrice": "0.0001",
        //         "riskLimitValue": "200000",
        //         "takeProfit": "",
        //         "positionValue": "36.15",
        //         "tpslMode": "Full",
        //         "riskId": 41,
        //         "trailingStop": "0",
        //         "unrealisedPnl": "-1.83",
        //         "markPrice": "0.3432",
        //         "cumRealisedPnl": "0.48805876",
        //         "positionMM": "0.381021",
        //         "createdTime": "1672121182216",
        //         "positionIdx": 0,
        //         "positionIM": "3.634521",
        //         "updatedTime": "1672279322668",
        //         "side": "Buy",
        //         "bustPrice": "",
        //         "size": "100",
        //         "positionStatus": "Normal",
        //         "stopLoss": "",
        //         "tradeMode": 0
        //     }
        //
        // fetchPositionsHistory
        //
        //    {
        //        symbol: 'XRPUSDT',
        //        orderType: 'Market',
        //        leverage: '10',
        //        updatedTime: '1712717265572',
        //        side: 'Sell',
        //        orderId: '071749f3-a9fa-427b-b5ca-27b2f52b81de',
        //        closedPnl: '-0.00049568',
        //        avgEntryPrice: '0.6045',
        //        qty: '3',
        //        cumEntryValue: '1.8135',
        //        createdTime: '1712717265566',
        //        orderPrice: '0.5744',
        //        closedSize: '3',
        //        avgExitPrice: '0.605',
        //        execType: 'Trade',
        //        fillCount: '1',
        //        cumExitValue: '1.815'
        //    }
        //
        const closedSize = this.safeString(position, 'closedSize');
        const isHistory = (closedSize !== undefined);
        const contract = this.safeString(position, 'symbol');
        market = this.safeMarket(contract, market, undefined, 'contract');
        const size = Precise["default"].stringAbs(this.safeString2(position, 'size', 'qty'));
        let side = this.safeString(position, 'side');
        if (side !== undefined) {
            if (side === 'Buy') {
                side = isHistory ? 'short' : 'long';
            }
            else if (side === 'Sell') {
                side = isHistory ? 'long' : 'short';
            }
            else {
                side = undefined;
            }
        }
        const notional = this.safeString2(position, 'positionValue', 'cumExitValue');
        const unrealisedPnl = this.omitZero(this.safeString(position, 'unrealisedPnl'));
        let initialMarginString = this.safeStringN(position, ['positionIM', 'cumEntryValue']);
        let maintenanceMarginString = this.safeString(position, 'positionMM');
        const timestamp = this.safeIntegerN(position, ['createdTime', 'createdAt']);
        let lastUpdateTimestamp = this.parse8601(this.safeString(position, 'updated_at'));
        if (lastUpdateTimestamp === undefined) {
            lastUpdateTimestamp = this.safeIntegerN(position, ['updatedTime', 'updatedAt', 'updatedTime']);
        }
        const tradeMode = this.safeInteger(position, 'tradeMode', 0);
        let marginMode = undefined;
        if ((!this.options['enableUnifiedAccount']) || (this.options['enableUnifiedAccount'] && market['inverse'])) {
            // tradeMode would work for classic and UTA(inverse)
            if (!isHistory) { // cannot tell marginMode for fetchPositionsHistory, and closedSize will only be defined for fetchPositionsHistory response
                marginMode = (tradeMode === 1) ? 'isolated' : 'cross';
            }
        }
        let collateralString = this.safeString(position, 'positionBalance');
        const entryPrice = this.omitZero(this.safeStringN(position, ['entryPrice', 'avgPrice', 'avgEntryPrice']));
        const liquidationPrice = this.omitZero(this.safeString(position, 'liqPrice'));
        const leverage = this.safeString(position, 'leverage');
        if (liquidationPrice !== undefined) {
            if (market['settle'] === 'USDC') {
                //  (Entry price - Liq price) * Contracts + Maintenance Margin + (unrealised pnl) = Collateral
                const difference = Precise["default"].stringAbs(Precise["default"].stringSub(entryPrice, liquidationPrice));
                collateralString = Precise["default"].stringAdd(Precise["default"].stringAdd(Precise["default"].stringMul(difference, size), maintenanceMarginString), unrealisedPnl);
            }
            else {
                const bustPrice = this.safeString(position, 'bustPrice');
                if (market['linear']) {
                    // derived from the following formulas
                    //  (Entry price - Bust price) * Contracts = Collateral
                    //  (Entry price - Liq price) * Contracts = Collateral - Maintenance Margin
                    // Maintenance Margin = (Bust price - Liq price) x Contracts
                    const maintenanceMarginPriceDifference = Precise["default"].stringAbs(Precise["default"].stringSub(liquidationPrice, bustPrice));
                    maintenanceMarginString = Precise["default"].stringMul(maintenanceMarginPriceDifference, size);
                    // Initial Margin = Contracts x Entry Price / Leverage
                    if (entryPrice !== undefined) {
                        initialMarginString = Precise["default"].stringDiv(Precise["default"].stringMul(size, entryPrice), leverage);
                    }
                }
                else {
                    // Contracts * (1 / Entry price - 1 / Bust price) = Collateral
                    // Contracts * (1 / Entry price - 1 / Liq price) = Collateral - Maintenance Margin
                    // Maintenance Margin = Contracts * (1 / Liq price - 1 / Bust price)
                    // Maintenance Margin = Contracts * (Bust price - Liq price) / (Liq price x Bust price)
                    const difference = Precise["default"].stringAbs(Precise["default"].stringSub(bustPrice, liquidationPrice));
                    const multiply = Precise["default"].stringMul(bustPrice, liquidationPrice);
                    maintenanceMarginString = Precise["default"].stringDiv(Precise["default"].stringMul(size, difference), multiply);
                    // Initial Margin = Leverage x Contracts / EntryPrice
                    if (entryPrice !== undefined) {
                        initialMarginString = Precise["default"].stringDiv(size, Precise["default"].stringMul(entryPrice, leverage));
                    }
                }
            }
        }
        const maintenanceMarginPercentage = Precise["default"].stringDiv(maintenanceMarginString, notional);
        const marginRatio = Precise["default"].stringDiv(maintenanceMarginString, collateralString, 4);
        const positionIdx = this.safeString(position, 'positionIdx');
        const hedged = (positionIdx !== undefined) && (positionIdx !== '0');
        return this.safePosition({
            'info': position,
            'id': undefined,
            'symbol': market['symbol'],
            'timestamp': timestamp,
            'datetime': this.iso8601(timestamp),
            'lastUpdateTimestamp': lastUpdateTimestamp,
            'initialMargin': this.parseNumber(initialMarginString),
            'initialMarginPercentage': this.parseNumber(Precise["default"].stringDiv(initialMarginString, notional)),
            'maintenanceMargin': this.parseNumber(maintenanceMarginString),
            'maintenanceMarginPercentage': this.parseNumber(maintenanceMarginPercentage),
            'entryPrice': this.parseNumber(entryPrice),
            'notional': this.parseNumber(notional),
            'leverage': this.parseNumber(leverage),
            'unrealizedPnl': this.parseNumber(unrealisedPnl),
            'realizedPnl': this.safeNumber(position, 'closedPnl'),
            'contracts': this.parseNumber(size),
            'contractSize': this.safeNumber(market, 'contractSize'),
            'marginRatio': this.parseNumber(marginRatio),
            'liquidationPrice': this.parseNumber(liquidationPrice),
            'markPrice': this.safeNumber(position, 'markPrice'),
            'lastPrice': this.safeNumber(position, 'avgExitPrice'),
            'collateral': this.parseNumber(collateralString),
            'marginMode': marginMode,
            'side': side,
            'percentage': undefined,
            'stopLossPrice': this.safeNumber2(position, 'stop_loss', 'stopLoss'),
            'takeProfitPrice': this.safeNumber2(position, 'take_profit', 'takeProfit'),
            'hedged': hedged,
        });
    }
    /**
     * @method
     * @name bybit#fetchLeverage
     * @description fetch the set leverage for a market
     * @see https://bybit-exchange.github.io/docs/v5/position
     * @param {string} symbol unified market symbol
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {object} a [leverage structure]{@link https://docs.ccxt.com/#/?id=leverage-structure}
     */
    async fetchLeverage(symbol, params = {}) {
        await this.loadMarkets();
        const market = this.market(symbol);
        const position = await this.fetchPosition(symbol, params);
        return this.parseLeverage(position, market);
    }
    parseLeverage(leverage, market = undefined) {
        const marketId = this.safeString(leverage, 'symbol');
        const leverageValue = this.safeInteger(leverage, 'leverage');
        return {
            'info': leverage,
            'symbol': this.safeSymbol(marketId, market),
            'marginMode': this.safeStringLower(leverage, 'marginMode'),
            'longLeverage': leverageValue,
            'shortLeverage': leverageValue,
        };
    }
    /**
     * @method
     * @name bybit#setMarginMode
     * @description set margin mode (account) or trade mode (symbol)
     * @see https://bybit-exchange.github.io/docs/v5/account/set-margin-mode
     * @see https://bybit-exchange.github.io/docs/v5/position/cross-isolate
     * @param {string} marginMode account mode must be either [isolated, cross, portfolio], trade mode must be either [isolated, cross]
     * @param {string} symbol unified market symbol of the market the position is held in, default is undefined
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @param {string} [params.leverage] the rate of leverage, is required if setting trade mode (symbol)
     * @returns {object} response from the exchange
     */
    async setMarginMode(marginMode, symbol = undefined, params = {}) {
        await this.loadMarkets();
        const [enableUnifiedMargin, enableUnifiedAccount] = await this.isUnifiedEnabled();
        const isUnifiedAccount = (enableUnifiedMargin || enableUnifiedAccount);
        let market = undefined;
        let response = undefined;
        if (isUnifiedAccount) {
            if (marginMode === 'isolated') {
                marginMode = 'ISOLATED_MARGIN';
            }
            else if (marginMode === 'cross') {
                marginMode = 'REGULAR_MARGIN';
            }
            else if (marginMode === 'portfolio') {
                marginMode = 'PORTFOLIO_MARGIN';
            }
            else {
                throw new errors.NotSupported(this.id + ' setMarginMode() marginMode must be either [isolated, cross, portfolio]');
            }
            const request = {
                'setMarginMode': marginMode,
            };
            response = await this.privatePostV5AccountSetMarginMode(this.extend(request, params));
        }
        else {
            if (symbol === undefined) {
                throw new errors.ArgumentsRequired(this.id + ' setMarginMode() requires a symbol parameter for non unified account');
            }
            market = this.market(symbol);
            const isUsdcSettled = market['settle'] === 'USDC';
            if (isUsdcSettled) {
                if (marginMode === 'cross') {
                    marginMode = 'REGULAR_MARGIN';
                }
                else if (marginMode === 'portfolio') {
                    marginMode = 'PORTFOLIO_MARGIN';
                }
                else {
                    throw new errors.NotSupported(this.id + ' setMarginMode() for usdc market marginMode must be either [cross, portfolio]');
                }
                const request = {
                    'setMarginMode': marginMode,
                };
                response = await this.privatePostV5AccountSetMarginMode(this.extend(request, params));
            }
            else {
                let type = undefined;
                [type, params] = this.getBybitType('setPositionMode', market, params);
                let tradeMode = undefined;
                if (marginMode === 'cross') {
                    tradeMode = 0;
                }
                else if (marginMode === 'isolated') {
                    tradeMode = 1;
                }
                else {
                    throw new errors.NotSupported(this.id + ' setMarginMode() with symbol marginMode must be either [isolated, cross]');
                }
                let sellLeverage = undefined;
                let buyLeverage = undefined;
                const leverage = this.safeString(params, 'leverage');
                if (leverage === undefined) {
                    sellLeverage = this.safeString2(params, 'sell_leverage', 'sellLeverage');
                    buyLeverage = this.safeString2(params, 'buy_leverage', 'buyLeverage');
                    if (sellLeverage === undefined && buyLeverage === undefined) {
                        throw new errors.ArgumentsRequired(this.id + ' setMarginMode() requires a leverage parameter or sell_leverage and buy_leverage parameters');
                    }
                    if (buyLeverage === undefined) {
                        buyLeverage = sellLeverage;
                    }
                    if (sellLeverage === undefined) {
                        sellLeverage = buyLeverage;
                    }
                    params = this.omit(params, ['buy_leverage', 'sell_leverage', 'sellLeverage', 'buyLeverage']);
                }
                else {
                    sellLeverage = leverage;
                    buyLeverage = leverage;
                    params = this.omit(params, 'leverage');
                }
                const request = {
                    'category': type,
                    'symbol': market['id'],
                    'tradeMode': tradeMode,
                    'buyLeverage': buyLeverage,
                    'sellLeverage': sellLeverage,
                };
                response = await this.privatePostV5PositionSwitchIsolated(this.extend(request, params));
            }
        }
        return response;
    }
    /**
     * @method
     * @name bybit#setLeverage
     * @description set the level of leverage for a market
     * @see https://bybit-exchange.github.io/docs/v5/position/leverage
     * @param {float} leverage the rate of leverage
     * @param {string} symbol unified market symbol
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @param {string} [params.buyLeverage] leverage for buy side
     * @param {string} [params.sellLeverage] leverage for sell side
     * @returns {object} response from the exchange
     */
    async setLeverage(leverage, symbol = undefined, params = {}) {
        if (symbol === undefined) {
            throw new errors.ArgumentsRequired(this.id + ' setLeverage() requires a symbol argument');
        }
        await this.loadMarkets();
        const market = this.market(symbol);
        // WARNING: THIS WILL INCREASE LIQUIDATION PRICE FOR OPEN ISOLATED LONG POSITIONS
        // AND DECREASE LIQUIDATION PRICE FOR OPEN ISOLATED SHORT POSITIONS
        // engage in leverage setting
        // we reuse the code here instead of having two methods
        const leverageString = this.numberToString(leverage);
        const request = {
            'symbol': market['id'],
            'buyLeverage': leverageString,
            'sellLeverage': leverageString,
        };
        request['buyLeverage'] = leverageString;
        request['sellLeverage'] = leverageString;
        if (market['linear']) {
            request['category'] = 'linear';
        }
        else if (market['inverse']) {
            request['category'] = 'inverse';
        }
        else {
            throw new errors.NotSupported(this.id + ' setLeverage() only support linear and inverse market');
        }
        const response = await this.privatePostV5PositionSetLeverage(this.extend(request, params));
        return response;
    }
    /**
     * @method
     * @name bybit#setPositionMode
     * @description set hedged to true or false for a market
     * @see https://bybit-exchange.github.io/docs/v5/position/position-mode
     * @param {bool} hedged
     * @param {string} symbol used for unified account with inverse market
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {object} response from the exchange
     */
    async setPositionMode(hedged, symbol = undefined, params = {}) {
        await this.loadMarkets();
        let market = undefined;
        if (symbol !== undefined) {
            market = this.market(symbol);
        }
        let mode = undefined;
        if (hedged) {
            mode = 3;
        }
        else {
            mode = 0;
        }
        const request = {
            'mode': mode,
        };
        if (symbol === undefined) {
            request['coin'] = 'USDT';
        }
        else {
            request['symbol'] = market['id'];
        }
        if (symbol !== undefined) {
            request['category'] = market['linear'] ? 'linear' : 'inverse';
        }
        else {
            let type = undefined;
            [type, params] = this.getBybitType('setPositionMode', market, params);
            request['category'] = type;
        }
        params = this.omit(params, 'type');
        const response = await this.privatePostV5PositionSwitchMode(this.extend(request, params));
        //
        // v5
        //     {
        //         "retCode": 0,
        //         "retMsg": "OK",
        //         "result": {},
        //         "retExtInfo": {},
        //         "time": 1675249072814
        //     }
        return response;
    }
    async fetchDerivativesOpenInterestHistory(symbol, timeframe = '1h', since = undefined, limit = undefined, params = {}) {
        await this.loadMarkets();
        let market = this.market(symbol);
        const subType = market['linear'] ? 'linear' : 'inverse';
        const category = this.safeString(params, 'category', subType);
        const intervals = this.safeDict(this.options, 'intervals');
        const interval = this.safeString(intervals, timeframe); // 5min,15min,30min,1h,4h,1d
        if (interval === undefined) {
            throw new errors.BadRequest(this.id + ' fetchOpenInterestHistory() cannot use the ' + timeframe + ' timeframe');
        }
        const request = {
            'symbol': market['id'],
            'intervalTime': interval,
            'category': category,
        };
        if (since !== undefined) {
            request['startTime'] = since;
        }
        const until = this.safeInteger(params, 'until'); // unified in milliseconds
        params = this.omit(params, ['until']);
        if (until !== undefined) {
            request['endTime'] = until;
        }
        if (limit !== undefined) {
            request['limit'] = limit;
        }
        const response = await this.publicGetV5MarketOpenInterest(this.extend(request, params));
        //
        //     {
        //         "retCode": 0,
        //         "retMsg": "OK",
        //         "result": {
        //             "symbol": "BTCUSD",
        //             "category": "inverse",
        //             "list": [
        //                 {
        //                     "openInterest": "461134384.00000000",
        //                     "timestamp": "1669571400000"
        //                 },
        //                 {
        //                     "openInterest": "461134292.00000000",
        //                     "timestamp": "1669571100000"
        //                 }
        //             ],
        //             "nextPageCursor": ""
        //         },
        //         "retExtInfo": {},
        //         "time": 1672053548579
        //     }
        //
        const result = this.safeDict(response, 'result', {});
        const data = this.addPaginationCursorToResult(response);
        const id = this.safeString(result, 'symbol');
        market = this.safeMarket(id, market, undefined, 'contract');
        return this.parseOpenInterestsHistory(data, market, since, limit);
    }
    /**
     * @method
     * @name bybit#fetchOpenInterest
     * @description Retrieves the open interest of a derivative trading pair
     * @see https://bybit-exchange.github.io/docs/v5/market/open-interest
     * @param {string} symbol Unified CCXT market symbol
     * @param {object} [params] exchange specific parameters
     * @param {string} [params.interval] 5m, 15m, 30m, 1h, 4h, 1d
     * @param {string} [params.category] "linear" or "inverse"
     * @returns {object} an open interest structure{@link https://docs.ccxt.com/#/?id=open-interest-structure}
     */
    async fetchOpenInterest(symbol, params = {}) {
        await this.loadMarkets();
        let market = this.market(symbol);
        if (!market['contract']) {
            throw new errors.BadRequest(this.id + ' fetchOpenInterest() supports contract markets only');
        }
        const timeframe = this.safeString(params, 'interval', '1h');
        const intervals = this.safeDict(this.options, 'intervals');
        const interval = this.safeString(intervals, timeframe); // 5min,15min,30min,1h,4h,1d
        if (interval === undefined) {
            throw new errors.BadRequest(this.id + ' fetchOpenInterest() cannot use the ' + timeframe + ' timeframe');
        }
        const subType = market['linear'] ? 'linear' : 'inverse';
        const category = this.safeString(params, 'category', subType);
        const request = {
            'symbol': market['id'],
            'intervalTime': interval,
            'category': category,
        };
        const response = await this.publicGetV5MarketOpenInterest(this.extend(request, params));
        //
        //     {
        //         "retCode": 0,
        //         "retMsg": "OK",
        //         "result": {
        //             "symbol": "BTCUSD",
        //             "category": "inverse",
        //             "list": [
        //                 {
        //                     "openInterest": "461134384.00000000",
        //                     "timestamp": "1669571400000"
        //                 },
        //                 {
        //                     "openInterest": "461134292.00000000",
        //                     "timestamp": "1669571100000"
        //                 }
        //             ],
        //             "nextPageCursor": ""
        //         },
        //         "retExtInfo": {},
        //         "time": 1672053548579
        //     }
        //
        const result = this.safeDict(response, 'result', {});
        const id = this.safeString(result, 'symbol');
        market = this.safeMarket(id, market, undefined, 'contract');
        const data = this.addPaginationCursorToResult(response);
        return this.parseOpenInterest(data[0], market);
    }
    /**
     * @method
     * @name bybit#fetchOpenInterestHistory
     * @description Gets the total amount of unsettled contracts. In other words, the total number of contracts held in open positions
     * @see https://bybit-exchange.github.io/docs/v5/market/open-interest
     * @param {string} symbol Unified market symbol
     * @param {string} timeframe "5m", 15m, 30m, 1h, 4h, 1d
     * @param {int} [since] Not used by Bybit
     * @param {int} [limit] The number of open interest structures to return. Max 200, default 50
     * @param {object} [params] Exchange specific parameters
     * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
     * @returns An array of open interest structures
     */
    async fetchOpenInterestHistory(symbol, timeframe = '1h', since = undefined, limit = undefined, params = {}) {
        if (timeframe === '1m') {
            throw new errors.BadRequest(this.id + ' fetchOpenInterestHistory cannot use the 1m timeframe');
        }
        await this.loadMarkets();
        const paginate = this.safeBool(params, 'paginate');
        if (paginate) {
            params = this.omit(params, 'paginate');
            params['timeframe'] = timeframe;
            return await this.fetchPaginatedCallCursor('fetchOpenInterestHistory', symbol, since, limit, params, 'nextPageCursor', 'cursor', undefined, 200);
        }
        const market = this.market(symbol);
        if (market['spot'] || market['option']) {
            throw new errors.BadRequest(this.id + ' fetchOpenInterestHistory() symbol does not support market ' + symbol);
        }
        ({
            'symbol': market['id'],
        });
        return await this.fetchDerivativesOpenInterestHistory(symbol, timeframe, since, limit, params);
    }
    parseOpenInterest(interest, market = undefined) {
        //
        //    {
        //        "openInterest": 64757.62400000,
        //        "timestamp": 1665784800000,
        //    }
        //
        const timestamp = this.safeInteger(interest, 'timestamp');
        const openInterest = this.safeNumber2(interest, 'open_interest', 'openInterest');
        // the openInterest is in the base asset for linear and quote asset for inverse
        const amount = market['linear'] ? openInterest : undefined;
        const value = market['inverse'] ? openInterest : undefined;
        return this.safeOpenInterest({
            'symbol': market['symbol'],
            'openInterestAmount': amount,
            'openInterestValue': value,
            'timestamp': timestamp,
            'datetime': this.iso8601(timestamp),
            'info': interest,
        }, market);
    }
    /**
     * @method
     * @name bybit#fetchCrossBorrowRate
     * @description fetch the rate of interest to borrow a currency for margin trading
     * @see https://bybit-exchange.github.io/docs/zh-TW/v5/spot-margin-normal/interest-quota
     * @param {string} code unified currency code
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {object} a [borrow rate structure]{@link https://docs.ccxt.com/#/?id=borrow-rate-structure}
     */
    async fetchCrossBorrowRate(code, params = {}) {
        await this.loadMarkets();
        const currency = this.currency(code);
        const request = {
            'coin': currency['id'],
        };
        const response = await this.privateGetV5SpotCrossMarginTradeLoanInfo(this.extend(request, params));
        //
        //    {
        //         "retCode": "0",
        //         "retMsg": "success",
        //         "result": {
        //             "coin": "USDT",
        //             "interestRate": "0.000107000000",
        //             "loanAbleAmount": "",
        //             "maxLoanAmount": "79999.999"
        //         },
        //         "retExtInfo": null,
        //         "time": "1666734490778"
        //     }
        //
        const timestamp = this.safeInteger(response, 'time');
        const data = this.safeDict(response, 'result', {});
        data['timestamp'] = timestamp;
        return this.parseBorrowRate(data, currency);
    }
    parseBorrowRate(info, currency = undefined) {
        //
        //     {
        //         "coin": "USDT",
        //         "interestRate": "0.000107000000",
        //         "loanAbleAmount": "",
        //         "maxLoanAmount": "79999.999",
        //         "timestamp": 1666734490778
        //     }
        //
        // fetchBorrowRateHistory
        //     {
        //         "timestamp": 1721469600000,
        //         "currency": "USDC",
        //         "hourlyBorrowRate": "0.000014621596",
        //         "vipLevel": "No VIP"
        //     }
        //
        const timestamp = this.safeInteger(info, 'timestamp');
        const currencyId = this.safeString2(info, 'coin', 'currency');
        const hourlyBorrowRate = this.safeNumber(info, 'hourlyBorrowRate');
        const period = (hourlyBorrowRate !== undefined) ? 3600000 : 86400000; // 1h or 1d
        return {
            'currency': this.safeCurrencyCode(currencyId, currency),
            'rate': this.safeNumber(info, 'interestRate', hourlyBorrowRate),
            'period': period,
            'timestamp': timestamp,
            'datetime': this.iso8601(timestamp),
            'info': info,
        };
    }
    /**
     * @method
     * @name bybit#fetchBorrowInterest
     * @description fetch the interest owed by the user for borrowing currency for margin trading
     * @see https://bybit-exchange.github.io/docs/zh-TW/v5/spot-margin-normal/account-info
     * @param {string} code unified currency code
     * @param {string} symbol unified market symbol when fetch interest in isolated markets
     * @param {number} [since] the earliest time in ms to fetch borrrow interest for
     * @param {number} [limit] the maximum number of structures to retrieve
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {object[]} a list of [borrow interest structures]{@link https://docs.ccxt.com/#/?id=borrow-interest-structure}
     */
    async fetchBorrowInterest(code = undefined, symbol = undefined, since = undefined, limit = undefined, params = {}) {
        await this.loadMarkets();
        const request = {};
        const response = await this.privateGetV5SpotCrossMarginTradeAccount(this.extend(request, params));
        //
        //     {
        //         "ret_code": 0,
        //         "ret_msg": "",
        //         "ext_code": null,
        //         "ext_info": null,
        //         "result": {
        //             "status": "1",
        //             "riskRate": "0",
        //             "acctBalanceSum": "0.000486213817680857",
        //             "debtBalanceSum": "0",
        //             "loanAccountList": [
        //                 {
        //                     "tokenId": "BTC",
        //                     "total": "0.00048621",
        //                     "locked": "0",
        //                     "loan": "0",
        //                     "interest": "0",
        //                     "free": "0.00048621"
        //                 },
        //                 ...
        //             ]
        //         }
        //     }
        //
        const data = this.safeDict(response, 'result', {});
        const rows = this.safeList(data, 'loanAccountList', []);
        const interest = this.parseBorrowInterests(rows, undefined);
        return this.filterByCurrencySinceLimit(interest, code, since, limit);
    }
    /**
     * @method
     * @name bybit#fetchBorrowRateHistory
     * @description retrieves a history of a currencies borrow interest rate at specific time slots
     * @see https://bybit-exchange.github.io/docs/v5/spot-margin-uta/historical-interest
     * @param {string} code unified currency code
     * @param {int} [since] timestamp for the earliest borrow rate
     * @param {int} [limit] the maximum number of [borrow rate structures]{@link https://docs.ccxt.com/#/?id=borrow-rate-structure} to retrieve
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @param {int} [params.until] the latest time in ms to fetch entries for
     * @returns {object[]} an array of [borrow rate structures]{@link https://docs.ccxt.com/#/?id=borrow-rate-structure}
     */
    async fetchBorrowRateHistory(code, since = undefined, limit = undefined, params = {}) {
        await this.loadMarkets();
        const currency = this.currency(code);
        const request = {
            'currency': currency['id'],
        };
        if (since === undefined) {
            since = this.milliseconds() - 86400000 * 30; // last 30 days
        }
        request['startTime'] = since;
        let endTime = this.safeInteger2(params, 'until', 'endTime');
        params = this.omit(params, ['until']);
        if (endTime === undefined) {
            endTime = since + 86400000 * 30; // since + 30 days
        }
        request['endTime'] = endTime;
        const response = await this.privateGetV5SpotMarginTradeInterestRateHistory(this.extend(request, params));
        //
        //   {
        //       "retCode": 0,
        //       "retMsg": "OK",
        //       "result": {
        //           "list": [
        //               {
        //                   "timestamp": 1721469600000,
        //                   "currency": "USDC",
        //                   "hourlyBorrowRate": "0.000014621596",
        //                   "vipLevel": "No VIP"
        //               }
        //           ]
        //       },
        //       "retExtInfo": "{}",
        //       "time": 1721899048991
        //   }
        //
        const data = this.safeDict(response, 'result');
        const rows = this.safeList(data, 'list', []);
        return this.parseBorrowRateHistory(rows, code, since, limit);
    }
    parseBorrowInterest(info, market = undefined) {
        //
        //     {
        //         "tokenId": "BTC",
        //         "total": "0.00048621",
        //         "locked": "0",
        //         "loan": "0",
        //         "interest": "0",
        //         "free": "0.00048621"
        //     },
        //
        return {
            'info': info,
            'symbol': undefined,
            'currency': this.safeCurrencyCode(this.safeString(info, 'tokenId')),
            'interest': this.safeNumber(info, 'interest'),
            'interestRate': undefined,
            'amountBorrowed': this.safeNumber(info, 'loan'),
            'marginMode': 'cross',
            'timestamp': undefined,
            'datetime': undefined,
        };
    }
    /**
     * @method
     * @name bybit#transfer
     * @description transfer currency internally between wallets on the same account
     * @see https://bybit-exchange.github.io/docs/v5/asset/create-inter-transfer
     * @param {string} code unified currency code
     * @param {float} amount amount to transfer
     * @param {string} fromAccount account to transfer from
     * @param {string} toAccount account to transfer to
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @param {string} [params.transferId] UUID, which is unique across the platform
     * @returns {object} a [transfer structure]{@link https://docs.ccxt.com/#/?id=transfer-structure}
     */
    async transfer(code, amount, fromAccount, toAccount, params = {}) {
        await this.loadMarkets();
        const transferId = this.safeString(params, 'transferId', this.uuid());
        const accountTypes = this.safeDict(this.options, 'accountsByType', {});
        const fromId = this.safeString(accountTypes, fromAccount, fromAccount);
        const toId = this.safeString(accountTypes, toAccount, toAccount);
        const currency = this.currency(code);
        const amountToPrecision = this.currencyToPrecision(code, amount);
        const request = {
            'transferId': transferId,
            'fromAccountType': fromId,
            'toAccountType': toId,
            'coin': currency['id'],
            'amount': amountToPrecision,
        };
        const response = await this.privatePostV5AssetTransferInterTransfer(this.extend(request, params));
        //
        // {
        //     "retCode": 0,
        //     "retMsg": "success",
        //     "result": {
        //         "transferId": "4244af44-f3b0-4cf6-a743-b56560e987bc"
        //     },
        //     "retExtInfo": {},
        //     "time": 1666875857205
        // }
        //
        const timestamp = this.safeInteger(response, 'time');
        const transfer = this.safeDict(response, 'result', {});
        const statusRaw = this.safeStringN(response, ['retCode', 'retMsg']);
        const status = this.parseTransferStatus(statusRaw);
        return this.extend(this.parseTransfer(transfer, currency), {
            'timestamp': timestamp,
            'datetime': this.iso8601(timestamp),
            'amount': this.parseNumber(amountToPrecision),
            'fromAccount': fromAccount,
            'toAccount': toAccount,
            'status': status,
        });
    }
    /**
     * @method
     * @name bybit#fetchTransfers
     * @description fetch a history of internal transfers made on an account
     * @see https://bybit-exchange.github.io/docs/v5/asset/inter-transfer-list
     * @param {string} 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 transfer structures to retrieve
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @param {int} [params.until] the latest time in ms to fetch entries for
     * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
     * @returns {object[]} a list of [transfer structures]{@link https://docs.ccxt.com/#/?id=transfer-structure}
     */
    async fetchTransfers(code = undefined, since = undefined, limit = undefined, params = {}) {
        await this.loadMarkets();
        let paginate = false;
        [paginate, params] = this.handleOptionAndParams(params, 'fetchTransfers', 'paginate');
        if (paginate) {
            return await this.fetchPaginatedCallCursor('fetchTransfers', code, since, limit, params, 'nextPageCursor', 'cursor', undefined, 50);
        }
        let currency = undefined;
        let request = {};
        if (code !== undefined) {
            currency = this.safeCurrency(code);
            request['coin'] = currency['id'];
        }
        if (since !== undefined) {
            request['startTime'] = since;
        }
        if (limit !== undefined) {
            request['limit'] = limit;
        }
        [request, params] = this.handleUntilOption('endTime', request, params);
        const response = await this.privateGetV5AssetTransferQueryInterTransferList(this.extend(request, params));
        //
        //     {
        //         "retCode": 0,
        //         "retMsg": "success",
        //         "result": {
        //             "list": [
        //                 {
        //                     "transferId": "selfTransfer_a1091cc7-9364-4b74-8de1-18f02c6f2d5c",
        //                     "coin": "USDT",
        //                     "amount": "5000",
        //                     "fromAccountType": "SPOT",
        //                     "toAccountType": "UNIFIED",
        //                     "timestamp": "1667283263000",
        //                     "status": "SUCCESS"
        //                 }
        //             ],
        //             "nextPageCursor": "eyJtaW5JRCI6MTM1ODQ2OCwibWF4SUQiOjEzNTg0Njh9"
        //         },
        //         "retExtInfo": {},
        //         "time": 1670988271677
        //     }
        //
        const data = this.addPaginationCursorToResult(response);
        return this.parseTransfers(data, currency, since, limit);
    }
    /**
     * @method
     * @name bybit#borrowCrossMargin
     * @description create a loan to borrow margin
     * @see https://bybit-exchange.github.io/docs/v5/spot-margin-normal/borrow
     * @param {string} code unified currency code of the currency to borrow
     * @param {float} amount the amount to borrow
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {object} a [margin loan structure]{@link https://docs.ccxt.com/#/?id=margin-loan-structure}
     */
    async borrowCrossMargin(code, amount, params = {}) {
        await this.loadMarkets();
        const currency = this.currency(code);
        const request = {
            'coin': currency['id'],
            'qty': this.currencyToPrecision(code, amount),
        };
        const response = await this.privatePostV5SpotCrossMarginTradeLoan(this.extend(request, params));
        //
        //     {
        //         "retCode": 0,
        //         "retMsg": "success",
        //         "result": {
        //             "transactId": "14143"
        //         },
        //         "retExtInfo": null,
        //         "time": 1662617848970
        //     }
        //
        const result = this.safeDict(response, 'result', {});
        const transaction = this.parseMarginLoan(result, currency);
        return this.extend(transaction, {
            'symbol': undefined,
            'amount': amount,
        });
    }
    /**
     * @method
     * @name bybit#repayCrossMargin
     * @description repay borrowed margin and interest
     * @see https://bybit-exchange.github.io/docs/v5/spot-margin-normal/repay
     * @param {string} code unified currency code of the currency to repay
     * @param {float} amount the amount to repay
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {object} a [margin loan structure]{@link https://docs.ccxt.com/#/?id=margin-loan-structure}
     */
    async repayCrossMargin(code, amount, params = {}) {
        await this.loadMarkets();
        const currency = this.currency(code);
        const request = {
            'coin': currency['id'],
            'qty': this.numberToString(amount),
        };
        const response = await this.privatePostV5SpotCrossMarginTradeRepay(this.extend(request, params));
        //
        //     {
        //         "retCode": 0,
        //         "retMsg": "success",
        //         "result": {
        //            "repayId": "12128"
        //         },
        //         "retExtInfo": null,
        //         "time": 1662618298452
        //     }
        //
        const result = this.safeDict(response, 'result', {});
        const transaction = this.parseMarginLoan(result, currency);
        return this.extend(transaction, {
            'symbol': undefined,
            'amount': amount,
        });
    }
    parseMarginLoan(info, currency = undefined) {
        //
        // borrowCrossMargin
        //
        //     {
        //         "transactId": "14143"
        //     }
        //
        // repayCrossMargin
        //
        //     {
        //         "repayId": "12128"
        //     }
        //
        return {
            'id': this.safeString2(info, 'transactId', 'repayId'),
            'currency': this.safeString(currency, 'code'),
            'amount': undefined,
            'symbol': undefined,
            'timestamp': undefined,
            'datetime': undefined,
            'info': info,
        };
    }
    parseTransferStatus(status) {
        const statuses = {
            '0': 'ok',
            'OK': 'ok',
            'SUCCESS': 'ok',
        };
        return this.safeString(statuses, status, status);
    }
    parseTransfer(transfer, currency = undefined) {
        //
        // transfer
        //
        //     {
        //         "transferId": "22c2bc11-ed5b-49a4-8647-c4e0f5f6f2b2"
        //     }
        //
        // fetchTransfers
        //
        //     {
        //         "transferId": "e9c421c4-b010-4b16-abd6-106179f27702",
        //         "coin": "USDT",
        //         "amount": "8",
        //         "fromAccountType": "FUND",
        //         "toAccountType": "SPOT",
        //         "timestamp": "1666879426000",
        //         "status": "SUCCESS"
        //      }
        //
        const currencyId = this.safeString(transfer, 'coin');
        const timestamp = this.safeInteger(transfer, 'timestamp');
        const fromAccountId = this.safeString(transfer, 'fromAccountType');
        const toAccountId = this.safeString(transfer, 'toAccountType');
        const accountIds = this.safeDict(this.options, 'accountsById', {});
        const fromAccount = this.safeString(accountIds, fromAccountId, fromAccountId);
        const toAccount = this.safeString(accountIds, toAccountId, toAccountId);
        return {
            'info': transfer,
            'id': this.safeString(transfer, 'transferId'),
            'timestamp': timestamp,
            'datetime': this.iso8601(timestamp),
            'currency': this.safeCurrencyCode(currencyId, currency),
            'amount': this.safeNumber(transfer, 'amount'),
            'fromAccount': fromAccount,
            'toAccount': toAccount,
            'status': this.parseTransferStatus(this.safeString(transfer, 'status')),
        };
    }
    async fetchDerivativesMarketLeverageTiers(symbol, params = {}) {
        await this.loadMarkets();
        const market = this.market(symbol);
        const request = {
            'symbol': market['id'],
        };
        if (market['linear']) {
            request['category'] = 'linear';
        }
        else if (market['inverse']) {
            request['category'] = 'inverse';
        }
        const response = await this.publicGetV5MarketRiskLimit(this.extend(request, params));
        //
        //     {
        //         "retCode": 0,
        //         "retMsg": "OK",
        //         "result": {
        //             "category": "inverse",
        //             "list": [
        //                 {
        //                     "id": 1,
        //                     "symbol": "BTCUSD",
        //                     "riskLimitValue": "150",
        //                     "maintenanceMargin": "0.5",
        //                     "initialMargin": "1",
        //                     "isLowestRisk": 1,
        //                     "maxLeverage": "100.00"
        //                 },
        //             ....
        //             ]
        //         },
        //         "retExtInfo": {},
        //         "time": 1672054488010
        //     }
        //
        const result = this.safeDict(response, 'result');
        const tiers = this.safeList(result, 'list');
        return this.parseMarketLeverageTiers(tiers, market);
    }
    /**
     * @method
     * @name bybit#fetchMarketLeverageTiers
     * @description retrieve information on the maximum leverage, and maintenance margin for trades of varying trade sizes for a single market
     * @see https://bybit-exchange.github.io/docs/v5/market/risk-limit
     * @param {string} symbol unified market symbol
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {object} a [leverage tiers structure]{@link https://docs.ccxt.com/#/?id=leverage-tiers-structure}
     */
    async fetchMarketLeverageTiers(symbol, params = {}) {
        await this.loadMarkets();
        let market = undefined;
        market = this.market(symbol);
        if (market['spot'] || market['option']) {
            throw new errors.BadRequest(this.id + ' fetchMarketLeverageTiers() symbol does not support market ' + symbol);
        }
        market['id'];
        return await this.fetchDerivativesMarketLeverageTiers(symbol, params);
    }
    parseTradingFee(fee, market = undefined) {
        //
        //     {
        //         "symbol": "ETHUSDT",
        //         "makerFeeRate": 0.001,
        //         "takerFeeRate": 0.001
        //     }
        //
        const marketId = this.safeString(fee, 'symbol');
        const defaultType = (market !== undefined) ? market['type'] : 'contract';
        const symbol = this.safeSymbol(marketId, market, undefined, defaultType);
        return {
            'info': fee,
            'symbol': symbol,
            'maker': this.safeNumber(fee, 'makerFeeRate'),
            'taker': this.safeNumber(fee, 'takerFeeRate'),
            'percentage': undefined,
            'tierBased': undefined,
        };
    }
    /**
     * @method
     * @name bybit#fetchTradingFee
     * @description fetch the trading fees for a market
     * @see https://bybit-exchange.github.io/docs/v5/account/fee-rate
     * @param {string} symbol unified market symbol
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {object} a [fee structure]{@link https://docs.ccxt.com/#/?id=fee-structure}
     */
    async fetchTradingFee(symbol, params = {}) {
        await this.loadMarkets();
        const market = this.market(symbol);
        const request = {
            'symbol': market['id'],
        };
        let category = undefined;
        [category, params] = this.getBybitType('fetchTradingFee', market, params);
        request['category'] = category;
        const response = await this.privateGetV5AccountFeeRate(this.extend(request, params));
        //
        //     {
        //         "retCode": 0,
        //         "retMsg": "OK",
        //         "result": {
        //             "list": [
        //                 {
        //                     "symbol": "ETHUSDT",
        //                     "takerFeeRate": "0.0006",
        //                     "makerFeeRate": "0.0001"
        //                 }
        //             ]
        //         },
        //         "retExtInfo": {},
        //         "time": 1676360412576
        //     }
        //
        const result = this.safeDict(response, 'result', {});
        const fees = this.safeList(result, 'list', []);
        const first = this.safeDict(fees, 0, {});
        return this.parseTradingFee(first, market);
    }
    /**
     * @method
     * @name bybit#fetchTradingFees
     * @description fetch the trading fees for multiple markets
     * @see https://bybit-exchange.github.io/docs/v5/account/fee-rate
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @param {string} [params.type] market type, ['swap', 'option', 'spot']
     * @returns {object} a dictionary of [fee structures]{@link https://docs.ccxt.com/#/?id=fee-structure} indexed by market symbols
     */
    async fetchTradingFees(params = {}) {
        await this.loadMarkets();
        let type = undefined;
        [type, params] = this.handleOptionAndParams(params, 'fetchTradingFees', 'type', 'future');
        if (type === 'spot') {
            throw new errors.NotSupported(this.id + ' fetchTradingFees() is not supported for spot market');
        }
        const response = await this.privateGetV5AccountFeeRate(params);
        //
        //     {
        //         "retCode": 0,
        //         "retMsg": "OK",
        //         "result": {
        //             "list": [
        //                 {
        //                     "symbol": "ETHUSDT",
        //                     "takerFeeRate": "0.0006",
        //                     "makerFeeRate": "0.0001"
        //                 }
        //             ]
        //         },
        //         "retExtInfo": {},
        //         "time": 1676360412576
        //     }
        //
        let fees = this.safeDict(response, 'result', {});
        fees = this.safeList(fees, 'list', []);
        const result = {};
        for (let i = 0; i < fees.length; i++) {
            const fee = this.parseTradingFee(fees[i]);
            const symbol = fee['symbol'];
            result[symbol] = fee;
        }
        return result;
    }
    parseDepositWithdrawFee(fee, currency = undefined) {
        //
        //    {
        //        "name": "BTC",
        //        "coin": "BTC",
        //        "remainAmount": "150",
        //        "chains": [
        //            {
        //                "chainType": "BTC",
        //                "confirmation": "10000",
        //                "withdrawFee": "0.0005",
        //                "depositMin": "0.0005",
        //                "withdrawMin": "0.001",
        //                "chain": "BTC",
        //                "chainDeposit": "1",
        //                "chainWithdraw": "1",
        //                "minAccuracy": "8"
        //            }
        //        ]
        //    }
        //
        const chains = this.safeList(fee, 'chains', []);
        const chainsLength = chains.length;
        const result = {
            'info': fee,
            'withdraw': {
                'fee': undefined,
                'percentage': undefined,
            },
            'deposit': {
                'fee': undefined,
                'percentage': undefined,
            },
            'networks': {},
        };
        if (chainsLength !== 0) {
            for (let i = 0; i < chainsLength; i++) {
                const chain = chains[i];
                const networkId = this.safeString(chain, 'chain');
                const currencyCode = this.safeString(currency, 'code');
                const networkCode = this.networkIdToCode(networkId, currencyCode);
                result['networks'][networkCode] = {
                    'deposit': { 'fee': undefined, 'percentage': undefined },
                    'withdraw': { 'fee': this.safeNumber(chain, 'withdrawFee'), 'percentage': false },
                };
                if (chainsLength === 1) {
                    result['withdraw']['fee'] = this.safeNumber(chain, 'withdrawFee');
                    result['withdraw']['percentage'] = false;
                }
            }
        }
        return result;
    }
    /**
     * @method
     * @name bybit#fetchDepositWithdrawFees
     * @description fetch deposit and withdraw fees
     * @see https://bybit-exchange.github.io/docs/v5/asset/coin-info
     * @param {string[]} codes list of unified currency codes
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {object} a list of [fee structures]{@link https://docs.ccxt.com/#/?id=fee-structure}
     */
    async fetchDepositWithdrawFees(codes = undefined, params = {}) {
        this.checkRequiredCredentials();
        await this.loadMarkets();
        const response = await this.privateGetV5AssetCoinQueryInfo(params);
        //
        //     {
        //         "retCode": 0,
        //         "retMsg": "",
        //         "result": {
        //             "rows": [
        //                 {
        //                     "name": "BTC",
        //                     "coin": "BTC",
        //                     "remainAmount": "150",
        //                     "chains": [
        //                         {
        //                             "chainType": "BTC",
        //                             "confirmation": "10000",
        //                             "withdrawFee": "0.0005",
        //                             "depositMin": "0.0005",
        //                             "withdrawMin": "0.001",
        //                             "chain": "BTC",
        //                             "chainDeposit": "1",
        //                             "chainWithdraw": "1",
        //                             "minAccuracy": "8"
        //                         }
        //                     ]
        //                 }
        //             ]
        //         },
        //         "retExtInfo": {},
        //         "time": 1672194582264
        //     }
        //
        const data = this.safeDict(response, 'result', {});
        const rows = this.safeList(data, 'rows', []);
        return this.parseDepositWithdrawFees(rows, codes, 'coin');
    }
    /**
     * @method
     * @name bybit#fetchSettlementHistory
     * @description fetches historical settlement records
     * @see https://bybit-exchange.github.io/docs/v5/market/delivery-price
     * @param {string} symbol unified market symbol of the settlement history
     * @param {int} [since] timestamp in ms
     * @param {int} [limit] number of records
     * @param {object} [params] exchange specific params
     * @param {string} [params.type] market type, ['swap', 'option', 'spot']
     * @param {string} [params.subType] market subType, ['linear', 'inverse']
     * @returns {object[]} a list of [settlement history objects]
     */
    async fetchSettlementHistory(symbol = undefined, since = undefined, limit = undefined, params = {}) {
        await this.loadMarkets();
        const request = {};
        let market = undefined;
        if (symbol !== undefined) {
            market = this.market(symbol);
            request['symbol'] = market['id'];
        }
        let type = undefined;
        [type, params] = this.getBybitType('fetchSettlementHistory', market, params);
        if (type === 'spot') {
            throw new errors.NotSupported(this.id + ' fetchSettlementHistory() is not supported for spot market');
        }
        request['category'] = type;
        if (limit !== undefined) {
            request['limit'] = limit;
        }
        const response = await this.publicGetV5MarketDeliveryPrice(this.extend(request, params));
        //
        //     {
        //         "retCode": 0,
        //         "retMsg": "success",
        //         "result": {
        //             "category": "option",
        //             "nextPageCursor": "0%2C3",
        //             "list": [
        //                 {
        //                     "symbol": "SOL-27JUN23-20-C",
        //                     "deliveryPrice": "16.62258889",
        //                     "deliveryTime": "1687852800000"
        //                 },
        //             ]
        //         },
        //         "retExtInfo": {},
        //         "time": 1689043527231
        //     }
        //
        const result = this.safeDict(response, 'result', {});
        const data = this.safeList(result, 'list', []);
        const settlements = this.parseSettlements(data, market);
        const sorted = this.sortBy(settlements, 'timestamp');
        return this.filterBySymbolSinceLimit(sorted, market['symbol'], since, limit);
    }
    /**
     * @method
     * @name bybit#fetchMySettlementHistory
     * @description fetches historical settlement records of the user
     * @see https://bybit-exchange.github.io/docs/v5/asset/delivery
     * @param {string} symbol unified market symbol of the settlement history
     * @param {int} [since] timestamp in ms
     * @param {int} [limit] number of records
     * @param {object} [params] exchange specific params
     * @param {string} [params.type] market type, ['swap', 'option', 'spot']
     * @param {string} [params.subType] market subType, ['linear', 'inverse']
     * @returns {object[]} a list of [settlement history objects]
     */
    async fetchMySettlementHistory(symbol = undefined, since = undefined, limit = undefined, params = {}) {
        await this.loadMarkets();
        const request = {};
        let market = undefined;
        if (symbol !== undefined) {
            market = this.market(symbol);
            request['symbol'] = market['id'];
        }
        let type = undefined;
        [type, params] = this.getBybitType('fetchMySettlementHistory', market, params);
        if (type === 'spot') {
            throw new errors.NotSupported(this.id + ' fetchMySettlementHistory() is not supported for spot market');
        }
        request['category'] = type;
        if (limit !== undefined) {
            request['limit'] = limit;
        }
        const response = await this.privateGetV5AssetDeliveryRecord(this.extend(request, params));
        //
        //     {
        //         "retCode": 0,
        //         "retMsg": "success",
        //         "result": {
        //             "category": "option",
        //             "nextPageCursor": "0%2C3",
        //             "list": [
        //                 {
        //                     "symbol": "SOL-27JUN23-20-C",
        //                     "deliveryPrice": "16.62258889",
        //                     "deliveryTime": "1687852800000",
        //                     "side": "Buy",
        //                     "strike": "20",
        //                     "fee": "0.00000000",
        //                     "position": "0.01",
        //                     "deliveryRpl": "3.5"
        //                 },
        //             ]
        //         },
        //         "retExtInfo": {},
        //         "time": 1689043527231
        //     }
        //
        const result = this.safeDict(response, 'result', {});
        const data = this.safeList(result, 'list', []);
        const settlements = this.parseSettlements(data, market);
        const sorted = this.sortBy(settlements, 'timestamp');
        return this.filterBySymbolSinceLimit(sorted, market['symbol'], since, limit);
    }
    parseSettlement(settlement, market) {
        //
        // fetchSettlementHistory
        //
        //     {
        //         "symbol": "SOL-27JUN23-20-C",
        //         "deliveryPrice": "16.62258889",
        //         "deliveryTime": "1687852800000"
        //     }
        //
        // fetchMySettlementHistory
        //
        //     {
        //         "symbol": "SOL-27JUN23-20-C",
        //         "deliveryPrice": "16.62258889",
        //         "deliveryTime": "1687852800000",
        //         "side": "Buy",
        //         "strike": "20",
        //         "fee": "0.00000000",
        //         "position": "0.01",
        //         "deliveryRpl": "3.5"
        //     }
        //
        const timestamp = this.safeInteger(settlement, 'deliveryTime');
        const marketId = this.safeString(settlement, 'symbol');
        return {
            'info': settlement,
            'symbol': this.safeSymbol(marketId, market),
            'price': this.safeNumber(settlement, 'deliveryPrice'),
            'timestamp': timestamp,
            'datetime': this.iso8601(timestamp),
        };
    }
    parseSettlements(settlements, market) {
        //
        // fetchSettlementHistory
        //
        //     [
        //         {
        //             "symbol": "SOL-27JUN23-20-C",
        //             "deliveryPrice": "16.62258889",
        //             "deliveryTime": "1687852800000"
        //         }
        //     ]
        //
        // fetchMySettlementHistory
        //
        //     [
        //         {
        //             "symbol": "SOL-27JUN23-20-C",
        //             "deliveryPrice": "16.62258889",
        //             "deliveryTime": "1687852800000",
        //             "side": "Buy",
        //             "strike": "20",
        //             "fee": "0.00000000",
        //             "position": "0.01",
        //             "deliveryRpl": "3.5"
        //         }
        //     ]
        //
        const result = [];
        for (let i = 0; i < settlements.length; i++) {
            result.push(this.parseSettlement(settlements[i], market));
        }
        return result;
    }
    /**
     * @method
     * @name bybit#fetchVolatilityHistory
     * @description fetch the historical volatility of an option market based on an underlying asset
     * @see https://bybit-exchange.github.io/docs/v5/market/iv
     * @param {string} code unified currency code
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @param {int} [params.period] the period in days to fetch the volatility for: 7,14,21,30,60,90,180,270
     * @returns {object[]} a list of [volatility history objects]{@link https://docs.ccxt.com/#/?id=volatility-structure}
     */
    async fetchVolatilityHistory(code, params = {}) {
        await this.loadMarkets();
        const currency = this.currency(code);
        const request = {
            'category': 'option',
            'baseCoin': currency['id'],
        };
        const response = await this.publicGetV5MarketHistoricalVolatility(this.extend(request, params));
        //
        //     {
        //         "retCode": 0,
        //         "retMsg": "SUCCESS",
        //         "category": "option",
        //         "result": [
        //             {
        //                 "period": 7,
        //                 "value": "0.23854072",
        //                 "time": "1690574400000"
        //             }
        //         ]
        //     }
        //
        const volatility = this.safeList(response, 'result', []);
        return this.parseVolatilityHistory(volatility);
    }
    parseVolatilityHistory(volatility) {
        //
        //     {
        //         "period": 7,
        //         "value": "0.23854072",
        //         "time": "1690574400000"
        //     }
        //
        const result = [];
        for (let i = 0; i < volatility.length; i++) {
            const entry = volatility[i];
            const timestamp = this.safeInteger(entry, 'time');
            result.push({
                'info': volatility,
                'timestamp': timestamp,
                'datetime': this.iso8601(timestamp),
                'volatility': this.safeNumber(entry, 'value'),
            });
        }
        return result;
    }
    /**
     * @method
     * @name bybit#fetchGreeks
     * @description fetches an option contracts greeks, financial metrics used to measure the factors that affect the price of an options contract
     * @see https://bybit-exchange.github.io/docs/api-explorer/v5/market/tickers
     * @param {string} symbol unified symbol of the market to fetch greeks for
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {object} a [greeks structure]{@link https://docs.ccxt.com/#/?id=greeks-structure}
     */
    async fetchGreeks(symbol, params = {}) {
        await this.loadMarkets();
        const market = this.market(symbol);
        const request = {
            'symbol': market['id'],
            'category': 'option',
        };
        const response = await this.publicGetV5MarketTickers(this.extend(request, params));
        //
        //     {
        //         "retCode": 0,
        //         "retMsg": "SUCCESS",
        //         "result": {
        //             "category": "option",
        //             "list": [
        //                 {
        //                     "symbol": "BTC-26JAN24-39000-C",
        //                     "bid1Price": "3205",
        //                     "bid1Size": "7.1",
        //                     "bid1Iv": "0.5478",
        //                     "ask1Price": "3315",
        //                     "ask1Size": "1.98",
        //                     "ask1Iv": "0.5638",
        //                     "lastPrice": "3230",
        //                     "highPrice24h": "3255",
        //                     "lowPrice24h": "3200",
        //                     "markPrice": "3273.02263032",
        //                     "indexPrice": "36790.96",
        //                     "markIv": "0.5577",
        //                     "underlyingPrice": "37649.67254894",
        //                     "openInterest": "19.67",
        //                     "turnover24h": "170140.33875912",
        //                     "volume24h": "4.56",
        //                     "totalVolume": "22",
        //                     "totalTurnover": "789305",
        //                     "delta": "0.49640971",
        //                     "gamma": "0.00004131",
        //                     "vega": "69.08651675",
        //                     "theta": "-24.9443226",
        //                     "predictedDeliveryPrice": "0",
        //                     "change24h": "0.18532111"
        //                 }
        //             ]
        //         },
        //         "retExtInfo": {},
        //         "time": 1699584008326
        //     }
        //
        const timestamp = this.safeInteger(response, 'time');
        const result = this.safeDict(response, 'result', {});
        const data = this.safeList(result, 'list', []);
        const greeks = this.parseGreeks(data[0], market);
        return this.extend(greeks, {
            'timestamp': timestamp,
            'datetime': this.iso8601(timestamp),
        });
    }
    parseGreeks(greeks, market = undefined) {
        //
        //     {
        //         "symbol": "BTC-26JAN24-39000-C",
        //         "bid1Price": "3205",
        //         "bid1Size": "7.1",
        //         "bid1Iv": "0.5478",
        //         "ask1Price": "3315",
        //         "ask1Size": "1.98",
        //         "ask1Iv": "0.5638",
        //         "lastPrice": "3230",
        //         "highPrice24h": "3255",
        //         "lowPrice24h": "3200",
        //         "markPrice": "3273.02263032",
        //         "indexPrice": "36790.96",
        //         "markIv": "0.5577",
        //         "underlyingPrice": "37649.67254894",
        //         "openInterest": "19.67",
        //         "turnover24h": "170140.33875912",
        //         "volume24h": "4.56",
        //         "totalVolume": "22",
        //         "totalTurnover": "789305",
        //         "delta": "0.49640971",
        //         "gamma": "0.00004131",
        //         "vega": "69.08651675",
        //         "theta": "-24.9443226",
        //         "predictedDeliveryPrice": "0",
        //         "change24h": "0.18532111"
        //     }
        //
        const marketId = this.safeString(greeks, 'symbol');
        const symbol = this.safeSymbol(marketId, market);
        return {
            'symbol': symbol,
            'timestamp': undefined,
            'datetime': undefined,
            'delta': this.safeNumber(greeks, 'delta'),
            'gamma': this.safeNumber(greeks, 'gamma'),
            'theta': this.safeNumber(greeks, 'theta'),
            'vega': this.safeNumber(greeks, 'vega'),
            'rho': undefined,
            'bidSize': this.safeNumber(greeks, 'bid1Size'),
            'askSize': this.safeNumber(greeks, 'ask1Size'),
            'bidImpliedVolatility': this.safeNumber(greeks, 'bid1Iv'),
            'askImpliedVolatility': this.safeNumber(greeks, 'ask1Iv'),
            'markImpliedVolatility': this.safeNumber(greeks, 'markIv'),
            'bidPrice': this.safeNumber(greeks, 'bid1Price'),
            'askPrice': this.safeNumber(greeks, 'ask1Price'),
            'markPrice': this.safeNumber(greeks, 'markPrice'),
            'lastPrice': this.safeNumber(greeks, 'lastPrice'),
            'underlyingPrice': this.safeNumber(greeks, 'underlyingPrice'),
            'info': greeks,
        };
    }
    /**
     * @method
     * @name bybit#fetchMyLiquidations
     * @description retrieves the users liquidated positions
     * @see https://bybit-exchange.github.io/docs/api-explorer/v5/position/execution
     * @param {string} [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 {object} [params] exchange specific parameters for the exchange API endpoint
     * @param {string} [params.type] market type, ['swap', 'option', 'spot']
     * @param {string} [params.subType] market subType, ['linear', 'inverse']
     * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [available parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
     * @returns {object} an array of [liquidation structures]{@link https://docs.ccxt.com/#/?id=liquidation-structure}
     */
    async fetchMyLiquidations(symbol = undefined, since = undefined, limit = undefined, params = {}) {
        await this.loadMarkets();
        let paginate = false;
        [paginate, params] = this.handleOptionAndParams(params, 'fetchMyLiquidations', 'paginate');
        if (paginate) {
            return await this.fetchPaginatedCallCursor('fetchMyLiquidations', symbol, since, limit, params, 'nextPageCursor', 'cursor', undefined, 100);
        }
        let request = {
            'execType': 'BustTrade',
        };
        let market = undefined;
        if (symbol !== undefined) {
            market = this.market(symbol);
            request['symbol'] = market['id'];
        }
        let type = undefined;
        [type, params] = this.getBybitType('fetchMyLiquidations', market, params);
        request['category'] = type;
        if (limit !== undefined) {
            request['limit'] = limit;
        }
        if (since !== undefined) {
            request['startTime'] = since;
        }
        [request, params] = this.handleUntilOption('endTime', request, params);
        const response = await this.privateGetV5ExecutionList(this.extend(request, params));
        //
        //     {
        //         "retCode": 0,
        //         "retMsg": "OK",
        //         "result": {
        //             "nextPageCursor": "132766%3A2%2C132766%3A2",
        //             "category": "linear",
        //             "list": [
        //                 {
        //                     "symbol": "ETHPERP",
        //                     "orderType": "Market",
        //                     "underlyingPrice": "",
        //                     "orderLinkId": "",
        //                     "side": "Buy",
        //                     "indexPrice": "",
        //                     "orderId": "8c065341-7b52-4ca9-ac2c-37e31ac55c94",
        //                     "stopOrderType": "UNKNOWN",
        //                     "leavesQty": "0",
        //                     "execTime": "1672282722429",
        //                     "isMaker": false,
        //                     "execFee": "0.071409",
        //                     "feeRate": "0.0006",
        //                     "execId": "e0cbe81d-0f18-5866-9415-cf319b5dab3b",
        //                     "tradeIv": "",
        //                     "blockTradeId": "",
        //                     "markPrice": "1183.54",
        //                     "execPrice": "1190.15",
        //                     "markIv": "",
        //                     "orderQty": "0.1",
        //                     "orderPrice": "1236.9",
        //                     "execValue": "119.015",
        //                     "execType": "Trade",
        //                     "execQty": "0.1"
        //                 }
        //             ]
        //         },
        //         "retExtInfo": {},
        //         "time": 1672283754510
        //     }
        //
        const liquidations = this.addPaginationCursorToResult(response);
        return this.parseLiquidations(liquidations, market, since, limit);
    }
    parseLiquidation(liquidation, market = undefined) {
        //
        //     {
        //         "symbol": "ETHPERP",
        //         "orderType": "Market",
        //         "underlyingPrice": "",
        //         "orderLinkId": "",
        //         "side": "Buy",
        //         "indexPrice": "",
        //         "orderId": "8c065341-7b52-4ca9-ac2c-37e31ac55c94",
        //         "stopOrderType": "UNKNOWN",
        //         "leavesQty": "0",
        //         "execTime": "1672282722429",
        //         "isMaker": false,
        //         "execFee": "0.071409",
        //         "feeRate": "0.0006",
        //         "execId": "e0cbe81d-0f18-5866-9415-cf319b5dab3b",
        //         "tradeIv": "",
        //         "blockTradeId": "",
        //         "markPrice": "1183.54",
        //         "execPrice": "1190.15",
        //         "markIv": "",
        //         "orderQty": "0.1",
        //         "orderPrice": "1236.9",
        //         "execValue": "119.015",
        //         "execType": "Trade",
        //         "execQty": "0.1"
        //     }
        //
        const marketId = this.safeString(liquidation, 'symbol');
        const timestamp = this.safeInteger(liquidation, 'execTime');
        const contractsString = this.safeString(liquidation, 'execQty');
        const contractSizeString = this.safeString(market, 'contractSize');
        const priceString = this.safeString(liquidation, 'execPrice');
        const baseValueString = Precise["default"].stringMul(contractsString, contractSizeString);
        const quoteValueString = Precise["default"].stringMul(baseValueString, priceString);
        return this.safeLiquidation({
            'info': liquidation,
            'symbol': this.safeSymbol(marketId, market, undefined, 'contract'),
            'contracts': this.parseNumber(contractsString),
            'contractSize': this.parseNumber(contractSizeString),
            'price': this.parseNumber(priceString),
            'baseValue': this.parseNumber(baseValueString),
            'quoteValue': this.parseNumber(quoteValueString),
            'timestamp': timestamp,
            'datetime': this.iso8601(timestamp),
        });
    }
    async getLeverageTiersPaginated(symbol = undefined, params = {}) {
        await this.loadMarkets();
        let market = undefined;
        if (symbol !== undefined) {
            market = this.market(symbol);
        }
        let paginate = false;
        [paginate, params] = this.handleOptionAndParams(params, 'getLeverageTiersPaginated', 'paginate');
        if (paginate) {
            return await this.fetchPaginatedCallCursor('getLeverageTiersPaginated', symbol, undefined, undefined, params, 'nextPageCursor', 'cursor', undefined, 100);
        }
        let subType = undefined;
        [subType, params] = this.handleSubTypeAndParams('getLeverageTiersPaginated', market, params, 'linear');
        const request = {
            'category': subType,
        };
        const response = await this.publicGetV5MarketRiskLimit(this.extend(request, params));
        const result = this.addPaginationCursorToResult(response);
        const first = this.safeDict(result, 0);
        const total = result.length;
        const lastIndex = total - 1;
        const last = this.safeDict(result, lastIndex);
        const cursorValue = this.safeString(first, 'nextPageCursor');
        last['info'] = {
            'nextPageCursor': cursorValue,
        };
        result[lastIndex] = last;
        return result;
    }
    /**
     * @method
     * @name bybit#fetchLeverageTiers
     * @description retrieve information on the maximum leverage, for different trade sizes
     * @see https://bybit-exchange.github.io/docs/v5/market/risk-limit
     * @param {string[]} [symbols] a list of unified market symbols
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @param {string} [params.subType] market subType, ['linear', 'inverse'], default is 'linear'
     * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [available parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
     * @returns {object} a dictionary of [leverage tiers structures]{@link https://docs.ccxt.com/#/?id=leverage-tiers-structure}, indexed by market symbols
     */
    async fetchLeverageTiers(symbols = undefined, params = {}) {
        await this.loadMarkets();
        let market = undefined;
        let symbol = undefined;
        if (symbols !== undefined) {
            market = this.market(symbols[0]);
            if (market['spot']) {
                throw new errors.NotSupported(this.id + ' fetchLeverageTiers() is not supported for spot market');
            }
            symbol = market['symbol'];
        }
        const data = await this.getLeverageTiersPaginated(symbol, this.extend({ 'paginate': true, 'paginationCalls': 40 }, params));
        symbols = this.marketSymbols(symbols);
        return this.parseLeverageTiers(data, symbols, 'symbol');
    }
    parseLeverageTiers(response, symbols = undefined, marketIdKey = undefined) {
        //
        //  [
        //      {
        //          "id": 1,
        //          "symbol": "BTCUSD",
        //          "riskLimitValue": "150",
        //          "maintenanceMargin": "0.5",
        //          "initialMargin": "1",
        //          "isLowestRisk": 1,
        //          "maxLeverage": "100.00"
        //      }
        //  ]
        //
        const tiers = {};
        const marketIds = this.marketIds(symbols);
        const filteredResults = this.filterByArray(response, marketIdKey, marketIds, false);
        const grouped = this.groupBy(filteredResults, marketIdKey);
        const keys = Object.keys(grouped);
        for (let i = 0; i < keys.length; i++) {
            const marketId = keys[i];
            const entry = grouped[marketId];
            for (let j = 0; j < entry.length; j++) {
                const id = this.safeInteger(entry[j], 'id');
                entry[j]['id'] = id;
            }
            const market = this.safeMarket(marketId, undefined, undefined, 'contract');
            const symbol = market['symbol'];
            tiers[symbol] = this.parseMarketLeverageTiers(this.sortBy(entry, 'id'), market);
        }
        return tiers;
    }
    parseMarketLeverageTiers(info, market = undefined) {
        //
        //  [
        //      {
        //          "id": 1,
        //          "symbol": "BTCUSD",
        //          "riskLimitValue": "150",
        //          "maintenanceMargin": "0.5",
        //          "initialMargin": "1",
        //          "isLowestRisk": 1,
        //          "maxLeverage": "100.00"
        //      }
        //  ]
        //
        const tiers = [];
        for (let i = 0; i < info.length; i++) {
            const tier = info[i];
            const marketId = this.safeString(info, 'symbol');
            market = this.safeMarket(marketId);
            let minNotional = this.parseNumber('0');
            if (i !== 0) {
                minNotional = this.safeNumber(info[i - 1], 'riskLimitValue');
            }
            tiers.push({
                'tier': this.safeInteger(tier, 'id'),
                'symbol': this.safeSymbol(marketId, market),
                'currency': market['settle'],
                'minNotional': minNotional,
                'maxNotional': this.safeNumber(tier, 'riskLimitValue'),
                'maintenanceMarginRate': this.safeNumber(tier, 'maintenanceMargin'),
                'maxLeverage': this.safeNumber(tier, 'maxLeverage'),
                'info': tier,
            });
        }
        return tiers;
    }
    /**
     * @method
     * @name bybit#fetchFundingHistory
     * @description fetch the history of funding payments paid and received on this account
     * @see https://bybit-exchange.github.io/docs/api-explorer/v5/position/execution
     * @param {string} [symbol] unified market symbol
     * @param {int} [since] the earliest time in ms to fetch funding history for
     * @param {int} [limit] the maximum number of funding history structures to retrieve
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [available parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
     * @returns {object} a [funding history structure]{@link https://docs.ccxt.com/#/?id=funding-history-structure}
     */
    async fetchFundingHistory(symbol = undefined, since = undefined, limit = undefined, params = {}) {
        await this.loadMarkets();
        let paginate = false;
        [paginate, params] = this.handleOptionAndParams(params, 'fetchFundingHistory', 'paginate');
        if (paginate) {
            return await this.fetchPaginatedCallCursor('fetchFundingHistory', symbol, since, limit, params, 'nextPageCursor', 'cursor', undefined, 100);
        }
        let request = {
            'execType': 'Funding',
        };
        let market = undefined;
        if (symbol !== undefined) {
            market = this.market(symbol);
            request['symbol'] = market['id'];
        }
        let type = undefined;
        [type, params] = this.getBybitType('fetchFundingHistory', market, params);
        request['category'] = type;
        if (symbol !== undefined) {
            request['symbol'] = market['id'];
        }
        if (since !== undefined) {
            request['startTime'] = since;
        }
        if (limit !== undefined) {
            request['size'] = limit;
        }
        else {
            request['size'] = 100;
        }
        [request, params] = this.handleUntilOption('endTime', request, params);
        const response = await this.privateGetV5ExecutionList(this.extend(request, params));
        const fundings = this.addPaginationCursorToResult(response);
        return this.parseIncomes(fundings, market, since, limit);
    }
    parseIncome(income, market = undefined) {
        //
        // {
        //     "symbol": "XMRUSDT",
        //     "orderType": "UNKNOWN",
        //     "underlyingPrice": "",
        //     "orderLinkId": "",
        //     "orderId": "a11e5fe2-1dbf-4bab-a9b2-af80a14efc5d",
        //     "stopOrderType": "UNKNOWN",
        //     "execTime": "1710950400000",
        //     "feeCurrency": "",
        //     "createType": "",
        //     "feeRate": "-0.000761",
        //     "tradeIv": "",
        //     "blockTradeId": "",
        //     "markPrice": "136.79",
        //     "execPrice": "137.11",
        //     "markIv": "",
        //     "orderQty": "0",
        //     "orderPrice": "0",
        //     "execValue": "134.3678",
        //     "closedSize": "0",
        //     "execType": "Funding",
        //     "seq": "28097658790",
        //     "side": "Sell",
        //     "indexPrice": "",
        //     "leavesQty": "0",
        //     "isMaker": false,
        //     "execFee": "-0.10232512",
        //     "execId": "8d1ef156-4ec6-4445-9a6c-1c0c24dbd046",
        //     "marketUnit": "",
        //     "execQty": "0.98",
        //     "nextPageCursor": "5774437%3A0%2C5771289%3A0"
        // }
        //
        const marketId = this.safeString(income, 'symbol');
        market = this.safeMarket(marketId, market, undefined, 'contract');
        let code = 'USDT';
        if (market['inverse']) {
            code = market['quote'];
        }
        const timestamp = this.safeInteger(income, 'execTime');
        return {
            'info': income,
            'symbol': this.safeSymbol(marketId, market, '-', 'swap'),
            'code': code,
            'timestamp': timestamp,
            'datetime': this.iso8601(timestamp),
            'id': this.safeString(income, 'execId'),
            'amount': this.safeNumber(income, 'execQty'),
            'rate': this.safeNumber(income, 'feeRate'),
        };
    }
    /**
     * @method
     * @name bybit#fetchOption
     * @description fetches option data that is commonly found in an option chain
     * @see https://bybit-exchange.github.io/docs/v5/market/tickers
     * @param {string} symbol unified market symbol
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {object} an [option chain structure]{@link https://docs.ccxt.com/#/?id=option-chain-structure}
     */
    async fetchOption(symbol, params = {}) {
        await this.loadMarkets();
        const market = this.market(symbol);
        const request = {
            'category': 'option',
            'symbol': market['id'],
        };
        const response = await this.publicGetV5MarketTickers(this.extend(request, params));
        //
        //     {
        //         "retCode": 0,
        //         "retMsg": "SUCCESS",
        //         "result": {
        //             "category": "option",
        //             "list": [
        //                 {
        //                     "symbol": "BTC-27DEC24-55000-P",
        //                     "bid1Price": "0",
        //                     "bid1Size": "0",
        //                     "bid1Iv": "0",
        //                     "ask1Price": "0",
        //                     "ask1Size": "0",
        //                     "ask1Iv": "0",
        //                     "lastPrice": "10980",
        //                     "highPrice24h": "0",
        //                     "lowPrice24h": "0",
        //                     "markPrice": "11814.66756236",
        //                     "indexPrice": "63838.92",
        //                     "markIv": "0.8866",
        //                     "underlyingPrice": "71690.55303594",
        //                     "openInterest": "0.01",
        //                     "turnover24h": "0",
        //                     "volume24h": "0",
        //                     "totalVolume": "2",
        //                     "totalTurnover": "78719",
        //                     "delta": "-0.23284954",
        //                     "gamma": "0.0000055",
        //                     "vega": "191.70757975",
        //                     "theta": "-30.43617927",
        //                     "predictedDeliveryPrice": "0",
        //                     "change24h": "0"
        //                 }
        //             ]
        //         },
        //         "retExtInfo": {},
        //         "time": 1711162003672
        //     }
        //
        const result = this.safeDict(response, 'result', {});
        const resultList = this.safeList(result, 'list', []);
        const chain = this.safeDict(resultList, 0, {});
        return this.parseOption(chain, undefined, market);
    }
    /**
     * @method
     * @name bybit#fetchOptionChain
     * @description fetches data for an underlying asset that is commonly found in an option chain
     * @see https://bybit-exchange.github.io/docs/v5/market/tickers
     * @param {string} code base currency to fetch an option chain for
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {object} a list of [option chain structures]{@link https://docs.ccxt.com/#/?id=option-chain-structure}
     */
    async fetchOptionChain(code, params = {}) {
        await this.loadMarkets();
        const currency = this.currency(code);
        const request = {
            'category': 'option',
            'baseCoin': currency['id'],
        };
        const response = await this.publicGetV5MarketTickers(this.extend(request, params));
        //
        //     {
        //         "retCode": 0,
        //         "retMsg": "SUCCESS",
        //         "result": {
        //             "category": "option",
        //             "list": [
        //                 {
        //                     "symbol": "BTC-27DEC24-55000-P",
        //                     "bid1Price": "0",
        //                     "bid1Size": "0",
        //                     "bid1Iv": "0",
        //                     "ask1Price": "0",
        //                     "ask1Size": "0",
        //                     "ask1Iv": "0",
        //                     "lastPrice": "10980",
        //                     "highPrice24h": "0",
        //                     "lowPrice24h": "0",
        //                     "markPrice": "11814.66756236",
        //                     "indexPrice": "63838.92",
        //                     "markIv": "0.8866",
        //                     "underlyingPrice": "71690.55303594",
        //                     "openInterest": "0.01",
        //                     "turnover24h": "0",
        //                     "volume24h": "0",
        //                     "totalVolume": "2",
        //                     "totalTurnover": "78719",
        //                     "delta": "-0.23284954",
        //                     "gamma": "0.0000055",
        //                     "vega": "191.70757975",
        //                     "theta": "-30.43617927",
        //                     "predictedDeliveryPrice": "0",
        //                     "change24h": "0"
        //                 },
        //             ]
        //         },
        //         "retExtInfo": {},
        //         "time": 1711162003672
        //     }
        //
        const result = this.safeDict(response, 'result', {});
        const resultList = this.safeList(result, 'list', []);
        return this.parseOptionChain(resultList, undefined, 'symbol');
    }
    parseOption(chain, currency = undefined, market = undefined) {
        //
        //     {
        //         "symbol": "BTC-27DEC24-55000-P",
        //         "bid1Price": "0",
        //         "bid1Size": "0",
        //         "bid1Iv": "0",
        //         "ask1Price": "0",
        //         "ask1Size": "0",
        //         "ask1Iv": "0",
        //         "lastPrice": "10980",
        //         "highPrice24h": "0",
        //         "lowPrice24h": "0",
        //         "markPrice": "11814.66756236",
        //         "indexPrice": "63838.92",
        //         "markIv": "0.8866",
        //         "underlyingPrice": "71690.55303594",
        //         "openInterest": "0.01",
        //         "turnover24h": "0",
        //         "volume24h": "0",
        //         "totalVolume": "2",
        //         "totalTurnover": "78719",
        //         "delta": "-0.23284954",
        //         "gamma": "0.0000055",
        //         "vega": "191.70757975",
        //         "theta": "-30.43617927",
        //         "predictedDeliveryPrice": "0",
        //         "change24h": "0"
        //     }
        //
        const marketId = this.safeString(chain, 'symbol');
        market = this.safeMarket(marketId, market);
        return {
            'info': chain,
            'currency': undefined,
            'symbol': market['symbol'],
            'timestamp': undefined,
            'datetime': undefined,
            'impliedVolatility': this.safeNumber(chain, 'markIv'),
            'openInterest': this.safeNumber(chain, 'openInterest'),
            'bidPrice': this.safeNumber(chain, 'bid1Price'),
            'askPrice': this.safeNumber(chain, 'ask1Price'),
            'midPrice': undefined,
            'markPrice': this.safeNumber(chain, 'markPrice'),
            'lastPrice': this.safeNumber(chain, 'lastPrice'),
            'underlyingPrice': this.safeNumber(chain, 'underlyingPrice'),
            'change': this.safeNumber(chain, 'change24h'),
            'percentage': undefined,
            'baseVolume': this.safeNumber(chain, 'totalVolume'),
            'quoteVolume': undefined,
        };
    }
    /**
     * @method
     * @name bybit#fetchPositionsHistory
     * @description fetches historical positions
     * @see https://bybit-exchange.github.io/docs/v5/position/close-pnl
     * @param {string[]} symbols a list of unified market symbols
     * @param {int} [since] timestamp in ms of the earliest position to fetch, params["until"] - since <= 7 days
     * @param {int} [limit] the maximum amount of records to fetch, default=50, max=100
     * @param {object} params extra parameters specific to the exchange api endpoint
     * @param {int} [params.until] timestamp in ms of the latest position to fetch, params["until"] - since <= 7 days
     * @param {string} [params.subType] 'linear' or 'inverse'
     * @returns {object[]} a list of [position structures]{@link https://docs.ccxt.com/#/?id=position-structure}
     */
    async fetchPositionsHistory(symbols = undefined, since = undefined, limit = undefined, params = {}) {
        await this.loadMarkets();
        let market = undefined;
        let subType = undefined;
        let symbolsLength = 0;
        if (symbols !== undefined) {
            symbolsLength = symbols.length;
            if (symbolsLength > 0) {
                market = this.market(symbols[0]);
            }
        }
        const until = this.safeInteger(params, 'until');
        [subType, params] = this.handleSubTypeAndParams('fetchPositionsHistory', market, params, 'linear');
        params = this.omit(params, 'until');
        const request = {
            'category': subType,
        };
        if ((symbols !== undefined) && (symbolsLength === 1)) {
            request['symbol'] = market['id'];
        }
        if (since !== undefined) {
            request['startTime'] = since;
        }
        if (limit !== undefined) {
            request['limit'] = limit;
        }
        if (until !== undefined) {
            request['endTime'] = until;
        }
        const response = await this.privateGetV5PositionClosedPnl(this.extend(request, params));
        //
        //    {
        //        retCode: '0',
        //        retMsg: 'OK',
        //        result: {
        //            nextPageCursor: '071749f3-a9fa-427b-b5ca-27b2f52b81de%3A1712717265566520788%2C071749f3-a9fa-427b-b5ca-27b2f52b81de%3A1712717265566520788',
        //            category: 'linear',
        //            list: [
        //                {
        //                    symbol: 'XRPUSDT',
        //                    orderType: 'Market',
        //                    leverage: '10',
        //                    updatedTime: '1712717265572',
        //                    side: 'Sell',
        //                    orderId: '071749f3-a9fa-427b-b5ca-27b2f52b81de',
        //                    closedPnl: '-0.00049568',
        //                    avgEntryPrice: '0.6045',
        //                    qty: '3',
        //                    cumEntryValue: '1.8135',
        //                    createdTime: '1712717265566',
        //                    orderPrice: '0.5744',
        //                    closedSize: '3',
        //                    avgExitPrice: '0.605',
        //                    execType: 'Trade',
        //                    fillCount: '1',
        //                    cumExitValue: '1.815'
        //                }
        //            ]
        //        },
        //        retExtInfo: {},
        //        time: '1712717286073'
        //    }
        //
        const result = this.safeDict(response, 'result');
        const rawPositions = this.safeList(result, 'list');
        const positions = this.parsePositions(rawPositions, symbols, params);
        return this.filterBySinceLimit(positions, since, limit);
    }
    /**
     * @method
     * @name bybit#fetchConvertCurrencies
     * @description fetches all available currencies that can be converted
     * @see https://bybit-exchange.github.io/docs/v5/asset/convert/convert-coin-list
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @param {string} [params.accountType] eb_convert_uta, eb_convert_spot, eb_convert_funding, eb_convert_inverse, or eb_convert_contract
     * @returns {object} an associative dictionary of currencies
     */
    async fetchConvertCurrencies(params = {}) {
        await this.loadMarkets();
        let accountType = undefined;
        const [enableUnifiedMargin, enableUnifiedAccount] = await this.isUnifiedEnabled();
        const isUnifiedAccount = (enableUnifiedMargin || enableUnifiedAccount);
        const accountTypeDefault = isUnifiedAccount ? 'eb_convert_uta' : 'eb_convert_spot';
        [accountType, params] = this.handleOptionAndParams(params, 'fetchConvertCurrencies', 'accountType', accountTypeDefault);
        const request = {
            'accountType': accountType,
        };
        const response = await this.privateGetV5AssetExchangeQueryCoinList(this.extend(request, params));
        //
        //     {
        //         "retCode": 0,
        //         "retMsg": "ok",
        //         "result": {
        //             "coins": [
        //                 {
        //                     "coin": "MATIC",
        //                     "fullName": "MATIC",
        //                     "icon": "https://s1.bycsi.com/app/assets/token/0552ae79c535c3095fa18f7b377dd2e9.svg",
        //                     "iconNight": "https://t1.bycsi.com/app/assets/token/f59301aef2d6ac2165c4c4603e672fb4.svg",
        //                     "accuracyLength": 8,
        //                     "coinType": "crypto",
        //                     "balance": "0",
        //                     "uBalance": "0",
        //                     "timePeriod": 0,
        //                     "singleFromMinLimit": "1.1",
        //                     "singleFromMaxLimit": "20001",
        //                     "singleToMinLimit": "0",
        //                     "singleToMaxLimit": "0",
        //                     "dailyFromMinLimit": "0",
        //                     "dailyFromMaxLimit": "0",
        //                     "dailyToMinLimit": "0",
        //                     "dailyToMaxLimit": "0",
        //                     "disableFrom": false,
        //                     "disableTo": false
        //                 },
        //             ]
        //         },
        //         "retExtInfo": {},
        //         "time": 1727256416250
        //     }
        //
        const result = {};
        const data = this.safeDict(response, 'result', {});
        const coins = this.safeList(data, 'coins', []);
        for (let i = 0; i < coins.length; i++) {
            const entry = coins[i];
            const id = this.safeString(entry, 'coin');
            const disableFrom = this.safeBool(entry, 'disableFrom');
            const disableTo = this.safeBool(entry, 'disableTo');
            const inactive = (disableFrom || disableTo);
            const code = this.safeCurrencyCode(id);
            result[code] = {
                'info': entry,
                'id': id,
                'code': code,
                'networks': undefined,
                'type': this.safeString(entry, 'coinType'),
                'name': this.safeString(entry, 'fullName'),
                'active': !inactive,
                'deposit': undefined,
                'withdraw': this.safeNumber(entry, 'balance'),
                'fee': undefined,
                'precision': undefined,
                'limits': {
                    'amount': {
                        'min': this.safeNumber(entry, 'singleFromMinLimit'),
                        'max': this.safeNumber(entry, 'singleFromMaxLimit'),
                    },
                    'withdraw': {
                        'min': undefined,
                        'max': undefined,
                    },
                    'deposit': {
                        'min': undefined,
                        'max': undefined,
                    },
                },
                'created': undefined,
            };
        }
        return result;
    }
    /**
     * @method
     * @name bybit#fetchConvertQuote
     * @description fetch a quote for converting from one currency to another
     * @see https://bybit-exchange.github.io/docs/v5/asset/convert/apply-quote
     * @param {string} fromCode the currency that you want to sell and convert from
     * @param {string} toCode the currency that you want to buy and convert into
     * @param {float} [amount] how much you want to trade in units of the from currency
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @param {string} [params.accountType] eb_convert_uta, eb_convert_spot, eb_convert_funding, eb_convert_inverse, or eb_convert_contract
     * @returns {object} a [conversion structure]{@link https://docs.ccxt.com/#/?id=conversion-structure}
     */
    async fetchConvertQuote(fromCode, toCode, amount = undefined, params = {}) {
        await this.loadMarkets();
        let accountType = undefined;
        const [enableUnifiedMargin, enableUnifiedAccount] = await this.isUnifiedEnabled();
        const isUnifiedAccount = (enableUnifiedMargin || enableUnifiedAccount);
        const accountTypeDefault = isUnifiedAccount ? 'eb_convert_uta' : 'eb_convert_spot';
        [accountType, params] = this.handleOptionAndParams(params, 'fetchConvertQuote', 'accountType', accountTypeDefault);
        const request = {
            'fromCoin': fromCode,
            'toCoin': toCode,
            'requestAmount': this.numberToString(amount),
            'requestCoin': fromCode,
            'accountType': accountType,
        };
        const response = await this.privatePostV5AssetExchangeQuoteApply(this.extend(request, params));
        //
        //     {
        //         "retCode": 0,
        //         "retMsg": "ok",
        //         "result": {
        //             "quoteTxId": "1010020692439481682687668224",
        //             "exchangeRate": "0.000015330836780000",
        //             "fromCoin": "USDT",
        //             "fromCoinType": "crypto",
        //             "toCoin": "BTC",
        //             "toCoinType": "crypto",
        //             "fromAmount": "10",
        //             "toAmount": "0.000153308367800000",
        //             "expiredTime": "1727257413353",
        //             "requestId": ""
        //         },
        //         "retExtInfo": {},
        //         "time": 1727257398375
        //     }
        //
        const data = this.safeDict(response, 'result', {});
        const fromCurrencyId = this.safeString(data, 'fromCoin', fromCode);
        const fromCurrency = this.currency(fromCurrencyId);
        const toCurrencyId = this.safeString(data, 'toCoin', toCode);
        const toCurrency = this.currency(toCurrencyId);
        return this.parseConversion(data, fromCurrency, toCurrency);
    }
    /**
     * @method
     * @name bybit#createConvertTrade
     * @description convert from one currency to another
     * @see https://bybit-exchange.github.io/docs/v5/asset/convert/confirm-quote
     * @param {string} id the id of the trade that you want to make
     * @param {string} fromCode the currency that you want to sell and convert from
     * @param {string} toCode the currency that you want to buy and convert into
     * @param {float} amount how much you want to trade in units of the from currency
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {object} a [conversion structure]{@link https://docs.ccxt.com/#/?id=conversion-structure}
     */
    async createConvertTrade(id, fromCode, toCode, amount = undefined, params = {}) {
        await this.loadMarkets();
        const request = {
            'quoteTxId': id,
        };
        const response = await this.privatePostV5AssetExchangeConvertExecute(this.extend(request, params));
        //
        //     {
        //         "retCode": 0,
        //         "retMsg": "ok",
        //         "result": {
        //             "exchangeStatus": "processing",
        //             "quoteTxId": "1010020692439483803499737088"
        //         },
        //         "retExtInfo": {},
        //         "time": 1727257904969
        //     }
        //
        const data = this.safeDict(response, 'result', {});
        return this.parseConversion(data);
    }
    /**
     * @method
     * @name bybit#fetchConvertTrade
     * @description fetch the data for a conversion trade
     * @see https://bybit-exchange.github.io/docs/v5/asset/convert/get-convert-result
     * @param {string} id the id of the trade that you want to fetch
     * @param {string} [code] the unified currency code of the conversion trade
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @param {string} [params.accountType] eb_convert_uta, eb_convert_spot, eb_convert_funding, eb_convert_inverse, or eb_convert_contract
     * @returns {object} a [conversion structure]{@link https://docs.ccxt.com/#/?id=conversion-structure}
     */
    async fetchConvertTrade(id, code = undefined, params = {}) {
        await this.loadMarkets();
        let accountType = undefined;
        const [enableUnifiedMargin, enableUnifiedAccount] = await this.isUnifiedEnabled();
        const isUnifiedAccount = (enableUnifiedMargin || enableUnifiedAccount);
        const accountTypeDefault = isUnifiedAccount ? 'eb_convert_uta' : 'eb_convert_spot';
        [accountType, params] = this.handleOptionAndParams(params, 'fetchConvertQuote', 'accountType', accountTypeDefault);
        const request = {
            'quoteTxId': id,
            'accountType': accountType,
        };
        const response = await this.privateGetV5AssetExchangeConvertResultQuery(this.extend(request, params));
        //
        //     {
        //         "retCode": 0,
        //         "retMsg": "ok",
        //         "result": {
        //             "result": {
        //                 "accountType": "eb_convert_uta",
        //                 "exchangeTxId": "1010020692439483803499737088",
        //                 "userId": "100406395",
        //                 "fromCoin": "USDT",
        //                 "fromCoinType": "crypto",
        //                 "fromAmount": "10",
        //                 "toCoin": "BTC",
        //                 "toCoinType": "crypto",
        //                 "toAmount": "0.00015344889",
        //                 "exchangeStatus": "success",
        //                 "extInfo": {},
        //                 "convertRate": "0.000015344889",
        //                 "createdAt": "1727257904726"
        //             }
        //         },
        //         "retExtInfo": {},
        //         "time": 1727258257216
        //     }
        //
        const data = this.safeDict(response, 'result', {});
        const result = this.safeDict(data, 'result', {});
        const fromCurrencyId = this.safeString(result, 'fromCoin');
        const toCurrencyId = this.safeString(result, 'toCoin');
        let fromCurrency = undefined;
        let toCurrency = undefined;
        if (fromCurrencyId !== undefined) {
            fromCurrency = this.currency(fromCurrencyId);
        }
        if (toCurrencyId !== undefined) {
            toCurrency = this.currency(toCurrencyId);
        }
        return this.parseConversion(result, fromCurrency, toCurrency);
    }
    /**
     * @method
     * @name bybit#fetchConvertTradeHistory
     * @description fetch the users history of conversion trades
     * @see https://bybit-exchange.github.io/docs/v5/asset/convert/get-convert-history
     * @param {string} [code] the unified currency code
     * @param {int} [since] the earliest time in ms to fetch conversions for
     * @param {int} [limit] the maximum number of conversion structures to retrieve
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @param {string} [params.accountType] eb_convert_uta, eb_convert_spot, eb_convert_funding, eb_convert_inverse, or eb_convert_contract
     * @returns {object[]} a list of [conversion structures]{@link https://docs.ccxt.com/#/?id=conversion-structure}
     */
    async fetchConvertTradeHistory(code = undefined, since = undefined, limit = undefined, params = {}) {
        await this.loadMarkets();
        const request = {};
        if (limit !== undefined) {
            request['limit'] = limit;
        }
        const response = await this.privateGetV5AssetExchangeQueryConvertHistory(this.extend(request, params));
        //
        //     {
        //         "retCode": 0,
        //         "retMsg": "ok",
        //         "result": {
        //             "list": [
        //                 {
        //                     "accountType": "eb_convert_uta",
        //                     "exchangeTxId": "1010020692439483803499737088",
        //                     "userId": "100406395",
        //                     "fromCoin": "USDT",
        //                     "fromCoinType": "crypto",
        //                     "fromAmount": "10",
        //                     "toCoin": "BTC",
        //                     "toCoinType": "crypto",
        //                     "toAmount": "0.00015344889",
        //                     "exchangeStatus": "success",
        //                     "extInfo": {},
        //                     "convertRate": "0.000015344889",
        //                     "createdAt": "1727257904726"
        //                 }
        //             ]
        //         },
        //         "retExtInfo": {},
        //         "time": 1727258761874
        //     }
        //
        const data = this.safeDict(response, 'result', {});
        const dataList = this.safeList(data, 'list', []);
        return this.parseConversions(dataList, code, 'fromCoin', 'toCoin', since, limit);
    }
    parseConversion(conversion, fromCurrency = undefined, toCurrency = undefined) {
        //
        // fetchConvertQuote
        //
        //     {
        //         "quoteTxId": "1010020692439481682687668224",
        //         "exchangeRate": "0.000015330836780000",
        //         "fromCoin": "USDT",
        //         "fromCoinType": "crypto",
        //         "toCoin": "BTC",
        //         "toCoinType": "crypto",
        //         "fromAmount": "10",
        //         "toAmount": "0.000153308367800000",
        //         "expiredTime": "1727257413353",
        //         "requestId": ""
        //     }
        //
        // createConvertTrade
        //
        //     {
        //         "exchangeStatus": "processing",
        //         "quoteTxId": "1010020692439483803499737088"
        //     }
        //
        // fetchConvertTrade, fetchConvertTradeHistory
        //
        //     {
        //         "accountType": "eb_convert_uta",
        //         "exchangeTxId": "1010020692439483803499737088",
        //         "userId": "100406395",
        //         "fromCoin": "USDT",
        //         "fromCoinType": "crypto",
        //         "fromAmount": "10",
        //         "toCoin": "BTC",
        //         "toCoinType": "crypto",
        //         "toAmount": "0.00015344889",
        //         "exchangeStatus": "success",
        //         "extInfo": {},
        //         "convertRate": "0.000015344889",
        //         "createdAt": "1727257904726"
        //     }
        //
        const timestamp = this.safeInteger2(conversion, 'expiredTime', 'createdAt');
        const fromCoin = this.safeString(conversion, 'fromCoin');
        const fromCode = this.safeCurrencyCode(fromCoin, fromCurrency);
        const to = this.safeString(conversion, 'toCoin');
        const toCode = this.safeCurrencyCode(to, toCurrency);
        return {
            'info': conversion,
            'timestamp': timestamp,
            'datetime': this.iso8601(timestamp),
            'id': this.safeString2(conversion, 'quoteTxId', 'exchangeTxId'),
            'fromCurrency': fromCode,
            'fromAmount': this.safeNumber(conversion, 'fromAmount'),
            'toCurrency': toCode,
            'toAmount': this.safeNumber(conversion, 'toAmount'),
            'price': undefined,
            'fee': undefined,
        };
    }
    /**
     * @method
     * @name bybit#fetchLongShortRatioHistory
     * @description fetches the long short ratio history for a unified market symbol
     * @see https://bybit-exchange.github.io/docs/v5/market/long-short-ratio
     * @param {string} symbol unified symbol of the market to fetch the long short ratio for
     * @param {string} [timeframe] the period for the ratio, default is 24 hours
     * @param {int} [since] the earliest time in ms to fetch ratios for
     * @param {int} [limit] the maximum number of long short ratio structures to retrieve
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {object[]} an array of [long short ratio structures]{@link https://docs.ccxt.com/#/?id=long-short-ratio-structure}
     */
    async fetchLongShortRatioHistory(symbol = undefined, timeframe = undefined, since = undefined, limit = undefined, params = {}) {
        await this.loadMarkets();
        const market = this.market(symbol);
        let type = undefined;
        [type, params] = this.getBybitType('fetchLongShortRatioHistory', market, params);
        if (type === 'spot' || type === 'option') {
            throw new errors.NotSupported(this.id + ' fetchLongShortRatioHistory() only support linear and inverse markets');
        }
        if (timeframe === undefined) {
            timeframe = '1d';
        }
        const request = {
            'symbol': market['id'],
            'period': timeframe,
            'category': type,
        };
        if (limit !== undefined) {
            request['limit'] = limit;
        }
        const response = await this.publicGetV5MarketAccountRatio(this.extend(request, params));
        //
        //     {
        //         "retCode": 0,
        //         "retMsg": "OK",
        //         "result": {
        //             "list": [
        //                 {
        //                     "symbol": "BTCUSDT",
        //                     "buyRatio": "0.5707",
        //                     "sellRatio": "0.4293",
        //                     "timestamp": "1729123200000"
        //                 },
        //             ]
        //         },
        //         "retExtInfo": {},
        //         "time": 1729147842516
        //     }
        //
        const result = this.safeDict(response, 'result', {});
        const data = this.safeList(result, 'list', []);
        return this.parseLongShortRatioHistory(data, market);
    }
    parseLongShortRatio(info, market = undefined) {
        //
        //     {
        //         "symbol": "BTCUSDT",
        //         "buyRatio": "0.5707",
        //         "sellRatio": "0.4293",
        //         "timestamp": "1729123200000"
        //     }
        //
        const marketId = this.safeString(info, 'symbol');
        const timestamp = this.safeIntegerOmitZero(info, 'timestamp');
        const longString = this.safeString(info, 'buyRatio');
        const shortString = this.safeString(info, 'sellRatio');
        return {
            'info': info,
            'symbol': this.safeSymbol(marketId, market, undefined, 'contract'),
            'timestamp': timestamp,
            'datetime': this.iso8601(timestamp),
            'timeframe': undefined,
            'longShortRatio': this.parseToNumeric(Precise["default"].stringDiv(longString, shortString)),
        };
    }
    sign(path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
        let url = this.implodeHostname(this.urls['api'][api]) + '/' + path;
        if (api === 'public') {
            if (Object.keys(params).length) {
                url += '?' + this.rawencode(params);
            }
        }
        else if (api === 'private') {
            this.checkRequiredCredentials();
            const isOpenapi = url.indexOf('openapi') >= 0;
            const isV3UnifiedMargin = url.indexOf('unified/v3') >= 0;
            const isV3Contract = url.indexOf('contract/v3') >= 0;
            const isV5UnifiedAccount = url.indexOf('v5') >= 0;
            const timestamp = this.nonce().toString();
            if (isOpenapi) {
                if (Object.keys(params).length) {
                    body = this.json(params);
                }
                else {
                    // this fix for PHP is required otherwise it generates
                    // '[]' on empty arrays even when forced to use objects
                    body = '{}';
                }
                const payload = timestamp + this.apiKey + body;
                const signature = this.hmac(this.encode(payload), this.encode(this.secret), sha256.sha256, 'hex');
                headers = {
                    'Content-Type': 'application/json',
                    'X-BAPI-API-KEY': this.apiKey,
                    'X-BAPI-TIMESTAMP': timestamp,
                    'X-BAPI-SIGN': signature,
                };
            }
            else if (isV3UnifiedMargin || isV3Contract || isV5UnifiedAccount) {
                headers = {
                    'Content-Type': 'application/json',
                    'X-BAPI-API-KEY': this.apiKey,
                    'X-BAPI-TIMESTAMP': timestamp,
                    'X-BAPI-RECV-WINDOW': this.options['recvWindow'].toString(),
                };
                if (isV3UnifiedMargin || isV3Contract) {
                    headers['X-BAPI-SIGN-TYPE'] = '2';
                }
                const query = this.extend({}, params);
                const queryEncoded = this.rawencode(query);
                const auth_base = timestamp.toString() + this.apiKey + this.options['recvWindow'].toString();
                let authFull = undefined;
                if (method === 'POST') {
                    body = this.json(query);
                    authFull = auth_base + body;
                }
                else {
                    authFull = auth_base + queryEncoded;
                    url += '?' + this.rawencode(query);
                }
                let signature = undefined;
                if (this.secret.indexOf('PRIVATE KEY') > -1) {
                    signature = rsa.rsa(authFull, this.secret, sha256.sha256);
                }
                else {
                    signature = this.hmac(this.encode(authFull), this.encode(this.secret), sha256.sha256);
                }
                headers['X-BAPI-SIGN'] = signature;
            }
            else {
                const query = this.extend(params, {
                    'api_key': this.apiKey,
                    'recv_window': this.options['recvWindow'],
                    'timestamp': timestamp,
                });
                const sortedQuery = this.keysort(query);
                const auth = this.rawencode(sortedQuery);
                let signature = undefined;
                if (this.secret.indexOf('PRIVATE KEY') > -1) {
                    signature = rsa.rsa(auth, this.secret, sha256.sha256);
                }
                else {
                    signature = this.hmac(this.encode(auth), this.encode(this.secret), sha256.sha256);
                }
                if (method === 'POST') {
                    const isSpot = url.indexOf('spot') >= 0;
                    const extendedQuery = this.extend(query, {
                        'sign': signature,
                    });
                    if (isSpot) {
                        body = this.urlencode(extendedQuery);
                        headers = {
                            'Content-Type': 'application/x-www-form-urlencoded',
                        };
                    }
                    else {
                        body = this.json(extendedQuery);
                        headers = {
                            'Content-Type': 'application/json',
                        };
                    }
                }
                else {
                    url += '?' + this.rawencode(sortedQuery);
                    url += '&sign=' + signature;
                }
            }
        }
        if (method === 'POST') {
            const brokerId = this.safeString(this.options, 'brokerId');
            if (brokerId !== undefined) {
                headers['Referer'] = brokerId;
            }
        }
        return { 'url': url, 'method': method, 'body': body, 'headers': headers };
    }
    handleErrors(httpCode, reason, url, method, headers, body, response, requestHeaders, requestBody) {
        if (!response) {
            return undefined; // fallback to default error handler
        }
        //
        //     {
        //         "ret_code": 10001,
        //         "ret_msg": "ReadMapCB: expect { or n, but found \u0000, error " +
        //         "found in #0 byte of ...||..., bigger context " +
        //         "...||...",
        //         "ext_code": '',
        //         "ext_info": '',
        //         "result": null,
        //         "time_now": "1583934106.590436"
        //     }
        //
        //     {
        //         "retCode":10001,
        //         "retMsg":"symbol params err",
        //         "result":{"symbol":"","bid":"","bidIv":"","bidSize":"","ask":"","askIv":"","askSize":"","lastPrice":"","openInterest":"","indexPrice":"","markPrice":"","markPriceIv":"","change24h":"","high24h":"","low24h":"","volume24h":"","turnover24h":"","totalVolume":"","totalTurnover":"","fundingRate":"","predictedFundingRate":"","nextFundingTime":"","countdownHour":"0","predictedDeliveryPrice":"","underlyingPrice":"","delta":"","gamma":"","vega":"","theta":""}
        //     }
        //
        const errorCode = this.safeString2(response, 'ret_code', 'retCode');
        if (errorCode !== '0') {
            if (errorCode === '30084') {
                // not an error
                // https://github.com/ccxt/ccxt/issues/11268
                // https://github.com/ccxt/ccxt/pull/11624
                // POST https://api.bybit.com/v2/private/position/switch-isolated 200 OK
                // {"ret_code":30084,"ret_msg":"Isolated not modified","ext_code":"","ext_info":"","result":null,"time_now":"1642005219.937988","rate_limit_status":73,"rate_limit_reset_ms":1642005219894,"rate_limit":75}
                return undefined;
            }
            let feedback = undefined;
            if (errorCode === '10005' && url.indexOf('order') < 0) {
                feedback = this.id + ' private api uses /user/v3/private/query-api to check if you have a unified account. The API key of user id must own one of permissions: "Account Transfer", "Subaccount Transfer", "Withdrawal" ' + body;
            }
            else {
                feedback = this.id + ' ' + body;
            }
            if (body.indexOf('Withdraw address chain or destination tag are not equal') > -1) {
                feedback = feedback + '; You might also need to ensure the address is whitelisted';
            }
            this.throwBroadlyMatchedException(this.exceptions['broad'], body, feedback);
            this.throwExactlyMatchedException(this.exceptions['exact'], errorCode, feedback);
            throw new errors.ExchangeError(feedback); // unknown message
        }
        return undefined;
    }
}

module.exports = bybit;