UNPKG

astro-perp-ccxt-dev

Version:

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

8,242 lines 380 kB
'use strict';

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

// ----------------------------------------------------------------------------
/**
 * @class gate
 * @augments Exchange
 */
class gate extends gate$1 {
    describe() {
        return this.deepExtend(super.describe(), {
            'id': 'gate',
            'name': 'Gate.io',
            'countries': ['KR'],
            'rateLimit': 50,
            'version': 'v4',
            'certified': true,
            'pro': true,
            'urls': {
                'logo': 'https://github.com/user-attachments/assets/64f988c5-07b6-4652-b5c1-679a6bf67c85',
                'doc': 'https://www.gate.io/docs/developers/apiv4/en/',
                'www': 'https://gate.io/',
                'api': {
                    'public': {
                        'wallet': 'https://api.gateio.ws/api/v4',
                        'futures': 'https://api.gateio.ws/api/v4',
                        'margin': 'https://api.gateio.ws/api/v4',
                        'delivery': 'https://api.gateio.ws/api/v4',
                        'spot': 'https://api.gateio.ws/api/v4',
                        'options': 'https://api.gateio.ws/api/v4',
                        'sub_accounts': 'https://api.gateio.ws/api/v4',
                        'earn': 'https://api.gateio.ws/api/v4',
                    },
                    'private': {
                        'withdrawals': 'https://api.gateio.ws/api/v4',
                        'wallet': 'https://api.gateio.ws/api/v4',
                        'futures': 'https://api.gateio.ws/api/v4',
                        'margin': 'https://api.gateio.ws/api/v4',
                        'delivery': 'https://api.gateio.ws/api/v4',
                        'spot': 'https://api.gateio.ws/api/v4',
                        'options': 'https://api.gateio.ws/api/v4',
                        'subAccounts': 'https://api.gateio.ws/api/v4',
                        'unified': 'https://api.gateio.ws/api/v4',
                        'rebate': 'https://api.gateio.ws/api/v4',
                        'earn': 'https://api.gateio.ws/api/v4',
                        'account': 'https://api.gateio.ws/api/v4',
                        'loan': 'https://api.gateio.ws/api/v4',
                    },
                },
                'test': {
                    'public': {
                        'futures': 'https://fx-api-testnet.gateio.ws/api/v4',
                        'delivery': 'https://fx-api-testnet.gateio.ws/api/v4',
                        'options': 'https://fx-api-testnet.gateio.ws/api/v4',
                    },
                    'private': {
                        'futures': 'https://fx-api-testnet.gateio.ws/api/v4',
                        'delivery': 'https://fx-api-testnet.gateio.ws/api/v4',
                        'options': 'https://fx-api-testnet.gateio.ws/api/v4',
                    },
                },
                'referral': {
                    'url': 'https://www.gate.io/signup/2436035',
                    'discount': 0.2,
                },
            },
            'has': {
                'CORS': undefined,
                'spot': true,
                'margin': true,
                'swap': true,
                'future': true,
                'option': true,
                'addMargin': true,
                'borrowCrossMargin': true,
                'borrowIsolatedMargin': true,
                'cancelAllOrders': true,
                'cancelOrder': true,
                'cancelOrders': true,
                'cancelOrdersForSymbols': true,
                'createMarketBuyOrderWithCost': true,
                'createMarketOrder': true,
                'createMarketOrderWithCost': false,
                'createMarketSellOrderWithCost': false,
                'createOrder': true,
                'createOrders': true,
                'createPostOnlyOrder': true,
                'createReduceOnlyOrder': true,
                'createStopLimitOrder': true,
                'createStopLossOrder': true,
                'createStopMarketOrder': false,
                'createStopOrder': true,
                'createTakeProfitOrder': true,
                'createTriggerOrder': true,
                'editOrder': true,
                'fetchBalance': true,
                'fetchBorrowInterest': true,
                'fetchBorrowRateHistories': false,
                'fetchBorrowRateHistory': false,
                'fetchClosedOrders': true,
                'fetchCrossBorrowRate': false,
                'fetchCrossBorrowRates': false,
                'fetchCurrencies': true,
                'fetchDepositAddress': true,
                'fetchDepositAddresses': false,
                'fetchDepositAddressesByNetwork': true,
                'fetchDeposits': true,
                'fetchDepositWithdrawFee': 'emulated',
                'fetchDepositWithdrawFees': true,
                'fetchFundingHistory': true,
                'fetchFundingRate': true,
                'fetchFundingRateHistory': true,
                'fetchFundingRates': true,
                'fetchGreeks': true,
                'fetchIndexOHLCV': true,
                'fetchIsolatedBorrowRate': false,
                'fetchIsolatedBorrowRates': false,
                'fetchLedger': true,
                'fetchLeverage': true,
                'fetchLeverages': true,
                'fetchLeverageTiers': true,
                'fetchLiquidations': true,
                'fetchMarginAdjustmentHistory': false,
                'fetchMarginMode': false,
                'fetchMarketLeverageTiers': true,
                'fetchMarkets': true,
                'fetchMarkOHLCV': true,
                'fetchMyLiquidations': true,
                'fetchMySettlementHistory': true,
                'fetchMyTrades': true,
                'fetchNetworkDepositAddress': true,
                'fetchOHLCV': true,
                'fetchOpenInterest': false,
                'fetchOpenInterestHistory': true,
                'fetchOpenOrders': true,
                'fetchOption': true,
                'fetchOptionChain': true,
                'fetchOrder': true,
                'fetchOrderBook': true,
                'fetchPosition': true,
                'fetchPositionHistory': 'emulated',
                'fetchPositionMode': false,
                'fetchPositions': true,
                'fetchPositionsHistory': true,
                'fetchPremiumIndexOHLCV': false,
                'fetchSettlementHistory': true,
                'fetchTicker': true,
                'fetchTickers': true,
                'fetchTime': true,
                'fetchTrades': true,
                'fetchTradingFee': true,
                'fetchTradingFees': true,
                'fetchTransactionFees': true,
                'fetchUnderlyingAssets': true,
                'fetchVolatilityHistory': false,
                'fetchWithdrawals': true,
                'reduceMargin': true,
                'repayCrossMargin': true,
                'repayIsolatedMargin': true,
                'sandbox': true,
                'setLeverage': true,
                'setMarginMode': false,
                'setPositionMode': true,
                'signIn': false,
                'transfer': true,
                'withdraw': true,
            },
            'api': {
                'public': {
                    // All public endpoints 200r/10s per endpoint
                    'wallet': {
                        'get': {
                            'currency_chains': 1,
                        },
                    },
                    'spot': {
                        'get': {
                            'currencies': 1,
                            'currencies/{currency}': 1,
                            'currency_pairs': 1,
                            'currency_pairs/{currency_pair}': 1,
                            'tickers': 1,
                            'order_book': 1,
                            'trades': 1,
                            'candlesticks': 1,
                            'time': 1,
                        },
                    },
                    'margin': {
                        'get': {
                            'currency_pairs': 1,
                            'currency_pairs/{currency_pair}': 1,
                            'funding_book': 1,
                            'cross/currencies': 1,
                            'cross/currencies/{currency}': 1,
                            'uni/currency_pairs': 1,
                            'uni/currency_pairs/{currency_pair}': 1,
                        },
                    },
                    'flash_swap': {
                        'get': {
                            'currencies': 1,
                        },
                    },
                    'futures': {
                        'get': {
                            '{settle}/contracts': 1,
                            '{settle}/contracts/{contract}': 1,
                            '{settle}/order_book': 1,
                            '{settle}/trades': 1,
                            '{settle}/candlesticks': 1,
                            '{settle}/premium_index': 1,
                            '{settle}/tickers': 1,
                            '{settle}/funding_rate': 1,
                            '{settle}/insurance': 1,
                            '{settle}/contract_stats': 1,
                            '{settle}/index_constituents/{index}': 1,
                            '{settle}/liq_orders': 1,
                            '{settle}/risk_limit_tiers': 1,
                        },
                    },
                    'delivery': {
                        'get': {
                            '{settle}/contracts': 1,
                            '{settle}/contracts/{contract}': 1,
                            '{settle}/order_book': 1,
                            '{settle}/trades': 1,
                            '{settle}/candlesticks': 1,
                            '{settle}/tickers': 1,
                            '{settle}/insurance': 1,
                        },
                    },
                    'options': {
                        'get': {
                            'underlyings': 1,
                            'expirations': 1,
                            'contracts': 1,
                            'contracts/{contract}': 1,
                            'settlements': 1,
                            'settlements/{contract}': 1,
                            'order_book': 1,
                            'tickers': 1,
                            'underlying/tickers/{underlying}': 1,
                            'candlesticks': 1,
                            'underlying/candlesticks': 1,
                            'trades': 1,
                        },
                    },
                    'earn': {
                        'get': {
                            'uni/currencies': 1,
                            'uni/currencies/{currency}': 1,
                        },
                    },
                },
                'private': {
                    // private endpoints default is 150r/10s per endpoint
                    'withdrawals': {
                        'post': {
                            'withdrawals': 20,
                            'push': 1,
                        },
                        'delete': {
                            'withdrawals/{withdrawal_id}': 1,
                        },
                    },
                    'wallet': {
                        'get': {
                            'deposit_address': 1,
                            'withdrawals': 1,
                            'deposits': 1,
                            'sub_account_transfers': 1,
                            'order_status': 1,
                            'withdraw_status': 1,
                            'sub_account_balances': 2.5,
                            'sub_account_margin_balances': 2.5,
                            'sub_account_futures_balances': 2.5,
                            'sub_account_cross_margin_balances': 2.5,
                            'saved_address': 1,
                            'fee': 1,
                            'total_balance': 2.5,
                            'small_balance': 1,
                            'small_balance_history': 1,
                            'push': 1,
                        },
                        'post': {
                            'transfers': 2.5,
                            'sub_account_transfers': 2.5,
                            'sub_account_to_sub_account': 2.5,
                            'small_balance': 1,
                        },
                    },
                    'subAccounts': {
                        'get': {
                            'sub_accounts': 2.5,
                            'sub_accounts/{user_id}': 2.5,
                            'sub_accounts/{user_id}/keys': 2.5,
                            'sub_accounts/{user_id}/keys/{key}': 2.5,
                        },
                        'post': {
                            'sub_accounts': 2.5,
                            'sub_accounts/{user_id}/keys': 2.5,
                            'sub_accounts/{user_id}/lock': 2.5,
                            'sub_accounts/{user_id}/unlock': 2.5,
                        },
                        'put': {
                            'sub_accounts/{user_id}/keys/{key}': 2.5,
                        },
                        'delete': {
                            'sub_accounts/{user_id}/keys/{key}': 2.5,
                        },
                    },
                    'unified': {
                        'get': {
                            'accounts': 20 / 15,
                            'account_mode': 20 / 15,
                            'borrowable': 20 / 15,
                            'transferable': 20 / 15,
                            'loans': 20 / 15,
                            'loan_records': 20 / 15,
                            'interest_records': 20 / 15,
                            'estimate_rate': 20 / 15,
                            'currency_discount_tiers': 20 / 15,
                            'risk_units': 20 / 15,
                            'unified_mode': 20 / 15,
                            'loan_margin_tiers': 20 / 15,
                            'leverage/user_currency_config': 20 / 15,
                            'leverage/user_currency_setting': 20 / 15,
                        },
                        'post': {
                            'account_mode': 20 / 15,
                            'loans': 200 / 15,
                            'portfolio_calculator': 20 / 15,
                            'leverage/user_currency_setting': 20 / 15,
                        },
                        'put': {
                            'unified_mode': 20 / 15,
                        },
                    },
                    'spot': {
                        // default is 200r/10s
                        'get': {
                            'fee': 1,
                            'batch_fee': 1,
                            'accounts': 1,
                            'account_book': 1,
                            'open_orders': 1,
                            'orders': 1,
                            'orders/{order_id}': 1,
                            'my_trades': 1,
                            'price_orders': 1,
                            'price_orders/{order_id}': 1,
                        },
                        'post': {
                            'batch_orders': 0.4,
                            'cross_liquidate_orders': 1,
                            'orders': 0.4,
                            'cancel_batch_orders': 20 / 75,
                            'countdown_cancel_all': 20 / 75,
                            'amend_batch_orders': 0.4,
                            'price_orders': 0.4,
                        },
                        'delete': {
                            'orders': 20 / 75,
                            'orders/{order_id}': 20 / 75,
                            'price_orders': 20 / 75,
                            'price_orders/{order_id}': 20 / 75,
                        },
                        'patch': {
                            'orders/{order_id}': 0.4,
                        },
                    },
                    'margin': {
                        'get': {
                            'accounts': 20 / 15,
                            'account_book': 20 / 15,
                            'funding_accounts': 20 / 15,
                            'auto_repay': 20 / 15,
                            'transferable': 20 / 15,
                            'loans': 20 / 15,
                            'loans/{loan_id}': 20 / 15,
                            'loans/{loan_id}/repayment': 20 / 15,
                            'loan_records': 20 / 15,
                            'loan_records/{loan_record_id}': 20 / 15,
                            'borrowable': 20 / 15,
                            'cross/accounts': 20 / 15,
                            'cross/account_book': 20 / 15,
                            'cross/loans': 20 / 15,
                            'cross/loans/{loan_id}': 20 / 15,
                            'cross/repayments': 20 / 15,
                            'cross/interest_records': 20 / 15,
                            'cross/transferable': 20 / 15,
                            'cross/estimate_rate': 20 / 15,
                            'cross/borrowable': 20 / 15,
                            'uni/estimate_rate': 20 / 15,
                            'uni/loans': 20 / 15,
                            'uni/loan_records': 20 / 15,
                            'uni/interest_records': 20 / 15,
                            'uni/borrowable': 20 / 15,
                        },
                        'post': {
                            'auto_repay': 20 / 15,
                            'loans': 20 / 15,
                            'merged_loans': 20 / 15,
                            'loans/{loan_id}/repayment': 20 / 15,
                            'cross/loans': 20 / 15,
                            'cross/repayments': 20 / 15,
                            'uni/loans': 20 / 15,
                        },
                        'patch': {
                            'loans/{loan_id}': 20 / 15,
                            'loan_records/{loan_record_id}': 20 / 15,
                        },
                        'delete': {
                            'loans/{loan_id}': 20 / 15,
                        },
                    },
                    'flash_swap': {
                        'get': {
                            'currencies': 1,
                            'currency_pairs': 1,
                            'orders': 1,
                            'orders/{order_id}': 1,
                        },
                        'post': {
                            'orders': 1,
                            'orders/preview': 1,
                        },
                    },
                    'futures': {
                        'get': {
                            '{settle}/accounts': 1,
                            '{settle}/account_book': 1,
                            '{settle}/positions': 1,
                            '{settle}/positions/{contract}': 1,
                            '{settle}/dual_comp/positions/{contract}': 1,
                            '{settle}/orders': 1,
                            '{settle}/orders_timerange': 1,
                            '{settle}/orders/{order_id}': 1,
                            '{settle}/my_trades': 1,
                            '{settle}/my_trades_timerange': 1,
                            '{settle}/position_close': 1,
                            '{settle}/liquidates': 1,
                            '{settle}/auto_deleverages': 1,
                            '{settle}/fee': 1,
                            '{settle}/risk_limit_tiers': 1,
                            '{settle}/price_orders': 1,
                            '{settle}/price_orders/{order_id}': 1,
                        },
                        'post': {
                            '{settle}/positions/{contract}/margin': 1,
                            '{settle}/positions/{contract}/leverage': 1,
                            '{settle}/positions/{contract}/risk_limit': 1,
                            '{settle}/dual_mode': 1,
                            '{settle}/dual_comp/positions/{contract}/margin': 1,
                            '{settle}/dual_comp/positions/{contract}/leverage': 1,
                            '{settle}/dual_comp/positions/{contract}/risk_limit': 1,
                            '{settle}/orders': 0.4,
                            '{settle}/batch_orders': 0.4,
                            '{settle}/countdown_cancel_all': 0.4,
                            '{settle}/batch_cancel_orders': 0.4,
                            '{settle}/price_orders': 0.4,
                        },
                        'put': {
                            '{settle}/orders/{order_id}': 1,
                        },
                        'delete': {
                            '{settle}/orders': 20 / 75,
                            '{settle}/orders/{order_id}': 20 / 75,
                            '{settle}/price_orders': 20 / 75,
                            '{settle}/price_orders/{order_id}': 20 / 75,
                        },
                    },
                    'delivery': {
                        'get': {
                            '{settle}/accounts': 20 / 15,
                            '{settle}/account_book': 20 / 15,
                            '{settle}/positions': 20 / 15,
                            '{settle}/positions/{contract}': 20 / 15,
                            '{settle}/orders': 20 / 15,
                            '{settle}/orders/{order_id}': 20 / 15,
                            '{settle}/my_trades': 20 / 15,
                            '{settle}/position_close': 20 / 15,
                            '{settle}/liquidates': 20 / 15,
                            '{settle}/settlements': 20 / 15,
                            '{settle}/price_orders': 20 / 15,
                            '{settle}/price_orders/{order_id}': 20 / 15,
                        },
                        'post': {
                            '{settle}/positions/{contract}/margin': 20 / 15,
                            '{settle}/positions/{contract}/leverage': 20 / 15,
                            '{settle}/positions/{contract}/risk_limit': 20 / 15,
                            '{settle}/orders': 20 / 15,
                            '{settle}/price_orders': 20 / 15,
                        },
                        'delete': {
                            '{settle}/orders': 20 / 15,
                            '{settle}/orders/{order_id}': 20 / 15,
                            '{settle}/price_orders': 20 / 15,
                            '{settle}/price_orders/{order_id}': 20 / 15,
                        },
                    },
                    'options': {
                        'get': {
                            'my_settlements': 20 / 15,
                            'accounts': 20 / 15,
                            'account_book': 20 / 15,
                            'positions': 20 / 15,
                            'positions/{contract}': 20 / 15,
                            'position_close': 20 / 15,
                            'orders': 20 / 15,
                            'orders/{order_id}': 20 / 15,
                            'my_trades': 20 / 15,
                            'mmp': 20 / 15,
                        },
                        'post': {
                            'orders': 20 / 15,
                            'countdown_cancel_all': 20 / 15,
                            'mmp': 20 / 15,
                            'mmp/reset': 20 / 15,
                        },
                        'delete': {
                            'orders': 20 / 15,
                            'orders/{order_id}': 20 / 15,
                        },
                    },
                    'earn': {
                        'get': {
                            'uni/currencies': 20 / 15,
                            'uni/currencies/{currency}': 20 / 15,
                            'uni/lends': 20 / 15,
                            'uni/lend_records': 20 / 15,
                            'uni/interests/{currency}': 20 / 15,
                            'uni/interest_records': 20 / 15,
                            'uni/interest_status/{currency}': 20 / 15,
                        },
                        'post': {
                            'uni/lends': 20 / 15,
                        },
                        'put': {
                            'uni/interest_reinvest': 20 / 15,
                        },
                        'patch': {
                            'uni/lends': 20 / 15,
                        },
                    },
                    'loan': {
                        'get': {
                            'collateral/orders': 20 / 15,
                            'collateral/orders/{order_id}': 20 / 15,
                            'collateral/repay_records': 20 / 15,
                            'collateral/collaterals': 20 / 15,
                            'collateral/total_amount': 20 / 15,
                            'collateral/ltv': 20 / 15,
                            'collateral/currencies': 20 / 15,
                            'multi_collateral/orders': 20 / 15,
                            'multi_collateral/orders/{order_id}': 20 / 15,
                            'multi_collateral/repay': 20 / 15,
                            'multi_collateral/mortgage': 20 / 15,
                            'multi_collateral/currency_quota': 20 / 15,
                            'multi_collateral/currencies': 20 / 15,
                            'multi_collateral/ltv': 20 / 15,
                            'multi_collateral/fixed_rate': 20 / 15,
                            'multi_collateral/current_rate': 20 / 15,
                        },
                        'post': {
                            'collateral/orders': 20 / 15,
                            'collateral/repay': 20 / 15,
                            'collateral/collaterals': 20 / 15,
                            'multi_collateral/orders': 20 / 15,
                            'multi_collateral/repay': 20 / 15,
                            'multi_collateral/mortgage': 20 / 15,
                        },
                    },
                    'account': {
                        'get': {
                            'detail': 20 / 15,
                            'rate_limit': 20 / 15,
                            'stp_groups': 20 / 15,
                            'stp_groups/{stp_id}/users': 20 / 15,
                            'stp_groups/debit_fee': 20 / 15,
                        },
                        'post': {
                            'stp_groups': 20 / 15,
                            'stp_groups/{stp_id}/users': 20 / 15,
                        },
                        'delete': {
                            'stp_groups/{stp_id}/users': 20 / 15,
                        },
                    },
                    'rebate': {
                        'get': {
                            'agency/transaction_history': 20 / 15,
                            'agency/commission_history': 20 / 15,
                        },
                    },
                },
            },
            'timeframes': {
                '10s': '10s',
                '1m': '1m',
                '5m': '5m',
                '15m': '15m',
                '30m': '30m',
                '1h': '1h',
                '2h': '2h',
                '4h': '4h',
                '8h': '8h',
                '1d': '1d',
                '7d': '7d',
                '1w': '7d',
            },
            // copied from gatev2
            'commonCurrencies': {
                'ORT': 'XREATORS',
                'ASS': 'ASSF',
                '88MPH': 'MPH',
                'AXIS': 'AXISDEFI',
                'BIFI': 'BITCOINFILE',
                'BOX': 'DEFIBOX',
                'BYN': 'BEYONDFI',
                'EGG': 'GOOSEFINANCE',
                'GTC': 'GAMECOM',
                'GTC_HT': 'GAMECOM_HT',
                'GTC_BSC': 'GAMECOM_BSC',
                'HIT': 'HITCHAIN',
                'MM': 'MILLION',
                'MPH': 'MORPHER',
                'POINT': 'GATEPOINT',
                'RAI': 'RAIREFLEXINDEX',
                'RED': 'RedLang',
                'SBTC': 'SUPERBITCOIN',
                'TNC': 'TRINITYNETWORKCREDIT',
                'VAI': 'VAIOT',
                'TRAC': 'TRACO', // conflict with OriginTrail (TRAC)
            },
            'requiredCredentials': {
                'apiKey': true,
                'secret': true,
            },
            'headers': {
                'X-Gate-Channel-Id': 'ccxt',
            },
            'options': {
                'timeDifference': 0,
                'adjustForTimeDifference': false,
                'sandboxMode': false,
                'unifiedAccount': undefined,
                'createOrder': {
                    'expiration': 86400, // for conditional orders
                },
                'createMarketBuyOrderRequiresPrice': true,
                'networks': {
                    'BTC': 'BTC',
                    'BRC20': 'BTCBRC',
                    'ETH': 'ETH',
                    'ERC20': 'ETH',
                    'TRX': 'TRX',
                    'TRC20': 'TRX',
                    'HECO': 'HT',
                    'HRC20': 'HT',
                    'BSC': 'BSC',
                    'BEP20': 'BSC',
                    'SOL': 'SOL',
                    'POLYGON': 'POL',
                    'MATIC': 'POL',
                    'OP': 'OPETH',
                    'OPTIMISM': 'OPETH',
                    'ADA': 'ADA',
                    'AVAXC': 'AVAX_C',
                    'NEAR': 'NEAR',
                    'ARBONE': 'ARBEVM',
                    'BASE': 'BASEEVM',
                    'SUI': 'SUI',
                    'CRONOS': 'CRO',
                    'CRO': 'CRO',
                    'APT': 'APT',
                    'SCROLL': 'SCROLLETH',
                    'TAIKO': 'TAIKOETH',
                    'HYPE': 'HYPE',
                    'ALGO': 'ALGO',
                    // KAVA: ['KAVA', 'KAVAEVM']
                    // SEI: ['SEI', 'SEIEVM']
                    'LINEA': 'LINEAETH',
                    'BLAST': 'BLASTETH',
                    'XLM': 'XLM',
                    'RSK': 'RBTC',
                    'TON': 'TON',
                    'MNT': 'MNT',
                    // 'RUNE': 'BTCRUNES', probably, cant verify atm
                    'CELO': 'CELO',
                    'HBAR': 'HBAR',
                    // 'FTM': SONIC REBRAND, todo
                    'ZKSERA': 'ZKSERA',
                    'KLAY': 'KLAY',
                    'EOS': 'EOS',
                    'ACA': 'ACA',
                    // TLOS: ['TLOS', 'TLOSEVM']
                    // ASTR: ['ASTR', 'ASTREVM']
                    // CFX: ['CFX', 'CFXEVM']
                    'XTZ': 'XTZ',
                    'EGLD': 'EGLD',
                    'GLMR': 'GLMR',
                    'AURORA': 'AURORAEVM',
                    // others
                    'KON': 'KONET',
                    'GATECHAIN': 'GTEVM',
                    'KUSAMA': 'KSMSM',
                    'OKC': 'OKT',
                    'POLKADOT': 'DOTSM',
                    'LUNA': 'LUNC',
                },
                'networksById': {
                    'OPETH': 'OP',
                    'ETH': 'ERC20',
                    'ERC20': 'ERC20',
                    'TRX': 'TRC20',
                    'TRC20': 'TRC20',
                    'HT': 'HRC20',
                    'HECO': 'HRC20',
                    'BSC': 'BEP20',
                    'BEP20': 'BEP20',
                    'POLYGON': 'MATIC',
                    'POL': 'MATIC',
                },
                'timeInForce': {
                    'GTC': 'gtc',
                    'IOC': 'ioc',
                    'PO': 'poc',
                    'POC': 'poc',
                    'FOK': 'fok',
                },
                'accountsByType': {
                    'funding': 'spot',
                    'spot': 'spot',
                    'margin': 'margin',
                    'cross_margin': 'cross_margin',
                    'cross': 'cross_margin',
                    'isolated': 'margin',
                    'swap': 'futures',
                    'future': 'delivery',
                    'futures': 'futures',
                    'delivery': 'delivery',
                    'option': 'options',
                    'options': 'options',
                },
                'swap': {
                    'fetchMarkets': {
                        'settlementCurrencies': ['usdt', 'btc'],
                    },
                },
                'future': {
                    'fetchMarkets': {
                        'settlementCurrencies': ['usdt'],
                    },
                },
            },
            'features': {
                'default': {
                    'sandbox': true,
                    'createOrder': {
                        'marginMode': true,
                        'triggerPrice': true,
                        'triggerDirection': true,
                        'triggerPriceType': undefined,
                        'stopLossPrice': true,
                        'takeProfitPrice': true,
                        'attachedStopLossTakeProfit': undefined,
                        'timeInForce': {
                            'IOC': true,
                            'FOK': true,
                            'PO': true,
                            'GTD': false,
                        },
                        'hedged': false,
                        'trailing': false,
                        'iceberg': true,
                        'selfTradePrevention': true,
                        'leverage': false,
                        'marketBuyByCost': true,
                        'marketBuyRequiresPrice': true,
                    },
                    'createOrders': {
                        'max': 40, // NOTE! max 10 per symbol
                    },
                    'fetchMyTrades': {
                        'marginMode': true,
                        'limit': 1000,
                        'daysBack': undefined,
                        'untilDays': 30,
                        'symbolRequired': false,
                    },
                    'fetchOrder': {
                        'marginMode': false,
                        'trigger': true,
                        'trailing': false,
                        'symbolRequired': true,
                    },
                    'fetchOpenOrders': {
                        'marginMode': true,
                        'trigger': true,
                        'trailing': false,
                        'limit': 100,
                        'symbolRequired': false,
                    },
                    'fetchOrders': undefined,
                    'fetchClosedOrders': {
                        'marginMode': true,
                        'trigger': true,
                        'trailing': false,
                        'limit': 100,
                        'untilDays': 30,
                        'daysBack': undefined,
                        'daysBackCanceled': undefined,
                        'symbolRequired': false,
                    },
                    'fetchOHLCV': {
                        'limit': 1000,
                    },
                },
                'spot': {
                    'extends': 'default',
                },
                'forDerivatives': {
                    'extends': 'spot',
                    'createOrder': {
                        'marginMode': false,
                        'triggerPriceType': {
                            'last': true,
                            'mark': true,
                            'index': true,
                        },
                    },
                    'createOrders': {
                        'max': 10,
                    },
                    'fetchMyTrades': {
                        'marginMode': false,
                        'untilDays': undefined,
                    },
                    'fetchOpenOrders': {
                        'marginMode': false,
                    },
                    'fetchClosedOrders': {
                        'marginMode': false,
                        'untilDays': undefined,
                        'limit': 1000,
                    },
                    'fetchOHLCV': {
                        'limit': 1999,
                    },
                },
                'swap': {
                    'linear': {
                        'extends': 'forDerivatives',
                    },
                    'inverse': {
                        'extends': 'forDerivatives',
                    },
                },
                'future': {
                    'linear': {
                        'extends': 'forDerivatives',
                    },
                    'inverse': {
                        'extends': 'forDerivatives',
                    },
                },
            },
            'precisionMode': number.TICK_SIZE,
            'fees': {
                'trading': {
                    'tierBased': true,
                    'feeSide': 'get',
                    'percentage': true,
                    'maker': this.parseNumber('0.002'),
                    'taker': this.parseNumber('0.002'),
                    'tiers': {
                        // volume is in BTC
                        'maker': [
                            [this.parseNumber('0'), this.parseNumber('0.002')],
                            [this.parseNumber('1.5'), this.parseNumber('0.00185')],
                            [this.parseNumber('3'), this.parseNumber('0.00175')],
                            [this.parseNumber('6'), this.parseNumber('0.00165')],
                            [this.parseNumber('12.5'), this.parseNumber('0.00155')],
                            [this.parseNumber('25'), this.parseNumber('0.00145')],
                            [this.parseNumber('75'), this.parseNumber('0.00135')],
                            [this.parseNumber('200'), this.parseNumber('0.00125')],
                            [this.parseNumber('500'), this.parseNumber('0.00115')],
                            [this.parseNumber('1250'), this.parseNumber('0.00105')],
                            [this.parseNumber('2500'), this.parseNumber('0.00095')],
                            [this.parseNumber('3000'), this.parseNumber('0.00085')],
                            [this.parseNumber('6000'), this.parseNumber('0.00075')],
                            [this.parseNumber('11000'), this.parseNumber('0.00065')],
                            [this.parseNumber('20000'), this.parseNumber('0.00055')],
                            [this.parseNumber('40000'), this.parseNumber('0.00055')],
                            [this.parseNumber('75000'), this.parseNumber('0.00055')],
                        ],
                        'taker': [
                            [this.parseNumber('0'), this.parseNumber('0.002')],
                            [this.parseNumber('1.5'), this.parseNumber('0.00195')],
                            [this.parseNumber('3'), this.parseNumber('0.00185')],
                            [this.parseNumber('6'), this.parseNumber('0.00175')],
                            [this.parseNumber('12.5'), this.parseNumber('0.00165')],
                            [this.parseNumber('25'), this.parseNumber('0.00155')],
                            [this.parseNumber('75'), this.parseNumber('0.00145')],
                            [this.parseNumber('200'), this.parseNumber('0.00135')],
                            [this.parseNumber('500'), this.parseNumber('0.00125')],
                            [this.parseNumber('1250'), this.parseNumber('0.00115')],
                            [this.parseNumber('2500'), this.parseNumber('0.00105')],
                            [this.parseNumber('3000'), this.parseNumber('0.00095')],
                            [this.parseNumber('6000'), this.parseNumber('0.00085')],
                            [this.parseNumber('11000'), this.parseNumber('0.00075')],
                            [this.parseNumber('20000'), this.parseNumber('0.00065')],
                            [this.parseNumber('40000'), this.parseNumber('0.00065')],
                            [this.parseNumber('75000'), this.parseNumber('0.00065')],
                        ],
                    },
                },
                'swap': {
                    'tierBased': true,
                    'feeSide': 'base',
                    'percentage': true,
                    'maker': this.parseNumber('0.0'),
                    'taker': this.parseNumber('0.0005'),
                    'tiers': {
                        'maker': [
                            [this.parseNumber('0'), this.parseNumber('0.0000')],
                            [this.parseNumber('1.5'), this.parseNumber('-0.00005')],
                            [this.parseNumber('3'), this.parseNumber('-0.00005')],
                            [this.parseNumber('6'), this.parseNumber('-0.00005')],
                            [this.parseNumber('12.5'), this.parseNumber('-0.00005')],
                            [this.parseNumber('25'), this.parseNumber('-0.00005')],
                            [this.parseNumber('75'), this.parseNumber('-0.00005')],
                            [this.parseNumber('200'), this.parseNumber('-0.00005')],
                            [this.parseNumber('500'), this.parseNumber('-0.00005')],
                            [this.parseNumber('1250'), this.parseNumber('-0.00005')],
                            [this.parseNumber('2500'), this.parseNumber('-0.00005')],
                            [this.parseNumber('3000'), this.parseNumber('-0.00008')],
                            [this.parseNumber('6000'), this.parseNumber('-0.01000')],
                            [this.parseNumber('11000'), this.parseNumber('-0.01002')],
                            [this.parseNumber('20000'), this.parseNumber('-0.01005')],
                            [this.parseNumber('40000'), this.parseNumber('-0.02000')],
                            [this.parseNumber('75000'), this.parseNumber('-0.02005')],
                        ],
                        'taker': [
                            [this.parseNumber('0'), this.parseNumber('0.00050')],
                            [this.parseNumber('1.5'), this.parseNumber('0.00048')],
                            [this.parseNumber('3'), this.parseNumber('0.00046')],
                            [this.parseNumber('6'), this.parseNumber('0.00044')],
                            [this.parseNumber('12.5'), this.parseNumber('0.00042')],
                            [this.parseNumber('25'), this.parseNumber('0.00040')],
                            [this.parseNumber('75'), this.parseNumber('0.00038')],
                            [this.parseNumber('200'), this.parseNumber('0.00036')],
                            [this.parseNumber('500'), this.parseNumber('0.00034')],
                            [this.parseNumber('1250'), this.parseNumber('0.00032')],
                            [this.parseNumber('2500'), this.parseNumber('0.00030')],
                            [this.parseNumber('3000'), this.parseNumber('0.00030')],
                            [this.parseNumber('6000'), this.parseNumber('0.00030')],
                            [this.parseNumber('11000'), this.parseNumber('0.00030')],
                            [this.parseNumber('20000'), this.parseNumber('0.00030')],
                            [this.parseNumber('40000'), this.parseNumber('0.00030')],
                            [this.parseNumber('75000'), this.parseNumber('0.00030')],
                        ],
                    },
                },
            },
            // https://www.gate.io/docs/developers/apiv4/en/#label-list
            'exceptions': {
                'exact': {
                    'INVALID_PARAM_VALUE': errors.BadRequest,
                    'INVALID_PROTOCOL': errors.BadRequest,
                    'INVALID_ARGUMENT': errors.BadRequest,
                    'INVALID_REQUEST_BODY': errors.BadRequest,
                    'MISSING_REQUIRED_PARAM': errors.ArgumentsRequired,
                    'BAD_REQUEST': errors.BadRequest,
                    'INVALID_CONTENT_TYPE': errors.BadRequest,
                    'NOT_ACCEPTABLE': errors.BadRequest,
                    'METHOD_NOT_ALLOWED': errors.BadRequest,
                    'NOT_FOUND': errors.ExchangeError,
                    'AUTHENTICATION_FAILED': errors.AuthenticationError,
                    'INVALID_CREDENTIALS': errors.AuthenticationError,
                    'INVALID_KEY': errors.AuthenticationError,
                    'IP_FORBIDDEN': errors.AuthenticationError,
                    'READ_ONLY': errors.PermissionDenied,
                    'INVALID_SIGNATURE': errors.AuthenticationError,
                    'MISSING_REQUIRED_HEADER': errors.AuthenticationError,
                    'REQUEST_EXPIRED': errors.AuthenticationError,
                    'ACCOUNT_LOCKED': errors.AccountSuspended,
                    'FORBIDDEN': errors.PermissionDenied,
                    'SUB_ACCOUNT_NOT_FOUND': errors.ExchangeError,
                    'SUB_ACCOUNT_LOCKED': errors.AccountSuspended,
                    'MARGIN_BALANCE_EXCEPTION': errors.ExchangeError,
                    'MARGIN_TRANSFER_FAILED': errors.ExchangeError,
                    'TOO_MUCH_FUTURES_AVAILABLE': errors.ExchangeError,
                    'FUTURES_BALANCE_NOT_ENOUGH': errors.InsufficientFunds,
                    'ACCOUNT_EXCEPTION': errors.ExchangeError,
                    'SUB_ACCOUNT_TRANSFER_FAILED': errors.ExchangeError,
                    'ADDRESS_NOT_USED': errors.ExchangeError,
                    'TOO_FAST': errors.RateLimitExceeded,
                    'WITHDRAWAL_OVER_LIMIT': errors.ExchangeError,
                    'API_WITHDRAW_DISABLED': errors.ExchangeNotAvailable,
                    'INVALID_WITHDRAW_ID': errors.ExchangeError,
                    'INVALID_WITHDRAW_CANCEL_STATUS': errors.ExchangeError,
                    'INVALID_PRECISION': errors.InvalidOrder,
                    'INVALID_CURRENCY': errors.BadSymbol,
                    'INVALID_CURRENCY_PAIR': errors.BadSymbol,
                    'POC_FILL_IMMEDIATELY': errors.OrderImmediatelyFillable,
                    'ORDER_NOT_FOUND': errors.OrderNotFound,
                    'CLIENT_ID_NOT_FOUND': errors.OrderNotFound,
                    'ORDER_CLOSED': errors.InvalidOrder,
                    'ORDER_CANCELLED': errors.InvalidOrder,
                    'QUANTITY_NOT_ENOUGH': errors.InvalidOrder,
                    'BALANCE_NOT_ENOUGH': errors.InsufficientFunds,
                    'MARGIN_NOT_SUPPORTED': errors.InvalidOrder,
                    'MARGIN_BALANCE_NOT_ENOUGH': errors.InsufficientFunds,
                    'AMOUNT_TOO_LITTLE': errors.InvalidOrder,
                    'AMOUNT_TOO_MUCH': errors.InvalidOrder,
                    'REPEATED_CREATION': errors.InvalidOrder,
                    'LOAN_NOT_FOUND': errors.OrderNotFound,
                    'LOAN_RECORD_NOT_FOUND': errors.OrderNotFound,
                    'NO_MATCHED_LOAN': errors.ExchangeError,
                    'NOT_MERGEABLE': errors.ExchangeError,
                    'NO_CHANGE': errors.ExchangeError,
                    'REPAY_TOO_MUCH': errors.ExchangeError,
                    'TOO_MANY_CURRENCY_PAIRS': errors.InvalidOrder,
                    'TOO_MANY_ORDERS': errors.InvalidOrder,
                    'TOO_MANY_REQUESTS': errors.RateLimitExceeded,
                    'MIXED_ACCOUNT_TYPE': errors.InvalidOrder,
                    'AUTO_BORROW_TOO_MUCH': errors.ExchangeError,
                    'TRADE_RESTRICTED': errors.InsufficientFunds,
                    'USER_NOT_FOUND': errors.AccountNotEnabled,
                    'CONTRACT_NO_COUNTER': errors.ExchangeError,
                    'CONTRACT_NOT_FOUND': errors.BadSymbol,
                    'RISK_LIMIT_EXCEEDED': errors.ExchangeError,
                    'INSUFFICIENT_AVAILABLE': errors.InsufficientFunds,
                    'LIQUIDATE_IMMEDIATELY': errors.InvalidOrder,
                    'LEVERAGE_TOO_HIGH': errors.InvalidOrder,
                    'LEVERAGE_TOO_LOW': errors.InvalidOrder,
                    'ORDER_NOT_OWNED': errors.ExchangeError,
                    'ORDER_FINISHED': errors.ExchangeError,
                    'POSITION_CROSS_MARGIN': errors.ExchangeError,
                    'POSITION_IN_LIQUIDATION': errors.ExchangeError,
                    'POSITION_IN_CLOSE': errors.ExchangeError,
                    'POSITION_EMPTY': errors.InvalidOrder,
                    'REMOVE_TOO_MUCH': errors.ExchangeError,
                    'RISK_LIMIT_NOT_MULTIPLE': errors.ExchangeError,
                    'RISK_LIMIT_TOO_HIGH': errors.ExchangeError,
                    'RISK_LIMIT_TOO_lOW': errors.ExchangeError,
                    'PRICE_TOO_DEVIATED': errors.InvalidOrder,
                    'SIZE_TOO_LARGE': errors.InvalidOrder,
                    'SIZE_TOO_SMALL': errors.InvalidOrder,
                    'PRICE_OVER_LIQUIDATION': errors.InvalidOrder,
                    'PRICE_OVER_BANKRUPT': errors.InvalidOrder,
                    'ORDER_POC_IMMEDIATE': errors.OrderImmediatelyFillable,
                    'INCREASE_POSITION': errors.InvalidOrder,
                    'CONTRACT_IN_DELISTING': errors.ExchangeError,
                    'INTERNAL': errors.ExchangeNotAvailable,
                    'SERVER_ERROR': errors.ExchangeNotAvailable,
                    'TOO_BUSY': errors.ExchangeNotAvailable,
                    'CROSS_ACCOUNT_NOT_FOUND': errors.ExchangeError,
                    'RISK_LIMIT_TOO_LOW': errors.BadRequest,
                    'AUTO_TRIGGER_PRICE_LESS_LAST': errors.InvalidOrder,
                    'AUTO_TRIGGER_PRICE_GREATE_LAST': errors.InvalidOrder,
                    'POSITION_HOLDING': errors.BadRequest,
                    'USER_LOAN_EXCEEDED': errors.BadRequest, // {"label":"USER_LOAN_EXCEEDED","message":"Max loan amount per user would be exceeded"}
                },
                'broad': {},
            },
        });
    }
    setSandboxMode(enable) {
        super.setSandboxMode(enable);
        this.options['sandboxMode'] = enable;
    }
    /**
     * @method
     * @name gate#loadUnifiedStatus
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @description returns unifiedAccount so the user can check if the unified account is enabled
     * @see https://www.gate.io/docs/developers/apiv4/#get-account-detail
     * @returns {boolean} true or false if the enabled unified account is enabled or not and sets the unifiedAccount option if it is undefined
     */
    async loadUnifiedStatus(params = {}) {
        const unifiedAccount = this.safeBool(this.options, 'unifiedAccount');
        if (unifiedAccount === undefined) {
            try {
                //
                //     {
                //         "user_id": 10406147,
                //         "ip_whitelist": [],
                //         "currency_pairs": [],
                //         "key": {
                //             "mode": 1
                //         },
                //         "tier": 0,
                //         "tier_expire_time": "0001-01-01T00:00:00Z",
                //         "copy_trading_role": 0
                //     }
                //
                const response = await this.privateAccountGetDetail(params);
                const result = this.safeDict(response, 'key', {});
                this.options['unifiedAccount'] = this.safeInteger(result, 'mode') === 2;
            }
            catch (e) {
                // if the request fails, the unifiedAccount is disabled
                this.options['unifiedAccount'] = false;
            }
        }
        return this.options['unifiedAccount'];
    }
    async upgradeUnifiedTradeAccount(params = {}) {
        return await this.privateUnifiedPutUnifiedMode(params);
    }
    /**
     * @method
     * @name gate#fetchTime
     * @description fetches the current integer timestamp in milliseconds from the exchange server
     * @see https://www.gate.io/docs/developers/apiv4/en/#get-server-current-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.publicSpotGetTime(params);
        //
        //     {
        //         "server_time": 1731447921098
        //     }
        //
        return this.safeInteger(response, 'server_time');
    }
    createExpiredOptionMarket(symbol) {
        // support expired option contracts
        const quote = 'USDT';
        const settle = quote;
        const optionParts = symbol.split('-');
        const symbolBase = symbol.split('/');
        const marketIdBase = symbol.split('_');
        let base = undefined;
        let expiry = this.safeString(optionParts, 1);
        if (symbol.indexOf('/') > -1) {
            base = this.safeString(symbolBase, 0);
        }
        else {
            base = this.safeString(marketIdBase, 0);
            expiry = expiry.slice(2, 8); // convert 20230728 to 230728
        }
        const strike = this.safeString(optionParts, 2);
        const optionType = this.safeString(optionParts, 3);
        const datetime = this.convertExpireDate(expiry);
        const timestamp = this.parse8601(datetime);
        return {
            'id': base + '_' + quote + '-' + '20' + 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': this.parseNumber('1'),
                'price': undefined,
            },
            '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);
    }
    /**
     * @method
     * @name gate#fetchMarkets
     * @description retrieves data on all markets for gate
     * @see https://www.gate.io/docs/developers/apiv4/en/#list-all-currency-pairs-supported                                     // spot
     * @see https://www.gate.io/docs/developers/apiv4/en/#list-all-supported-currency-pairs-supported-in-margin-trading         // margin
     * @see https://www.gate.io/docs/developers/apiv4/en/#list-all-futures-contracts                                            // swap
     * @see https://www.gate.io/docs/developers/apiv4/en/#list-all-futures-contracts-2                                          // future
     * @see https://www.gate.io/docs/developers/apiv4/en/#list-all-the-contracts-with-specified-underlying-and-expiration-time  // option
     * @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();
        }
        if (this.checkRequiredCredentials(false)) {
            await this.loadUnifiedStatus();
        }
        const sandboxMode = this.safeBool(this.options, 'sandboxMode', false);
        let rawPromises = [
            this.fetchContractMarkets(params),
            this.fetchOptionMarkets(params),
        ];
        if (!sandboxMode) {
            // gate doesn't have a sandbox for spot markets
            const mainnetOnly = [this.fetchSpotMarkets(params)];
            rawPromises = this.arrayConcat(rawPromises, mainnetOnly);
        }
        const promises = await Promise.all(rawPromises);
        const spotMarkets = this.safeValue(promises, 0, []);
        const contractMarkets = this.safeValue(promises, 1, []);
        const optionMarkets = this.safeValue(promises, 2, []);
        const markets = this.arrayConcat(spotMarkets, contractMarkets);
        return this.arrayConcat(markets, optionMarkets);
    }
    async fetchSpotMarkets(params = {}) {
        const marginPromise = this.publicMarginGetCurrencyPairs(params);
        const spotMarketsPromise = this.publicSpotGetCurrencyPairs(params);
        const [marginResponse, spotMarketsResponse] = await Promise.all([marginPromise, spotMarketsPromise]);
        const marginMarkets = this.indexBy(marginResponse, 'id');
        //
        //  Spot
        //
        //     [
        //         {
        //             "id": "QTUM_ETH",
        //             "base": "QTUM",
        //             "base_name": "Quantum",
        //             "quote": "ETH",
        //             "quote_name": "Ethereum",
        //             "fee": "0.2",
        //             "min_base_amount": "0.01",
        //             "min_quote_amount": "0.001",
        //             "max_quote_amount": "50000",
        //             "amount_precision": 3,
        //             "precision": 6,
        //             "trade_status": "tradable",
        //             "sell_start": 1607313600,
        //             "buy_start": 1700492400,
        //             "type": "normal",
        //             "trade_url": "https://www.gate.io/trade/QTUM_ETH",
        //         }
        //
        //  Margin
        //
        //     [
        //         {
        //             "id": "ETH_USDT",
        //             "base": "ETH",
        //             "quote": "USDT",
        //             "leverage": 3,
        //             "min_base_amount": "0.01",
        //             "min_quote_amount": "100",
        //             "max_quote_amount": "1000000"
        //         }
        //     ]
        //
        const result = [];
        for (let i = 0; i < spotMarketsResponse.length; i++) {
            const spotMarket = spotMarketsResponse[i];
            const id = this.safeString(spotMarket, 'id');
            const marginMarket = this.safeValue(marginMarkets, id);
            const market = this.deepExtend(marginMarket, spotMarket);
            const [baseId, quoteId] = id.split('_');
            const base = this.safeCurrencyCode(baseId);
            const quote = this.safeCurrencyCode(quoteId);
            const takerPercent = this.safeString(market, 'fee');
            const makerPercent = this.safeString(market, 'maker_fee_rate', takerPercent);
            const amountPrecision = this.parseNumber(this.parsePrecision(this.safeString(market, 'amount_precision')));
            const tradeStatus = this.safeString(market, 'trade_status');
            const leverage = this.safeNumber(market, 'leverage');
            const margin = leverage !== undefined;
            const buyStart = this.safeIntegerProduct(spotMarket, 'buy_start', 1000); // buy_start is the trading start time, while sell_start is offline orders start time
            const createdTs = (buyStart !== 0) ? buyStart : undefined;
            result.push({
                'id': id,
                'symbol': base + '/' + quote,
                'base': base,
                'quote': quote,
                'settle': undefined,
                'baseId': baseId,
                'quoteId': quoteId,
                'settleId': undefined,
                'type': 'spot',
                'spot': true,
                'margin': margin,
                'swap': false,
                'future': false,
                'option': false,
                'active': (tradeStatus === 'tradable'),
                'contract': false,
                'linear': undefined,
                'inverse': undefined,
                // Fee is in %, so divide by 100
                'taker': this.parseNumber(Precise["default"].stringDiv(takerPercent, '100')),
                'maker': this.parseNumber(Precise["default"].stringDiv(makerPercent, '100')),
                'contractSize': undefined,
                'expiry': undefined,
                'expiryDatetime': undefined,
                'strike': undefined,
                'optionType': undefined,
                'precision': {
                    'amount': amountPrecision,
                    'price': this.parseNumber(this.parsePrecision(this.safeString(market, 'precision'))),
                },
                'limits': {
                    'leverage': {
                        'min': this.parseNumber('1'),
                        'max': this.safeNumber(market, 'leverage', 1),
                    },
                    'amount': {
                        'min': this.safeNumber(spotMarket, 'min_base_amount', amountPrecision),
                        'max': undefined,
                    },
                    'price': {
                        'min': undefined,
                        'max': undefined,
                    },
                    'cost': {
                        'min': this.safeNumber(market, 'min_quote_amount'),
                        'max': margin ? this.safeNumber(market, 'max_quote_amount') : undefined,
                    },
                },
                'created': createdTs,
                'info': market,
            });
        }
        return result;
    }
    async fetchContractMarkets(params = {}) {
        const result = [];
        const swapSettlementCurrencies = this.getSettlementCurrencies('swap', 'fetchMarkets');
        const futureSettlementCurrencies = this.getSettlementCurrencies('future', 'fetchMarkets');
        for (let c = 0; c < swapSettlementCurrencies.length; c++) {
            const settleId = swapSettlementCurrencies[c];
            const request = {
                'settle': settleId,
            };
            const response = await this.publicFuturesGetSettleContracts(this.extend(request, params));
            for (let i = 0; i < response.length; i++) {
                const parsedMarket = this.parseContractMarket(response[i], settleId);
                result.push(parsedMarket);
            }
        }
        for (let c = 0; c < futureSettlementCurrencies.length; c++) {
            const settleId = futureSettlementCurrencies[c];
            const request = {
                'settle': settleId,
            };
            const response = await this.publicDeliveryGetSettleContracts(this.extend(request, params));
            for (let i = 0; i < response.length; i++) {
                const parsedMarket = this.parseContractMarket(response[i], settleId);
                result.push(parsedMarket);
            }
        }
        return result;
    }
    parseContractMarket(market, settleId) {
        //
        //  Perpetual swap
        //
        //    {
        //        "name": "BTC_USDT",
        //        "type": "direct",
        //        "quanto_multiplier": "0.0001",
        //        "ref_discount_rate": "0",
        //        "order_price_deviate": "0.5",
        //        "maintenance_rate": "0.005",
        //        "mark_type": "index",
        //        "last_price": "38026",
        //        "mark_price": "37985.6",
        //        "index_price": "37954.92",
        //        "funding_rate_indicative": "0.000219",
        //        "mark_price_round": "0.01",
        //        "funding_offset": 0,
        //        "in_delisting": false,
        //        "risk_limit_base": "1000000",
        //        "interest_rate": "0.0003",
        //        "order_price_round": "0.1",
        //        "order_size_min": 1,
        //        "ref_rebate_rate": "0.2",
        //        "funding_interval": 28800,
        //        "risk_limit_step": "1000000",
        //        "leverage_min": "1",
        //        "leverage_max": "100",
        //        "risk_limit_max": "8000000",
        //        "maker_fee_rate": "-0.00025",
        //        "taker_fee_rate": "0.00075",
        //        "funding_rate": "0.002053",
        //        "order_size_max": 1000000,
        //        "funding_next_apply": 1610035200,
        //        "short_users": 977,
        //        "config_change_time": 1609899548,
        //        "create_time": 1609800048,
        //        "trade_size": 28530850594,
        //        "position_size": 5223816,
        //        "long_users": 455,
        //        "funding_impact_value": "60000",
        //        "orders_limit": 50,
        //        "trade_id": 10851092,
        //        "orderbook_id": 2129638396
        //    }
        //
        //  Delivery Futures
        //
        //    {
        //        "name": "BTC_USDT_20200814",
        //        "underlying": "BTC_USDT",
        //        "cycle": "WEEKLY",
        //        "type": "direct",
        //        "quanto_multiplier": "0.0001",
        //        "mark_type": "index",
        //        "last_price": "9017",
        //        "mark_price": "9019",
        //        "index_price": "9005.3",
        //        "basis_rate": "0.185095",
        //        "basis_value": "13.7",
        //        "basis_impact_value": "100000",
        //        "settle_price": "0",
        //        "settle_price_interval": 60,
        //        "settle_price_duration": 1800,
        //        "settle_fee_rate": "0.0015",
        //        "expire_time": 1593763200,
        //        "order_price_round": "0.1",
        //        "mark_price_round": "0.1",
        //        "leverage_min": "1",
        //        "leverage_max": "100",
        //        "maintenance_rate": "1000000",
        //        "risk_limit_base": "140.726652109199",
        //        "risk_limit_step": "1000000",
        //        "risk_limit_max": "8000000",
        //        "maker_fee_rate": "-0.00025",
        //        "taker_fee_rate": "0.00075",
        //        "ref_discount_rate": "0",
        //        "ref_rebate_rate": "0.2",
        //        "order_price_deviate": "0.5",
        //        "order_size_min": 1,
        //        "order_size_max": 1000000,
        //        "orders_limit": 50,
        //        "orderbook_id": 63,
        //        "trade_id": 26,
        //        "trade_size": 435,
        //        "position_size": 130,
        //        "config_change_time": 1593158867,
        //        "in_delisting": false
        //    }
        //
        const id = this.safeString(market, 'name');
        const parts = id.split('_');
        const baseId = this.safeString(parts, 0);
        const quoteId = this.safeString(parts, 1);
        const date = this.safeString(parts, 2);
        const base = this.safeCurrencyCode(baseId);
        const quote = this.safeCurrencyCode(quoteId);
        const settle = this.safeCurrencyCode(settleId);
        const expiry = this.safeTimestamp(market, 'expire_time');
        let symbol = '';
        let marketType = 'swap';
        if (date !== undefined) {
            symbol = base + '/' + quote + ':' + settle + '-' + this.yymmdd(expiry, '');
            marketType = 'future';
        }
        else {
            symbol = base + '/' + quote + ':' + settle;
        }
        const priceDeviate = this.safeString(market, 'order_price_deviate');
        const markPrice = this.safeString(market, 'mark_price');
        const minMultiplier = Precise["default"].stringSub('1', priceDeviate);
        const maxMultiplier = Precise["default"].stringAdd('1', priceDeviate);
        const minPrice = Precise["default"].stringMul(minMultiplier, markPrice);
        const maxPrice = Precise["default"].stringMul(maxMultiplier, markPrice);
        const takerPercent = this.safeString(market, 'taker_fee_rate');
        const makerPercent = this.safeString(market, 'maker_fee_rate', takerPercent);
        const isLinear = quote === settle;
        let contractSize = this.safeString(market, 'quanto_multiplier');
        // exception only for one market: https://api.gateio.ws/api/v4/futures/btc/contracts
        if (contractSize === '0') {
            contractSize = '1'; // 1 USD in WEB: https://i.imgur.com/MBBUI04.png
        }
        return {
            'id': id,
            'symbol': symbol,
            'base': base,
            'quote': quote,
            'settle': settle,
            'baseId': baseId,
            'quoteId': quoteId,
            'settleId': settleId,
            'type': marketType,
            'spot': false,
            'margin': false,
            'swap': marketType === 'swap',
            'future': marketType === 'future',
            'option': marketType === 'option',
            'active': true,
            'contract': true,
            'linear': isLinear,
            'inverse': !isLinear,
            'taker': this.parseNumber(Precise["default"].stringDiv(takerPercent, '100')),
            'maker': this.parseNumber(Precise["default"].stringDiv(makerPercent, '100')),
            'contractSize': this.parseNumber(contractSize),
            'expiry': expiry,
            'expiryDatetime': this.iso8601(expiry),
            'strike': undefined,
            'optionType': undefined,
            'precision': {
                'amount': this.parseNumber('1'),
                'price': this.safeNumber(market, 'order_price_round'),
            },
            'limits': {
                'leverage': {
                    'min': this.safeNumber(market, 'leverage_min'),
                    'max': this.safeNumber(market, 'leverage_max'),
                },
                'amount': {
                    'min': this.safeNumber(market, 'order_size_min'),
                    'max': this.safeNumber(market, 'order_size_max'),
                },
                'price': {
                    'min': this.parseNumber(minPrice),
                    'max': this.parseNumber(maxPrice),
                },
                'cost': {
                    'min': undefined,
                    'max': undefined,
                },
            },
            'created': this.safeIntegerProduct(market, 'create_time', 1000),
            'info': market,
        };
    }
    async fetchOptionMarkets(params = {}) {
        const result = [];
        const underlyings = await this.fetchOptionUnderlyings();
        for (let i = 0; i < underlyings.length; i++) {
            const underlying = underlyings[i];
            const query = this.extend({}, params);
            query['underlying'] = underlying;
            const response = await this.publicOptionsGetContracts(query);
            //
            //    [
            //        {
            //            "orders_limit": "50",
            //            "order_size_max": "100000",
            //            "mark_price_round": "0.1",
            //            "order_size_min": "1",
            //            "position_limit": "1000000",
            //            "orderbook_id": "575967",
            //            "order_price_deviate": "0.9",
            //            "is_call": true, // true means Call false means Put
            //            "last_price": "93.9",
            //            "bid1_size": "0",
            //            "bid1_price": "0",
            //            "taker_fee_rate": "0.0004",
            //            "underlying": "BTC_USDT",
            //            "create_time": "1646381188",
            //            "price_limit_fee_rate": "0.1",
            //            "maker_fee_rate": "0.0004",
            //            "trade_id": "727",
            //            "order_price_round": "0.1",
            //            "settle_fee_rate": "0.0001",
            //            "trade_size": "1982",
            //            "ref_rebate_rate": "0",
            //            "name": "BTC_USDT-20220311-44000-C",
            //            "underlying_price": "39194.26",
            //            "strike_price": "44000",
            //            "multiplier": "0.0001",
            //            "ask1_price": "0",
            //            "ref_discount_rate": "0",
            //            "expiration_time": "1646985600",
            //            "mark_price": "12.15",
            //            "position_size": "4",
            //            "ask1_size": "0",
            //            "tag": "WEEK"
            //        }
            //    ]
            //
            for (let j = 0; j < response.length; j++) {
                const market = response[j];
                const id = this.safeString(market, 'name');
                const parts = underlying.split('_');
                const baseId = this.safeString(parts, 0);
                const quoteId = this.safeString(parts, 1);
                const base = this.safeCurrencyCode(baseId);
                const quote = this.safeCurrencyCode(quoteId);
                let symbol = base + '/' + quote;
                const expiry = this.safeTimestamp(market, 'expiration_time');
                const strike = this.safeString(market, 'strike_price');
                const isCall = this.safeValue(market, 'is_call');
                const optionLetter = isCall ? 'C' : 'P';
                const optionType = isCall ? 'call' : 'put';
                symbol = symbol + ':' + quote + '-' + this.yymmdd(expiry) + '-' + strike + '-' + optionLetter;
                const priceDeviate = this.safeString(market, 'order_price_deviate');
                const markPrice = this.safeString(market, 'mark_price');
                const minMultiplier = Precise["default"].stringSub('1', priceDeviate);
                const maxMultiplier = Precise["default"].stringAdd('1', priceDeviate);
                const minPrice = Precise["default"].stringMul(minMultiplier, markPrice);
                const maxPrice = Precise["default"].stringMul(maxMultiplier, markPrice);
                const takerPercent = this.safeString(market, 'taker_fee_rate');
                const makerPercent = this.safeString(market, 'maker_fee_rate', takerPercent);
                result.push({
                    'id': id,
                    'symbol': symbol,
                    'base': base,
                    'quote': quote,
                    'settle': quote,
                    'baseId': baseId,
                    'quoteId': quoteId,
                    'settleId': quoteId,
                    'type': 'option',
                    'spot': false,
                    'margin': false,
                    'swap': false,
                    'future': false,
                    'option': true,
                    'active': true,
                    'contract': true,
                    'linear': true,
                    'inverse': false,
                    'taker': this.parseNumber(Precise["default"].stringDiv(takerPercent, '100')),
                    'maker': this.parseNumber(Precise["default"].stringDiv(makerPercent, '100')),
                    'contractSize': this.parseNumber('1'),
                    'expiry': expiry,
                    'expiryDatetime': this.iso8601(expiry),
                    'strike': this.parseNumber(strike),
                    'optionType': optionType,
                    'precision': {
                        'amount': this.parseNumber('1'),
                        'price': this.safeNumber(market, 'order_price_round'),
                    },
                    'limits': {
                        'leverage': {
                            'min': undefined,
                            'max': undefined,
                        },
                        'amount': {
                            'min': this.safeNumber(market, 'order_size_min'),
                            'max': this.safeNumber(market, 'order_size_max'),
                        },
                        'price': {
                            'min': this.parseNumber(minPrice),
                            'max': this.parseNumber(maxPrice),
                        },
                        'cost': {
                            'min': undefined,
                            'max': undefined,
                        },
                    },
                    'created': this.safeTimestamp(market, 'create_time'),
                    'info': market,
                });
            }
        }
        return result;
    }
    async fetchOptionUnderlyings() {
        const underlyingsResponse = await this.publicOptionsGetUnderlyings();
        //
        //    [
        //        {
        //            "index_time": "1646915796",
        //            "name": "BTC_USDT",
        //            "index_price": "39142.73"
        //        }
        //    ]
        //
        const underlyings = [];
        for (let i = 0; i < underlyingsResponse.length; i++) {
            const underlying = underlyingsResponse[i];
            const name = this.safeString(underlying, 'name');
            if (name !== undefined) {
                underlyings.push(name);
            }
        }
        return underlyings;
    }
    prepareRequest(market = undefined, type = undefined, params = {}) {
        /**
         * @ignore
         * @method
         * @name gate#prepareRequest
         * @description Fills request params contract, settle, currency_pair, market and account where applicable
         * @param {object} market CCXT market, required when type is undefined
         * @param {string} type 'spot', 'swap', or 'future', required when market is undefined
         * @param {object} [params] request parameters
         * @returns the api request object, and the new params object with non-needed parameters removed
         */
        // * Do not call for multi spot order methods like cancelAllOrders and fetchOpenOrders. Use multiOrderSpotPrepareRequest instead
        const request = {};
        if (market !== undefined) {
            if (market['contract']) {
                request['contract'] = market['id'];
                if (!market['option']) {
                    request['settle'] = market['settleId'];
                }
            }
            else {
                request['currency_pair'] = market['id'];
            }
        }
        else {
            const swap = type === 'swap';
            const future = type === 'future';
            if (swap || future) {
                const defaultSettle = swap ? 'usdt' : 'btc';
                const settle = this.safeStringLower(params, 'settle', defaultSettle);
                params = this.omit(params, 'settle');
                request['settle'] = settle;
            }
        }
        return [request, params];
    }
    spotOrderPrepareRequest(market = undefined, trigger = false, params = {}) {
        /**
         * @ignore
         * @method
         * @name gate#multiOrderSpotPrepareRequest
         * @description Fills request params currency_pair, market and account where applicable for spot order methods like fetchOpenOrders, cancelAllOrders
         * @param {object} market CCXT market
         * @param {bool} trigger true if for a trigger order
         * @param {object} [params] request parameters
         * @returns the api request object, and the new params object with non-needed parameters removed
         */
        const [marginMode, query] = this.getMarginMode(trigger, params);
        const request = {};
        if (!trigger) {
            if (market === undefined) {
                throw new errors.ArgumentsRequired(this.id + ' spotOrderPrepareRequest() requires a market argument for non-trigger orders');
            }
            request['account'] = marginMode;
            request['currency_pair'] = market['id']; // Should always be set for non-trigger
        }
        return [request, query];
    }
    multiOrderSpotPrepareRequest(market = undefined, trigger = false, params = {}) {
        /**
         * @ignore
         * @method
         * @name gate#multiOrderSpotPrepareRequest
         * @description Fills request params currency_pair, market and account where applicable for spot order methods like fetchOpenOrders, cancelAllOrders
         * @param {object} market CCXT market
         * @param {bool} trigger true if for a trigger order
         * @param {object} [params] request parameters
         * @returns the api request object, and the new params object with non-needed parameters removed
         */
        const [marginMode, query] = this.getMarginMode(trigger, params);
        const request = {
            'account': marginMode,
        };
        if (market !== undefined) {
            if (trigger) {
                // gate spot and margin trigger orders use the term market instead of currency_pair, and normal instead of spot. Neither parameter is used when fetching/cancelling a single order. They are used for creating a single trigger order, but createOrder does not call this method
                request['market'] = market['id'];
            }
            else {
                request['currency_pair'] = market['id'];
            }
        }
        return [request, query];
    }
    getMarginMode(trigger, params) {
        /**
         * @ignore
         * @method
         * @name gate#getMarginMode
         * @description Gets the margin type for this api call
         * @param {bool} trigger True if for a trigger order
         * @param {object} [params] Request params
         * @returns The marginMode and the updated request params with marginMode removed, marginMode value is the value that can be read by the "account" property specified in gates api docs
         */
        const defaultMarginMode = this.safeStringLower2(this.options, 'defaultMarginMode', 'marginMode', 'spot'); // 'margin' is isolated margin on gate's api
        let marginMode = this.safeStringLower2(params, 'marginMode', 'account', defaultMarginMode);
        params = this.omit(params, ['marginMode', 'account']);
        if (marginMode === 'cross') {
            marginMode = 'cross_margin';
        }
        else if (marginMode === 'isolated') {
            marginMode = 'margin';
        }
        else if (marginMode === '') {
            marginMode = 'spot';
        }
        if (trigger) {
            if (marginMode === 'spot') {
                // gate spot trigger orders use the term normal instead of spot
                marginMode = 'normal';
            }
            if (marginMode === 'cross_margin') {
                throw new errors.BadRequest(this.id + ' getMarginMode() does not support trigger orders for cross margin');
            }
        }
        let isUnifiedAccount = false;
        [isUnifiedAccount, params] = this.handleOptionAndParams(params, 'getMarginMode', 'unifiedAccount');
        if (isUnifiedAccount) {
            marginMode = 'unified';
        }
        return [marginMode, params];
    }
    getSettlementCurrencies(type, method) {
        const options = this.safeValue(this.options, type, {}); // [ 'BTC', 'USDT' ] unified codes
        const fetchMarketsContractOptions = this.safeValue(options, method, {});
        const defaultSettle = (type === 'swap') ? ['usdt'] : ['btc'];
        return this.safeValue(fetchMarketsContractOptions, 'settlementCurrencies', defaultSettle);
    }
    /**
     * @method
     * @name gate#fetchCurrencies
     * @description fetches all available currencies on an exchange
     * @see https://www.gate.io/docs/developers/apiv4/en/#list-all-currencies-details
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {object} an associative dictionary of currencies
     */
    async fetchCurrencies(params = {}) {
        // sandbox/testnet only supports future markets
        const apiBackup = this.safeValue(this.urls, 'apiBackup');
        if (apiBackup !== undefined) {
            return undefined;
        }
        const response = await this.publicSpotGetCurrencies(params);
        //
        //    [
        //      {
        //         "currency": "USDT",
        //         "name": "Tether",
        //         "delisted": false,
        //         "withdraw_disabled": false,
        //         "withdraw_delayed": false,
        //         "deposit_disabled": false,
        //         "trade_disabled": false,
        //         "fixed_rate": "",
        //         "chain": "ETH",
        //         "chains": [
        //           {
        //             "name": "ETH",
        //             "addr": "0xdAC17F958D2ee523a2206206994597C13D831ec7",
        //             "withdraw_disabled": false,
        //             "withdraw_delayed": false,
        //             "deposit_disabled": false
        //           },
        //           {
        //             "name": "ARBEVM",
        //             "addr": "0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9",
        //             "withdraw_disabled": false,
        //             "withdraw_delayed": false,
        //             "deposit_disabled": false
        //           },
        //           {
        //             "name": "BSC",
        //             "addr": "0x55d398326f99059fF775485246999027B3197955",
        //             "withdraw_disabled": false,
        //             "withdraw_delayed": false,
        //             "deposit_disabled": false
        //           },
        //         ]
        //       },
        //    ]
        //
        const indexedCurrencies = this.indexBy(response, 'currency');
        const result = {};
        for (let i = 0; i < response.length; i++) {
            const entry = response[i];
            const currencyId = this.safeString(entry, 'currency');
            const code = this.safeCurrencyCode(currencyId);
            // check leveraged tokens (e.g. BTC3S, ETH5L)
            const type = this.isLeveragedCurrency(currencyId, true, indexedCurrencies) ? 'leveraged' : 'crypto';
            const chains = this.safeList(entry, 'chains', []);
            const networks = {};
            for (let j = 0; j < chains.length; j++) {
                const chain = chains[j];
                const networkId = this.safeString(chain, 'name');
                const networkCode = this.networkIdToCode(networkId);
                networks[networkCode] = {
                    'info': chain,
                    'id': networkId,
                    'network': networkCode,
                    'active': undefined,
                    'deposit': !this.safeBool(chain, 'deposit_disabled'),
                    'withdraw': !this.safeBool(chain, 'withdraw_disabled'),
                    'fee': undefined,
                    'precision': this.parseNumber('0.0001'),
                    'limits': {
                        'deposit': {
                            'min': undefined,
                            'max': undefined,
                        },
                        'withdraw': {
                            'min': undefined,
                            'max': undefined,
                        },
                    },
                };
            }
            result[code] = this.safeCurrencyStructure({
                'id': currencyId,
                'code': code,
                'name': this.safeString(entry, 'name'),
                'type': type,
                'active': !this.safeBool(entry, 'delisted'),
                'deposit': !this.safeBool(entry, 'deposit_disabled'),
                'withdraw': !this.safeBool(entry, 'withdraw_disabled'),
                'fee': undefined,
                'networks': networks,
                'precision': this.parseNumber('0.0001'),
                'info': entry,
            });
        }
        return result;
    }
    /**
     * @method
     * @name gate#fetchFundingRate
     * @description fetch the current funding rate
     * @see https://www.gate.io/docs/developers/apiv4/en/#get-a-single-contract
     * @param {string} symbol unified market symbol
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {object} a [funding rate structure]{@link https://docs.ccxt.com/#/?id=funding-rate-structure}
     */
    async fetchFundingRate(symbol, params = {}) {
        await this.loadMarkets();
        const market = this.market(symbol);
        if (!market['swap']) {
            throw new errors.BadSymbol(this.id + ' fetchFundingRate() supports swap contracts only');
        }
        const [request, query] = this.prepareRequest(market, undefined, params);
        const response = await this.publicFuturesGetSettleContractsContract(this.extend(request, query));
        //
        //    [
        //        {
        //            "name": "BTC_USDT",
        //            "type": "direct",
        //            "quanto_multiplier": "0.0001",
        //            "ref_discount_rate": "0",
        //            "order_price_deviate": "0.5",
        //            "maintenance_rate": "0.005",
        //            "mark_type": "index",
        //            "last_price": "38026",
        //            "mark_price": "37985.6",
        //            "index_price": "37954.92",
        //            "funding_rate_indicative": "0.000219",
        //            "mark_price_round": "0.01",
        //            "funding_offset": 0,
        //            "in_delisting": false,
        //            "risk_limit_base": "1000000",
        //            "interest_rate": "0.0003",
        //            "order_price_round": "0.1",
        //            "order_size_min": 1,
        //            "ref_rebate_rate": "0.2",
        //            "funding_interval": 28800,
        //            "risk_limit_step": "1000000",
        //            "leverage_min": "1",
        //            "leverage_max": "100",
        //            "risk_limit_max": "8000000",
        //            "maker_fee_rate": "-0.00025",
        //            "taker_fee_rate": "0.00075",
        //            "funding_rate": "0.002053",
        //            "order_size_max": 1000000,
        //            "funding_next_apply": 1610035200,
        //            "short_users": 977,
        //            "config_change_time": 1609899548,
        //            "trade_size": 28530850594,
        //            "position_size": 5223816,
        //            "long_users": 455,
        //            "funding_impact_value": "60000",
        //            "orders_limit": 50,
        //            "trade_id": 10851092,
        //            "orderbook_id": 2129638396
        //        }
        //    ]
        //
        return this.parseFundingRate(response);
    }
    /**
     * @method
     * @name gate#fetchFundingRates
     * @description fetch the funding rate for multiple markets
     * @see https://www.gate.io/docs/developers/apiv4/en/#list-all-futures-contracts
     * @param {string[]|undefined} symbols list of unified market symbols
     * @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-rates-structure}, indexed by market symbols
     */
    async fetchFundingRates(symbols = undefined, params = {}) {
        await this.loadMarkets();
        symbols = this.marketSymbols(symbols);
        let market = undefined;
        if (symbols !== undefined) {
            const firstSymbol = this.safeString(symbols, 0);
            market = this.market(firstSymbol);
        }
        const [request, query] = this.prepareRequest(market, 'swap', params);
        const response = await this.publicFuturesGetSettleContracts(this.extend(request, query));
        //
        //    [
        //        {
        //            "name": "BTC_USDT",
        //            "type": "direct",
        //            "quanto_multiplier": "0.0001",
        //            "ref_discount_rate": "0",
        //            "order_price_deviate": "0.5",
        //            "maintenance_rate": "0.005",
        //            "mark_type": "index",
        //            "last_price": "38026",
        //            "mark_price": "37985.6",
        //            "index_price": "37954.92",
        //            "funding_rate_indicative": "0.000219",
        //            "mark_price_round": "0.01",
        //            "funding_offset": 0,
        //            "in_delisting": false,
        //            "risk_limit_base": "1000000",
        //            "interest_rate": "0.0003",
        //            "order_price_round": "0.1",
        //            "order_size_min": 1,
        //            "ref_rebate_rate": "0.2",
        //            "funding_interval": 28800,
        //            "risk_limit_step": "1000000",
        //            "leverage_min": "1",
        //            "leverage_max": "100",
        //            "risk_limit_max": "8000000",
        //            "maker_fee_rate": "-0.00025",
        //            "taker_fee_rate": "0.00075",
        //            "funding_rate": "0.002053",
        //            "order_size_max": 1000000,
        //            "funding_next_apply": 1610035200,
        //            "short_users": 977,
        //            "config_change_time": 1609899548,
        //            "trade_size": 28530850594,
        //            "position_size": 5223816,
        //            "long_users": 455,
        //            "funding_impact_value": "60000",
        //            "orders_limit": 50,
        //            "trade_id": 10851092,
        //            "orderbook_id": 2129638396
        //        }
        //    ]
        //
        return this.parseFundingRates(response, symbols);
    }
    parseFundingRate(contract, market = undefined) {
        //
        //    {
        //        "name": "BTC_USDT",
        //        "type": "direct",
        //        "quanto_multiplier": "0.0001",
        //        "ref_discount_rate": "0",
        //        "order_price_deviate": "0.5",
        //        "maintenance_rate": "0.005",
        //        "mark_type": "index",
        //        "last_price": "38026",
        //        "mark_price": "37985.6",
        //        "index_price": "37954.92",
        //        "funding_rate_indicative": "0.000219",
        //        "mark_price_round": "0.01",
        //        "funding_offset": 0,
        //        "in_delisting": false,
        //        "risk_limit_base": "1000000",
        //        "interest_rate": "0.0003",
        //        "order_price_round": "0.1",
        //        "order_size_min": 1,
        //        "ref_rebate_rate": "0.2",
        //        "funding_interval": 28800,
        //        "risk_limit_step": "1000000",
        //        "leverage_min": "1",
        //        "leverage_max": "100",
        //        "risk_limit_max": "8000000",
        //        "maker_fee_rate": "-0.00025",
        //        "taker_fee_rate": "0.00075",
        //        "funding_rate": "0.002053",
        //        "order_size_max": 1000000,
        //        "funding_next_apply": 1610035200,
        //        "short_users": 977,
        //        "config_change_time": 1609899548,
        //        "trade_size": 28530850594,
        //        "position_size": 5223816,
        //        "long_users": 455,
        //        "funding_impact_value": "60000",
        //        "orders_limit": 50,
        //        "trade_id": 10851092,
        //        "orderbook_id": 2129638396
        //    }
        //
        const marketId = this.safeString(contract, 'name');
        const symbol = this.safeSymbol(marketId, market, '_', 'swap');
        const markPrice = this.safeNumber(contract, 'mark_price');
        const indexPrice = this.safeNumber(contract, 'index_price');
        const interestRate = this.safeNumber(contract, 'interest_rate');
        const fundingRate = this.safeNumber(contract, 'funding_rate');
        const fundingTime = this.safeTimestamp(contract, 'funding_next_apply');
        const fundingRateIndicative = this.safeNumber(contract, 'funding_rate_indicative');
        const fundingInterval = Precise["default"].stringMul('1000', this.safeString(contract, 'funding_interval'));
        return {
            'info': contract,
            'symbol': symbol,
            'markPrice': markPrice,
            'indexPrice': indexPrice,
            'interestRate': interestRate,
            'estimatedSettlePrice': undefined,
            'timestamp': undefined,
            'datetime': undefined,
            'fundingRate': fundingRate,
            'fundingTimestamp': fundingTime,
            'fundingDatetime': this.iso8601(fundingTime),
            'nextFundingRate': fundingRateIndicative,
            'nextFundingTimestamp': undefined,
            'nextFundingDatetime': undefined,
            'previousFundingRate': undefined,
            'previousFundingTimestamp': undefined,
            'previousFundingDatetime': undefined,
            'interval': this.parseFundingInterval(fundingInterval),
        };
    }
    parseFundingInterval(interval) {
        const intervals = {
            '3600000': '1h',
            '14400000': '4h',
            '28800000': '8h',
            '57600000': '16h',
            '86400000': '24h',
        };
        return this.safeString(intervals, interval, interval);
    }
    async fetchNetworkDepositAddress(code, params = {}) {
        await this.loadMarkets();
        const currency = this.currency(code);
        const request = {
            'currency': currency['id'], // todo: currencies have network-junctions
        };
        const response = await this.privateWalletGetDepositAddress(this.extend(request, params));
        const addresses = this.safeValue(response, 'multichain_addresses');
        const currencyId = this.safeString(response, 'currency');
        code = this.safeCurrencyCode(currencyId);
        const result = {};
        for (let i = 0; i < addresses.length; i++) {
            const entry = addresses[i];
            //
            //    {
            //        "chain": "ETH",
            //        "address": "0x359a697945E79C7e17b634675BD73B33324E9408",
            //        "payment_id": "",
            //        "payment_name": "",
            //        "obtain_failed": "0"
            //    }
            //
            const obtainFailed = this.safeInteger(entry, 'obtain_failed');
            if (obtainFailed) {
                continue;
            }
            const network = this.safeString(entry, 'chain');
            const address = this.safeString(entry, 'address');
            const tag = this.safeString(entry, 'payment_id');
            result[network] = {
                'info': entry,
                'code': code,
                'currency': code,
                'address': address,
                'tag': tag,
            };
        }
        return result;
    }
    /**
     * @method
     * @name gate#fetchDepositAddressesByNetwork
     * @description fetch a dictionary of addresses for a currency, indexed by network
     * @param {string} code unified currency code of the currency for the deposit address
     * @param {object} [params] extra parameters specific to the 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 = {
            'currency': currency['id'],
        };
        const response = await this.privateWalletGetDepositAddress(this.extend(request, params));
        const chains = this.safeValue(response, 'multichain_addresses', []);
        const currencyId = this.safeString(response, 'currency');
        currency = this.safeCurrency(currencyId, currency);
        const parsed = this.parseDepositAddresses(chains, undefined, false);
        return this.indexBy(parsed, 'network');
    }
    /**
     * @method
     * @name gate#fetchDepositAddress
     * @description fetch the deposit address for a currency associated with this account
     * @see https://www.gate.io/docs/developers/apiv4/en/#generate-currency-deposit-address
     * @param {string} code unified currency code
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @param {string} [params.network] unified network code (not used directly by gate.io but used by ccxt to filter the response)
     * @returns {object} an [address structure]{@link https://docs.ccxt.com/#/?id=address-structure}
     */
    async fetchDepositAddress(code, params = {}) {
        await this.loadMarkets();
        let networkCode = undefined;
        [networkCode, params] = this.handleNetworkCodeAndParams(params);
        const chainsIndexedById = await this.fetchDepositAddressesByNetwork(code, params);
        const selectedNetworkIdOrCode = this.selectNetworkCodeFromUnifiedNetworks(code, networkCode, chainsIndexedById);
        return chainsIndexedById[selectedNetworkIdOrCode];
    }
    parseDepositAddress(depositAddress, currency = undefined) {
        //
        //     {
        //         chain: "BTC",
        //         address: "1Nxu.......Ys",
        //         payment_id: "",
        //         payment_name: "",
        //         obtain_failed: "0",
        //     }
        //
        const address = this.safeString(depositAddress, 'address');
        this.checkAddress(address);
        return {
            'info': depositAddress,
            'currency': this.safeString(currency, 'code'),
            'address': address,
            'tag': this.safeString(depositAddress, 'payment_id'),
            'network': this.networkIdToCode(this.safeString(depositAddress, 'chain')),
        };
    }
    /**
     * @method
     * @name gate#fetchTradingFee
     * @description fetch the trading fees for a market
     * @see https://www.gate.io/docs/developers/apiv4/en/#retrieve-personal-trading-fee
     * @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 = {
            'currency_pair': market['id'],
        };
        const response = await this.privateWalletGetFee(this.extend(request, params));
        //
        //    {
        //        "user_id": 1486602,
        //        "taker_fee": "0.002",
        //        "maker_fee": "0.002",
        //        "gt_discount": true,
        //        "gt_taker_fee": "0.0015",
        //        "gt_maker_fee": "0.0015",
        //        "loan_fee": "0.18",
        //        "point_type": "0",
        //        "futures_taker_fee": "0.0005",
        //        "futures_maker_fee": "0"
        //    }
        //
        return this.parseTradingFee(response, market);
    }
    /**
     * @method
     * @name gate#fetchTradingFees
     * @description fetch the trading fees for multiple markets
     * @see https://www.gate.io/docs/developers/apiv4/en/#retrieve-personal-trading-fee
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @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();
        const response = await this.privateWalletGetFee(params);
        //
        //    {
        //        "user_id": 1486602,
        //        "taker_fee": "0.002",
        //        "maker_fee": "0.002",
        //        "gt_discount": true,
        //        "gt_taker_fee": "0.0015",
        //        "gt_maker_fee": "0.0015",
        //        "loan_fee": "0.18",
        //        "point_type": "0",
        //        "futures_taker_fee": "0.0005",
        //        "futures_maker_fee": "0"
        //    }
        //
        return this.parseTradingFees(response);
    }
    parseTradingFees(response) {
        const result = {};
        for (let i = 0; i < this.symbols.length; i++) {
            const symbol = this.symbols[i];
            const market = this.market(symbol);
            result[symbol] = this.parseTradingFee(response, market);
        }
        return result;
    }
    parseTradingFee(info, market = undefined) {
        //
        //    {
        //        "user_id": 1486602,
        //        "taker_fee": "0.002",
        //        "maker_fee": "0.002",
        //        "gt_discount": true,
        //        "gt_taker_fee": "0.0015",
        //        "gt_maker_fee": "0.0015",
        //        "loan_fee": "0.18",
        //        "point_type": "0",
        //        "futures_taker_fee": "0.0005",
        //        "futures_maker_fee": "0"
        //    }
        //
        const gtDiscount = this.safeValue(info, 'gt_discount');
        const taker = gtDiscount ? 'gt_taker_fee' : 'taker_fee';
        const maker = gtDiscount ? 'gt_maker_fee' : 'maker_fee';
        const contract = this.safeValue(market, 'contract');
        const takerKey = contract ? 'futures_taker_fee' : taker;
        const makerKey = contract ? 'futures_maker_fee' : maker;
        return {
            'info': info,
            'symbol': this.safeString(market, 'symbol'),
            'maker': this.safeNumber(info, makerKey),
            'taker': this.safeNumber(info, takerKey),
            'percentage': undefined,
            'tierBased': undefined,
        };
    }
    /**
     * @method
     * @name gate#fetchTransactionFees
     * @deprecated
     * @description please use fetchDepositWithdrawFees instead
     * @see https://www.gate.io/docs/developers/apiv4/en/#retrieve-withdrawal-status
     * @param {string[]|undefined} 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 fetchTransactionFees(codes = undefined, params = {}) {
        await this.loadMarkets();
        const response = await this.privateWalletGetWithdrawStatus(params);
        //
        //    {
        //        "currency": "MTN",
        //        "name": "Medicalchain",
        //        "name_cn": "Medicalchain",
        //        "deposit": "0",
        //        "withdraw_percent": "0%",
        //        "withdraw_fix": "900",
        //        "withdraw_day_limit": "500000",
        //        "withdraw_day_limit_remain": "500000",
        //        "withdraw_amount_mini": "900.1",
        //        "withdraw_eachtime_limit": "90000000000",
        //        "withdraw_fix_on_chains": {
        //            "ETH": "900"
        //        }
        //    }
        //
        const result = {};
        let withdrawFees = {};
        for (let i = 0; i < response.length; i++) {
            withdrawFees = {};
            const entry = response[i];
            const currencyId = this.safeString(entry, 'currency');
            const code = this.safeCurrencyCode(currencyId);
            if ((codes !== undefined) && !this.inArray(code, codes)) {
                continue;
            }
            const withdrawFixOnChains = this.safeValue(entry, 'withdraw_fix_on_chains');
            if (withdrawFixOnChains === undefined) {
                withdrawFees = this.safeNumber(entry, 'withdraw_fix');
            }
            else {
                const chainKeys = Object.keys(withdrawFixOnChains);
                for (let j = 0; j < chainKeys.length; j++) {
                    const chainKey = chainKeys[j];
                    withdrawFees[chainKey] = this.parseNumber(withdrawFixOnChains[chainKey]);
                }
            }
            result[code] = {
                'withdraw': withdrawFees,
                'deposit': undefined,
                'info': entry,
            };
        }
        return result;
    }
    /**
     * @method
     * @name gate#fetchDepositWithdrawFees
     * @description fetch deposit and withdraw fees
     * @see https://www.gate.io/docs/developers/apiv4/en/#retrieve-withdrawal-status
     * @param {string[]|undefined} 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 = {}) {
        await this.loadMarkets();
        const response = await this.privateWalletGetWithdrawStatus(params);
        //
        //    [
        //        {
        //            "currency": "MTN",
        //            "name": "Medicalchain",
        //            "name_cn": "Medicalchain",
        //            "deposit": "0",
        //            "withdraw_percent": "0%",
        //            "withdraw_fix": "900",
        //            "withdraw_day_limit": "500000",
        //            "withdraw_day_limit_remain": "500000",
        //            "withdraw_amount_mini": "900.1",
        //            "withdraw_eachtime_limit": "90000000000",
        //            "withdraw_fix_on_chains": {
        //                "ETH": "900"
        //            }
        //        }
        //    ]
        //
        return this.parseDepositWithdrawFees(response, codes, 'currency');
    }
    parseDepositWithdrawFee(fee, currency = undefined) {
        //
        //    {
        //        "currency": "MTN",
        //        "name": "Medicalchain",
        //        "name_cn": "Medicalchain",
        //        "deposit": "0",
        //        "withdraw_percent": "0%",
        //        "withdraw_fix": "900",
        //        "withdraw_day_limit": "500000",
        //        "withdraw_day_limit_remain": "500000",
        //        "withdraw_amount_mini": "900.1",
        //        "withdraw_eachtime_limit": "90000000000",
        //        "withdraw_fix_on_chains": {
        //            "ETH": "900"
        //        }
        //    }
        //
        const withdrawFixOnChains = this.safeValue(fee, 'withdraw_fix_on_chains');
        const result = {
            'info': fee,
            'withdraw': {
                'fee': this.safeNumber(fee, 'withdraw_fix'),
                'percentage': false,
            },
            'deposit': {
                'fee': this.safeNumber(fee, 'deposit'),
                'percentage': false,
            },
            'networks': {},
        };
        if (withdrawFixOnChains !== undefined) {
            const chainKeys = Object.keys(withdrawFixOnChains);
            for (let i = 0; i < chainKeys.length; i++) {
                const chainKey = chainKeys[i];
                const networkCode = this.networkIdToCode(chainKey, this.safeString(fee, 'currency'));
                result['networks'][networkCode] = {
                    'withdraw': {
                        'fee': this.parseNumber(withdrawFixOnChains[chainKey]),
                        'percentage': false,
                    },
                    'deposit': {
                        'fee': undefined,
                        'percentage': undefined,
                    },
                };
            }
        }
        return result;
    }
    /**
     * @method
     * @name gate#fetchFundingHistory
     * @description fetch the history of funding payments paid and received on this account
     * @see https://www.gate.io/docs/developers/apiv4/en/#query-account-book-2
     * @see https://www.gate.io/docs/developers/apiv4/en/#query-account-book-3
     * @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
     * @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 defaultType = 'future';
        let market = undefined;
        if (symbol !== undefined) {
            market = this.market(symbol);
            symbol = market['symbol'];
        }
        const [type, query] = this.handleMarketTypeAndParams('fetchFundingHistory', market, params);
        const [request, requestParams] = this.prepareRequest(market, type, query);
        request['type'] = 'fund'; // 'dnw' 'pnl' 'fee' 'refr' 'fund' 'point_dnw' 'point_fee' 'point_refr'
        if (since !== undefined) {
            // from should be integer
            request['from'] = this.parseToInt(since / 1000);
        }
        if (limit !== undefined) {
            request['limit'] = limit;
        }
        let response = undefined;
        if (type === 'swap') {
            response = await this.privateFuturesGetSettleAccountBook(this.extend(request, requestParams));
        }
        else if (type === 'future') {
            response = await this.privateDeliveryGetSettleAccountBook(this.extend(request, requestParams));
        }
        else {
            throw new errors.NotSupported(this.id + ' fetchFundingHistory() only support swap & future market type');
        }
        //
        //    [
        //        {
        //            "time": 1646899200,
        //            "change": "-0.027722",
        //            "balance": "11.653120591841",
        //            "text": "XRP_USDT",
        //            "type": "fund"
        //        },
        //        ...
        //    ]
        //
        return this.parseFundingHistories(response, symbol, since, limit);
    }
    parseFundingHistories(response, symbol, since, limit) {
        const result = [];
        for (let i = 0; i < response.length; i++) {
            const entry = response[i];
            const funding = this.parseFundingHistory(entry);
            result.push(funding);
        }
        const sorted = this.sortBy(result, 'timestamp');
        return this.filterBySymbolSinceLimit(sorted, symbol, since, limit);
    }
    parseFundingHistory(info, market = undefined) {
        //
        //    {
        //        "time": 1646899200,
        //        "change": "-0.027722",
        //        "balance": "11.653120591841",
        //        "text": "XRP_USDT",
        //        "type": "fund"
        //    }
        //
        const timestamp = this.safeTimestamp(info, 'time');
        const marketId = this.safeString(info, 'text');
        market = this.safeMarket(marketId, market, '_', 'swap');
        return {
            'info': info,
            'symbol': this.safeString(market, 'symbol'),
            'code': this.safeString(market, 'settle'),
            'timestamp': timestamp,
            'datetime': this.iso8601(timestamp),
            'id': undefined,
            'amount': this.safeNumber(info, 'change'),
        };
    }
    /**
     * @method
     * @name gate#fetchOrderBook
     * @description fetches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
     * @see https://www.gate.io/docs/developers/apiv4/en/#retrieve-order-book
     * @see https://www.gate.io/docs/developers/apiv4/en/#futures-order-book
     * @see https://www.gate.io/docs/developers/apiv4/en/#futures-order-book-2
     * @see https://www.gate.io/docs/developers/apiv4/en/#options-order-book
     * @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 = {}) {
        await this.loadMarkets();
        const market = this.market(symbol);
        //
        //     const request: Dict = {
        //         'currency_pair': market['id'],
        //         'interval': '0', // depth, 0 means no aggregation is applied, default to 0
        //         'limit': limit, // maximum number of order depth data in asks or bids
        //         'with_id': true, // return order book ID
        //     };
        //
        const [request, query] = this.prepareRequest(market, market['type'], params);
        if (limit !== undefined) {
            request['limit'] = limit; // default 10, max 100
        }
        request['with_id'] = true;
        let response = undefined;
        if (market['spot'] || market['margin']) {
            response = await this.publicSpotGetOrderBook(this.extend(request, query));
        }
        else if (market['swap']) {
            response = await this.publicFuturesGetSettleOrderBook(this.extend(request, query));
        }
        else if (market['future']) {
            response = await this.publicDeliveryGetSettleOrderBook(this.extend(request, query));
        }
        else if (market['option']) {
            response = await this.publicOptionsGetOrderBook(this.extend(request, query));
        }
        else {
            throw new errors.NotSupported(this.id + ' fetchOrderBook() not support this market type');
        }
        //
        // spot
        //
        //     {
        //         "id": 6358770031
        //         "current": 1634345973275,
        //         "update": 1634345973271,
        //         "asks": [
        //             ["2.2241","12449.827"],
        //             ["2.2242","200"],
        //             ["2.2244","826.931"],
        //             ["2.2248","3876.107"],
        //             ["2.225","2377.252"],
        //             ["2.22509","439.484"],
        //             ["2.2251","1489.313"],
        //             ["2.2253","714.582"],
        //             ["2.2254","1349.784"],
        //             ["2.2256","234.701"]],
        //          "bids": [
        //             ["2.2236","32.465"],
        //             ["2.2232","243.983"],
        //             ["2.2231","32.207"],
        //             ["2.223","449.827"],
        //             ["2.2228","7.918"],
        //             ["2.2227","12703.482"],
        //             ["2.2226","143.033"],
        //             ["2.2225","143.027"],
        //             ["2.2224","1369.352"],
        //             ["2.2223","756.063"]
        //         ]
        //     }
        //
        // swap, future and option
        //
        //     {
        //         "id": 6358770031
        //         "current": 1634350208.745,
        //         "asks": [
        //             {"s": 24909, "p": "61264.8"},
        //             {"s": 81, "p": "61266.6"},
        //             {"s": 2000, "p": "61267.6"},
        //             {"s": 490, "p": "61270.2"},
        //             {"s": 12, "p": "61270.4"},
        //             {"s": 11782, "p": "61273.2"},
        //             {"s": 14666, "p": "61273.3"},
        //             {"s": 22541, "p": "61273.4"},
        //             {"s": 33, "p": "61273.6"},
        //             {"s": 11980, "p": "61274.5"}
        //         ],
        //         "bids": [
        //             {"s": 41844, "p": "61264.7"},
        //             {"s": 13783, "p": "61263.3"},
        //             {"s": 1143, "p": "61259.8"},
        //             {"s": 81, "p": "61258.7"},
        //             {"s": 2471, "p": "61257.8"},
        //             {"s": 2471, "p": "61257.7"},
        //             {"s": 2471, "p": "61256.5"},
        //             {"s": 3, "p": "61254.2"},
        //             {"s": 114, "p": "61252.4"},
        //             {"s": 14372, "p": "61248.6"}
        //         ],
        //         "update": 1634350208.724
        //     }
        //
        let timestamp = this.safeInteger(response, 'current');
        if (!market['spot']) {
            timestamp = timestamp * 1000;
        }
        const priceKey = market['spot'] ? 0 : 'p';
        const amountKey = market['spot'] ? 1 : 's';
        const nonce = this.safeInteger(response, 'id');
        const result = this.parseOrderBook(response, symbol, timestamp, 'bids', 'asks', priceKey, amountKey);
        result['nonce'] = nonce;
        return result;
    }
    /**
     * @method
     * @name gate#fetchTicker
     * @description fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
     * @see https://www.gate.io/docs/developers/apiv4/en/#get-details-of-a-specifc-order
     * @see https://www.gate.io/docs/developers/apiv4/en/#list-futures-tickers
     * @see https://www.gate.io/docs/developers/apiv4/en/#list-futures-tickers-2
     * @see https://www.gate.io/docs/developers/apiv4/en/#list-tickers-of-options-contracts
     * @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 = {}) {
        await this.loadMarkets();
        const market = this.market(symbol);
        const [request, query] = this.prepareRequest(market, undefined, params);
        let response = undefined;
        if (market['spot'] || market['margin']) {
            response = await this.publicSpotGetTickers(this.extend(request, query));
        }
        else if (market['swap']) {
            response = await this.publicFuturesGetSettleTickers(this.extend(request, query));
        }
        else if (market['future']) {
            response = await this.publicDeliveryGetSettleTickers(this.extend(request, query));
        }
        else if (market['option']) {
            const marketId = market['id'];
            const optionParts = marketId.split('-');
            request['underlying'] = this.safeString(optionParts, 0);
            response = await this.publicOptionsGetTickers(this.extend(request, query));
        }
        else {
            throw new errors.NotSupported(this.id + ' fetchTicker() not support this market type');
        }
        let ticker = undefined;
        if (market['option']) {
            for (let i = 0; i < response.length; i++) {
                const entry = response[i];
                if (entry['name'] === market['id']) {
                    ticker = entry;
                    break;
                }
            }
        }
        else {
            ticker = this.safeValue(response, 0);
        }
        return this.parseTicker(ticker, market);
    }
    parseTicker(ticker, market = undefined) {
        //
        // SPOT
        //
        //     {
        //         "currency_pair": "KFC_USDT",
        //         "last": "7.255",
        //         "lowest_ask": "7.298",
        //         "highest_bid": "7.218",
        //         "change_percentage": "-1.18",
        //         "base_volume": "1219.053687865",
        //         "quote_volume": "8807.40299875455",
        //         "high_24h": "7.262",
        //         "low_24h": "7.095"
        //     }
        //
        // LINEAR/DELIVERY
        //
        //     {
        //         "contract": "BTC_USDT",
        //         "last": "6432",
        //         "low_24h": "6278",
        //         "high_24h": "6790",
        //         "change_percentage": "4.43",
        //         "total_size": "32323904",
        //         "volume_24h": "184040233284",
        //         "volume_24h_btc": "28613220",
        //         "volume_24h_usd": "184040233284",
        //         "volume_24h_base": "28613220",
        //         "volume_24h_quote": "184040233284",
        //         "volume_24h_settle": "28613220",
        //         "mark_price": "6534",
        //         "funding_rate": "0.0001",
        //         "funding_rate_indicative": "0.0001",
        //         "index_price": "6531"
        //     }
        //
        // bookTicker
        //    {
        //        "t": 1671363004228,
        //        "u": 9793320464,
        //        "s": "BTC_USDT",
        //        "b": "16716.8", // best bid price
        //        "B": "0.0134", // best bid size
        //        "a": "16716.9", // best ask price
        //        "A": "0.0353" // best ask size
        //     }
        //
        // option
        //
        //     {
        //         "vega": "0.00002",
        //         "leverage": "12.277188268663",
        //         "ask_iv": "0",
        //         "delta": "-0.99999",
        //         "last_price": "0",
        //         "theta": "-0.00661",
        //         "bid1_price": "1096",
        //         "mark_iv": "0.7799",
        //         "name": "BTC_USDT-20230608-28500-P",
        //         "bid_iv": "0",
        //         "ask1_price": "2935",
        //         "mark_price": "2147.3",
        //         "position_size": 0,
        //         "bid1_size": 12,
        //         "ask1_size": -14,
        //         "gamma": "0"
        //     }
        //
        const marketId = this.safeStringN(ticker, ['currency_pair', 'contract', 'name']);
        const marketType = ('mark_price' in ticker) ? 'contract' : 'spot';
        const symbol = this.safeSymbol(marketId, market, '_', marketType);
        const last = this.safeString2(ticker, 'last', 'last_price');
        const ask = this.safeStringN(ticker, ['lowest_ask', 'a', 'ask1_price']);
        const bid = this.safeStringN(ticker, ['highest_bid', 'b', 'bid1_price']);
        const high = this.safeString(ticker, 'high_24h');
        const low = this.safeString(ticker, 'low_24h');
        const bidVolume = this.safeString2(ticker, 'B', 'bid1_size');
        const askVolume = this.safeString2(ticker, 'A', 'ask1_size');
        const timestamp = this.safeInteger(ticker, 't');
        let baseVolume = this.safeString2(ticker, 'base_volume', 'volume_24h_base');
        if (baseVolume === 'nan') {
            baseVolume = '0';
        }
        let quoteVolume = this.safeString2(ticker, 'quote_volume', 'volume_24h_quote');
        if (quoteVolume === 'nan') {
            quoteVolume = '0';
        }
        const percentage = this.safeString(ticker, 'change_percentage');
        return this.safeTicker({
            'symbol': symbol,
            'timestamp': timestamp,
            'datetime': this.iso8601(timestamp),
            'high': high,
            'low': low,
            'bid': bid,
            'bidVolume': bidVolume,
            'ask': ask,
            'askVolume': askVolume,
            'vwap': undefined,
            'open': undefined,
            'close': last,
            'last': last,
            'previousClose': undefined,
            'change': undefined,
            'percentage': percentage,
            'average': undefined,
            'baseVolume': baseVolume,
            'quoteVolume': quoteVolume,
            'markPrice': this.safeString(ticker, 'mark_price'),
            'indexPrice': this.safeString(ticker, 'index_price'),
            'info': ticker,
        }, market);
    }
    /**
     * @method
     * @name gate#fetchTickers
     * @description fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market
     * @see https://www.gate.io/docs/developers/apiv4/en/#get-details-of-a-specifc-order
     * @see https://www.gate.io/docs/developers/apiv4/en/#list-futures-tickers
     * @see https://www.gate.io/docs/developers/apiv4/en/#list-futures-tickers-2
     * @see https://www.gate.io/docs/developers/apiv4/en/#list-tickers-of-options-contracts
     * @param {string[]|undefined} 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
     * @returns {object} a dictionary of [ticker structures]{@link https://docs.ccxt.com/#/?id=ticker-structure}
     */
    async fetchTickers(symbols = undefined, params = {}) {
        await this.loadMarkets();
        symbols = this.marketSymbols(symbols);
        const first = this.safeString(symbols, 0);
        let market = undefined;
        if (first !== undefined) {
            market = this.market(first);
        }
        const [type, query] = this.handleMarketTypeAndParams('fetchTickers', market, params);
        const [request, requestParams] = this.prepareRequest(undefined, type, query);
        let response = undefined;
        request['timezone'] = 'utc0'; // default to utc
        if (type === 'spot' || type === 'margin') {
            response = await this.publicSpotGetTickers(this.extend(request, requestParams));
        }
        else if (type === 'swap') {
            response = await this.publicFuturesGetSettleTickers(this.extend(request, requestParams));
        }
        else if (type === 'future') {
            response = await this.publicDeliveryGetSettleTickers(this.extend(request, requestParams));
        }
        else if (type === 'option') {
            this.checkRequiredArgument('fetchTickers', symbols, 'symbols');
            const marketId = market['id'];
            const optionParts = marketId.split('-');
            request['underlying'] = this.safeString(optionParts, 0);
            response = await this.publicOptionsGetTickers(this.extend(request, requestParams));
        }
        else {
            throw new errors.NotSupported(this.id + ' fetchTickers() not support this market type, provide symbols or set params["defaultType"] to one from spot/margin/swap/future/option');
        }
        return this.parseTickers(response, symbols);
    }
    parseBalanceHelper(entry) {
        const account = this.account();
        account['used'] = this.safeString2(entry, 'freeze', 'locked');
        account['free'] = this.safeString(entry, 'available');
        account['total'] = this.safeString(entry, 'total');
        if ('borrowed' in entry) {
            account['debt'] = this.safeString(entry, 'borrowed');
        }
        return account;
    }
    /**
     * @method
     * @name gate#fetchBalance
     * @param {object} [params] exchange specific parameters
     * @param {string} [params.type] spot, margin, swap or future, if not provided this.options['defaultType'] is used
     * @param {string} [params.settle] 'btc' or 'usdt' - settle currency for perpetual swap and future - default="usdt" for swap and "btc" for future
     * @param {string} [params.marginMode] 'cross' or 'isolated' - marginMode for margin trading if not provided this.options['defaultMarginMode'] is used
     * @param {string} [params.symbol] margin only - unified ccxt symbol
     * @param {boolean} [params.unifiedAccount] default false, set to true for fetching the unified account balance
     * @returns {object} a [balance structure]{@link https://docs.ccxt.com/#/?id=balance-structure}
     */
    async fetchBalance(params = {}) {
        await this.loadMarkets();
        await this.loadUnifiedStatus();
        const symbol = this.safeString(params, 'symbol');
        params = this.omit(params, 'symbol');
        let isUnifiedAccount = false;
        [isUnifiedAccount, params] = this.handleOptionAndParams(params, 'fetchBalance', 'unifiedAccount');
        const [type, query] = this.handleMarketTypeAndParams('fetchBalance', undefined, params);
        const [request, requestParams] = this.prepareRequest(undefined, type, query);
        const [marginMode, requestQuery] = this.getMarginMode(false, requestParams);
        if (symbol !== undefined) {
            const market = this.market(symbol);
            request['currency_pair'] = market['id'];
        }
        let response = undefined;
        if (isUnifiedAccount) {
            response = await this.privateUnifiedGetAccounts(this.extend(request, params));
        }
        else if (type === 'spot') {
            if (marginMode === 'spot') {
                response = await this.privateSpotGetAccounts(this.extend(request, requestQuery));
            }
            else if (marginMode === 'margin') {
                response = await this.privateMarginGetAccounts(this.extend(request, requestQuery));
            }
            else if (marginMode === 'cross_margin') {
                response = await this.privateMarginGetCrossAccounts(this.extend(request, requestQuery));
            }
            else {
                throw new errors.NotSupported(this.id + ' fetchBalance() not support this marginMode');
            }
        }
        else if (type === 'funding') {
            response = await this.privateMarginGetFundingAccounts(this.extend(request, requestQuery));
        }
        else if (type === 'swap') {
            response = await this.privateFuturesGetSettleAccounts(this.extend(request, requestQuery));
        }
        else if (type === 'future') {
            response = await this.privateDeliveryGetSettleAccounts(this.extend(request, requestQuery));
        }
        else if (type === 'option') {
            response = await this.privateOptionsGetAccounts(this.extend(request, requestQuery));
        }
        else {
            throw new errors.NotSupported(this.id + ' fetchBalance() not support this market type');
        }
        const contract = ((type === 'swap') || (type === 'future') || (type === 'option'));
        if (contract) {
            response = [response];
        }
        //
        // Spot / margin funding
        //
        //     [
        //         {
        //             "currency": "DBC",
        //             "available": "0",
        //             "locked": "0"
        //             "lent": "0", // margin funding only
        //             "total_lent": "0" // margin funding only
        //         },
        //         ...
        //     ]
        //
        //  Margin
        //
        //    [
        //        {
        //            "currency_pair": "DOGE_USDT",
        //            "locked": false,
        //            "risk": "9999.99",
        //            "base": {
        //                "currency": "DOGE",
        //                "available": "0",
        //                "locked": "0",
        //                "borrowed": "0",
        //                "interest": "0"
        //            },
        //            "quote": {
        //                "currency": "USDT",
        //                "available": "0.73402",
        //                "locked": "0",
        //                "borrowed": "0",
        //                "interest": "0"
        //            }
        //        },
        //        ...
        //    ]
        //
        // Cross margin
        //
        //    {
        //        "user_id": 10406147,
        //        "locked": false,
        //        "balances": {
        //            "USDT": {
        //                "available": "1",
        //                "freeze": "0",
        //                "borrowed": "0",
        //                "interest": "0"
        //            }
        //        },
        //        "total": "1",
        //        "borrowed": "0",
        //        "interest": "0",
        //        "risk": "9999.99"
        //    }
        //
        //  Perpetual Swap
        //
        //    {
        //        "order_margin": "0",
        //        "point": "0",
        //        "bonus": "0",
        //        "history": {
        //            "dnw": "2.1321",
        //            "pnl": "11.5351",
        //            "refr": "0",
        //            "point_fee": "0",
        //            "fund": "-0.32340576684",
        //            "bonus_dnw": "0",
        //            "point_refr": "0",
        //            "bonus_offset": "0",
        //            "fee": "-0.20132775",
        //            "point_dnw": "0",
        //        },
        //        "unrealised_pnl": "13.315100000006",
        //        "total": "12.51345151332",
        //        "available": "0",
        //        "in_dual_mode": false,
        //        "currency": "USDT",
        //        "position_margin": "12.51345151332",
        //        "user": "6333333",
        //    }
        //
        // Delivery Future
        //
        //    {
        //        "order_margin": "0",
        //        "point": "0",
        //        "history": {
        //            "dnw": "1",
        //            "pnl": "0",
        //            "refr": "0",
        //            "point_fee": "0",
        //            "point_dnw": "0",
        //            "settle": "0",
        //            "settle_fee": "0",
        //            "point_refr": "0",
        //            "fee": "0",
        //        },
        //        "unrealised_pnl": "0",
        //        "total": "1",
        //        "available": "1",
        //        "currency": "USDT",
        //        "position_margin": "0",
        //        "user": "6333333",
        //    }
        //
        // option
        //
        //     {
        //         "order_margin": "0",
        //         "bid_order_margin": "0",
        //         "init_margin": "0",
        //         "history": {
        //             "dnw": "32",
        //             "set": "0",
        //             "point_fee": "0",
        //             "point_dnw": "0",
        //             "prem": "0",
        //             "point_refr": "0",
        //             "insur": "0",
        //             "fee": "0",
        //             "refr": "0"
        //         },
        //         "total": "32",
        //         "available": "32",
        //         "liq_triggered": false,
        //         "maint_margin": "0",
        //         "ask_order_margin": "0",
        //         "point": "0",
        //         "position_notional_limit": "2000000",
        //         "unrealised_pnl": "0",
        //         "equity": "32",
        //         "user": 5691076,
        //         "currency": "USDT",
        //         "short_enabled": false,
        //         "orders_limit": 10
        //     }
        //
        // unified
        //
        //     {
        //         "user_id": 10001,
        //         "locked": false,
        //         "balances": {
        //             "ETH": {
        //                 "available": "0",
        //                 "freeze": "0",
        //                 "borrowed": "0.075393666654",
        //                 "negative_liab": "0",
        //                 "futures_pos_liab": "0",
        //                 "equity": "1016.1",
        //                 "total_freeze": "0",
        //                 "total_liab": "0"
        //             },
        //             "POINT": {
        //                 "available": "9999999999.017023138734",
        //                 "freeze": "0",
        //                 "borrowed": "0",
        //                 "negative_liab": "0",
        //                 "futures_pos_liab": "0",
        //                 "equity": "12016.1",
        //                 "total_freeze": "0",
        //                 "total_liab": "0"
        //             },
        //             "USDT": {
        //                 "available": "0.00000062023",
        //                 "freeze": "0",
        //                 "borrowed": "0",
        //                 "negative_liab": "0",
        //                 "futures_pos_liab": "0",
        //                 "equity": "16.1",
        //                 "total_freeze": "0",
        //                 "total_liab": "0"
        //             }
        //         },
        //         "total": "230.94621713",
        //         "borrowed": "161.66395521",
        //         "total_initial_margin": "1025.0524665088",
        //         "total_margin_balance": "3382495.944473949183",
        //         "total_maintenance_margin": "205.01049330176",
        //         "total_initial_margin_rate": "3299.827135672679",
        //         "total_maintenance_margin_rate": "16499.135678363399",
        //         "total_available_margin": "3381470.892007440383",
        //         "unified_account_total": "3381470.892007440383",
        //         "unified_account_total_liab": "0",
        //         "unified_account_total_equity": "100016.1",
        //         "leverage": "2"
        //     }
        //
        const result = {
            'info': response,
        };
        const isolated = marginMode === 'margin';
        let data = response;
        if ('balances' in data) { // True for cross_margin and unified
            const flatBalances = [];
            const balances = this.safeValue(data, 'balances', []);
            // inject currency and create an artificial balance object
            // so it can follow the existent flow
            const keys = Object.keys(balances);
            for (let i = 0; i < keys.length; i++) {
                const currencyId = keys[i];
                const content = balances[currencyId];
                content['currency'] = currencyId;
                flatBalances.push(content);
            }
            data = flatBalances;
        }
        for (let i = 0; i < data.length; i++) {
            const entry = data[i];
            if (isolated) {
                const marketId = this.safeString(entry, 'currency_pair');
                const symbolInner = this.safeSymbol(marketId, undefined, '_', 'margin');
                const base = this.safeValue(entry, 'base', {});
                const quote = this.safeValue(entry, 'quote', {});
                const baseCode = this.safeCurrencyCode(this.safeString(base, 'currency'));
                const quoteCode = this.safeCurrencyCode(this.safeString(quote, 'currency'));
                const subResult = {};
                subResult[baseCode] = this.parseBalanceHelper(base);
                subResult[quoteCode] = this.parseBalanceHelper(quote);
                result[symbolInner] = this.safeBalance(subResult);
            }
            else {
                const code = this.safeCurrencyCode(this.safeString(entry, 'currency'));
                result[code] = this.parseBalanceHelper(entry);
            }
        }
        const returnResult = isolated ? result : this.safeBalance(result);
        return returnResult;
    }
    /**
     * @method
     * @name gateio#fetchOHLCV
     * @description fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
     * @see https://www.gate.io/docs/developers/apiv4/en/#market-candlesticks       // spot
     * @see https://www.gate.io/docs/developers/apiv4/en/#get-futures-candlesticks  // swap
     * @see https://www.gate.io/docs/developers/apiv4/en/#market-candlesticks       // future
     * @see https://www.gate.io/docs/developers/apiv4/en/#get-options-candlesticks  // option
     * @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, limit is conflicted with since and params["until"], If either since and params["until"] is specified, request will be rejected
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @param {string} [params.price] "mark" or "index" for mark price and index price candles
     * @param {int} [params.until] timestamp in ms of the latest candle to fetch
     * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling 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 (units in quote currency)
     */
    async fetchOHLCV(symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
        await this.loadMarkets();
        const market = this.market(symbol);
        let paginate = false;
        [paginate, params] = this.handleOptionAndParams(params, 'fetchOHLCV', 'paginate');
        if (paginate) {
            return await this.fetchPaginatedCallDeterministic('fetchOHLCV', symbol, since, limit, timeframe, params, 1000);
        }
        if (market['option']) {
            return await this.fetchOptionOHLCV(symbol, timeframe, since, limit, params);
        }
        const price = this.safeString(params, 'price');
        let request = {};
        [request, params] = this.prepareRequest(market, undefined, params);
        request['interval'] = this.safeString(this.timeframes, timeframe, timeframe);
        const maxLimit = market['contract'] ? 1999 : 1000;
        limit = (limit === undefined) ? maxLimit : Math.min(limit, maxLimit);
        let until = this.safeInteger(params, 'until');
        if (until !== undefined) {
            until = this.parseToInt(until / 1000);
            params = this.omit(params, 'until');
        }
        if (since !== undefined) {
            const duration = this.parseTimeframe(timeframe);
            request['from'] = this.parseToInt(since / 1000);
            const distance = (limit - 1) * duration;
            const toTimestamp = this.sum(request['from'], distance);
            const currentTimestamp = this.seconds();
            const to = Math.min(toTimestamp, currentTimestamp);
            if (until !== undefined) {
                request['to'] = Math.min(to, until);
            }
            else {
                request['to'] = to;
            }
        }
        else {
            if (until !== undefined) {
                request['to'] = until;
            }
            request['limit'] = limit;
        }
        let response = undefined;
        if (market['contract']) {
            const isMark = (price === 'mark');
            const isIndex = (price === 'index');
            if (isMark || isIndex) {
                request['contract'] = price + '_' + market['id'];
                params = this.omit(params, 'price');
            }
            if (market['future']) {
                response = await this.publicDeliveryGetSettleCandlesticks(this.extend(request, params));
            }
            else if (market['swap']) {
                response = await this.publicFuturesGetSettleCandlesticks(this.extend(request, params));
            }
        }
        else {
            response = await this.publicSpotGetCandlesticks(this.extend(request, params));
        }
        return this.parseOHLCVs(response, market, timeframe, since, limit);
    }
    async fetchOptionOHLCV(symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
        // separated option logic because the from, to and limit parameters weren't functioning
        await this.loadMarkets();
        const market = this.market(symbol);
        let request = {};
        [request, params] = this.prepareRequest(market, undefined, params);
        request['interval'] = this.safeString(this.timeframes, timeframe, timeframe);
        const response = await this.publicOptionsGetCandlesticks(this.extend(request, params));
        return this.parseOHLCVs(response, market, timeframe, since, limit);
    }
    /**
     * @method
     * @name gate#fetchFundingRateHistory
     * @description fetches historical funding rate prices
     * @see https://www.gate.io/docs/developers/apiv4/en/#funding-rate-history
     * @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 to fetch
     * @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 [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);
        }
        const market = this.market(symbol);
        if (!market['swap']) {
            throw new errors.BadSymbol(this.id + ' fetchFundingRateHistory() supports swap contracts only');
        }
        let request = {};
        [request, params] = this.prepareRequest(market, undefined, params);
        if (limit !== undefined) {
            request['limit'] = limit;
        }
        if (since !== undefined) {
            request['from'] = this.parseToInt(since / 1000);
        }
        const until = this.safeInteger(params, 'until');
        if (until !== undefined) {
            params = this.omit(params, 'until');
            request['to'] = this.parseToInt(until / 1000);
        }
        const response = await this.publicFuturesGetSettleFundingRate(this.extend(request, params));
        //
        //     {
        //         "r": "0.00063521",
        //         "t": "1621267200000",
        //     }
        //
        const rates = [];
        for (let i = 0; i < response.length; i++) {
            const entry = response[i];
            const timestamp = this.safeTimestamp(entry, 't');
            rates.push({
                'info': entry,
                'symbol': symbol,
                'fundingRate': this.safeNumber(entry, 'r'),
                'timestamp': timestamp,
                'datetime': this.iso8601(timestamp),
            });
        }
        const sorted = this.sortBy(rates, 'timestamp');
        return this.filterBySymbolSinceLimit(sorted, market['symbol'], since, limit);
    }
    parseOHLCV(ohlcv, market = undefined) {
        //
        // Spot market candles
        //
        //    [
        //        "1660957920", // timestamp
        //        "6227.070147198573", // quote volume
        //        "0.0000133485", // close
        //        "0.0000133615", // high
        //        "0.0000133347", // low
        //        "0.0000133468", // open
        //        "466641934.99" // base volume
        //    ]
        //
        //
        // Swap, Future, Option, Mark and Index price candles
        //
        //     {
        //          "t":1632873600,         // Unix timestamp in seconds
        //          "o": "41025",           // Open price
        //          "h": "41882.17",        // Highest price
        //          "c": "41776.92",        // Close price
        //          "l": "40783.94"         // Lowest price
        //     }
        //
        if (Array.isArray(ohlcv)) {
            return [
                this.safeTimestamp(ohlcv, 0),
                this.safeNumber(ohlcv, 5),
                this.safeNumber(ohlcv, 3),
                this.safeNumber(ohlcv, 4),
                this.safeNumber(ohlcv, 2),
                this.safeNumber(ohlcv, 6), // trading volume
            ];
        }
        else {
            // Swap, Future, Option, Mark and Index price candles
            return [
                this.safeTimestamp(ohlcv, 't'),
                this.safeNumber(ohlcv, 'o'),
                this.safeNumber(ohlcv, 'h'),
                this.safeNumber(ohlcv, 'l'),
                this.safeNumber(ohlcv, 'c'),
                this.safeNumber(ohlcv, 'v'), // trading volume, undefined for mark or index price
            ];
        }
    }
    /**
     * @method
     * @name gate#fetchTrades
     * @description get the list of most recent trades for a particular symbol
     * @see https://www.gate.io/docs/developers/apiv4/en/#retrieve-market-trades
     * @see https://www.gate.io/docs/developers/apiv4/en/#futures-trading-history
     * @see https://www.gate.io/docs/developers/apiv4/en/#futures-trading-history-2
     * @see https://www.gate.io/docs/developers/apiv4/en/#options-trade-history
     * @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 {int} [params.until] timestamp in ms of the latest trade to fetch
     * @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=public-trades}
     */
    async fetchTrades(symbol, since = undefined, limit = undefined, params = {}) {
        await this.loadMarkets();
        let paginate = false;
        [paginate, params] = this.handleOptionAndParams(params, 'fetchTrades', 'paginate');
        if (paginate) {
            return await this.fetchPaginatedCallDynamic('fetchTrades', symbol, since, limit, params);
        }
        const market = this.market(symbol);
        //
        // spot
        //
        //     const request: Dict = {
        //         'currency_pair': market['id'],
        //         'limit': limit, // maximum number of records to be returned in a single list
        //         'last_id': 'id', // specify list staring point using the id of last record in previous list-query results
        //         'reverse': false, // true to retrieve records where id is smaller than the specified last_id, false to retrieve records where id is larger than the specified last_id
        //     };
        //
        // swap, future
        //
        //     const request: Dict = {
        //         'settle': market['settleId'],
        //         'contract': market['id'],
        //         'limit': limit, // maximum number of records to be returned in a single list
        //         'last_id': 'id', // specify list staring point using the id of last record in previous list-query results
        //         'from': since / 1000), // starting time in seconds, if not specified, to and limit will be used to limit response items
        //         'to': this.seconds (), // end time in seconds, default to current time
        //     };
        //
        const [request, query] = this.prepareRequest(market, undefined, params);
        const until = this.safeInteger2(params, 'to', 'until');
        if (until !== undefined) {
            params = this.omit(params, ['until']);
            request['to'] = this.parseToInt(until / 1000);
        }
        if (limit !== undefined) {
            request['limit'] = Math.min(limit, 1000); // default 100, max 1000
        }
        if (since !== undefined && (market['contract'])) {
            request['from'] = this.parseToInt(since / 1000);
        }
        let response = undefined;
        if (market['type'] === 'spot' || market['type'] === 'margin') {
            response = await this.publicSpotGetTrades(this.extend(request, query));
        }
        else if (market['swap']) {
            response = await this.publicFuturesGetSettleTrades(this.extend(request, query));
        }
        else if (market['future']) {
            response = await this.publicDeliveryGetSettleTrades(this.extend(request, query));
        }
        else if (market['type'] === 'option') {
            response = await this.publicOptionsGetTrades(this.extend(request, query));
        }
        else {
            throw new errors.NotSupported(this.id + ' fetchTrades() not support this market type.');
        }
        //
        // spot
        //
        //     [
        //         {
        //             "id": "1852958144",
        //             "create_time": "1634673259",
        //             "create_time_ms": "1634673259378.105000",
        //             "currency_pair": "ADA_USDT",
        //             "side": "sell",
        //             "amount": "307.078",
        //             "price": "2.104",
        //         }
        //     ]
        //
        // perpetual swap
        //
        //     [
        //         {
        //              "size": "2",
        //              "id": "2522911",
        //              "create_time_ms": "1634673380.182",
        //              "create_time": "1634673380.182",
        //              "contract": "ADA_USDT",
        //              "price": "2.10486",
        //         }
        //     ]
        //
        // option
        //
        //     [
        //         {
        //             "size": -5,
        //             "id": 25,
        //             "create_time": 1682378573,
        //             "contract": "ETH_USDT-20230526-2000-P",
        //             "price": "209.1"
        //         }
        //     ]
        //
        return this.parseTrades(response, market, since, limit);
    }
    /**
     * @method
     * @name gate#fetchOrderTrades
     * @description fetch all the trades made from a single order
     * @see https://www.gate.io/docs/developers/apiv4/en/#list-personal-trading-history
     * @see https://www.gate.io/docs/developers/apiv4/en/#list-personal-trading-history-2
     * @see https://www.gate.io/docs/developers/apiv4/en/#list-personal-trading-history-3
     * @see https://www.gate.io/docs/developers/apiv4/en/#list-personal-trading-history-4
     * @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 = {}) {
        if (symbol === undefined) {
            throw new errors.ArgumentsRequired(this.id + ' fetchOrderTrades() requires a symbol argument');
        }
        await this.loadMarkets();
        //
        //      [
        //          {
        //              "id":"3711449544",
        //              "create_time":"1655486040",
        //              "create_time_ms":"1655486040177.599900",
        //              "currency_pair":"SHIB_USDT",
        //              "side":"buy",
        //              "role":"taker",
        //              "amount":"1360039",
        //              "price":"0.0000081084",
        //              "order_id":"169717399644",
        //              "fee":"2720.078",
        //              "fee_currency":"SHIB",
        //              "point_fee":"0",
        //              "gt_fee":"0"
        //          }
        //      ]
        //
        const response = await this.fetchMyTrades(symbol, since, limit, { 'order_id': id });
        return response;
    }
    /**
     * @method
     * @name gate#fetchMyTrades
     * @description Fetch personal trading history
     * @see https://www.gate.io/docs/developers/apiv4/en/#list-personal-trading-history
     * @see https://www.gate.io/docs/developers/apiv4/en/#list-personal-trading-history-2
     * @see https://www.gate.io/docs/developers/apiv4/en/#list-personal-trading-history-3
     * @see https://www.gate.io/docs/developers/apiv4/en/#list-personal-trading-history-4
     * @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.marginMode] 'cross' or 'isolated' - marginMode for margin trading if not provided this.options['defaultMarginMode'] is used
     * @param {string} [params.type] 'spot', 'swap', or 'future', if not provided this.options['defaultMarginMode'] is used
     * @param {int} [params.until] The latest timestamp, in ms, that fetched trades were made
     * @param {int} [params.page] *spot only* Page number
     * @param {string} [params.order_id] *spot only* Filter trades with specified order ID. symbol is also required if this field is present
     * @param {string} [params.order] *contract only* Futures order ID, return related data only if specified
     * @param {int} [params.offset] *contract only* list offset, starting from 0
     * @param {string} [params.last_id] *contract only* specify list staring point using the id of last record in previous list-query results
     * @param {int} [params.count_total] *contract only* whether to return total number matched, default to 0(no return)
     * @param {bool} [params.unifiedAccount] set to true for fetching trades in a unified account
     * @param {bool} [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 {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();
        await this.loadUnifiedStatus();
        let paginate = false;
        [paginate, params] = this.handleOptionAndParams(params, 'fetchMyTrades', 'paginate');
        if (paginate) {
            return await this.fetchPaginatedCallDynamic('fetchMyTrades', symbol, since, limit, params);
        }
        let type = undefined;
        let marginMode = undefined;
        let request = {};
        const market = (symbol !== undefined) ? this.market(symbol) : undefined;
        const until = this.safeInteger(params, 'until');
        params = this.omit(params, ['until']);
        [type, params] = this.handleMarketTypeAndParams('fetchMyTrades', market, params);
        const contract = (type === 'swap') || (type === 'future') || (type === 'option');
        if (contract) {
            [request, params] = this.prepareRequest(market, type, params);
            if (type === 'option') {
                params = this.omit(params, 'order_id');
            }
        }
        else {
            if (market !== undefined) {
                request['currency_pair'] = market['id']; // Should always be set for non-trigger
            }
            [marginMode, params] = this.getMarginMode(false, params);
            request['account'] = marginMode;
        }
        if (limit !== undefined) {
            request['limit'] = limit; // default 100, max 1000
        }
        if (since !== undefined) {
            request['from'] = this.parseToInt(since / 1000);
        }
        if (until !== undefined) {
            request['to'] = this.parseToInt(until / 1000);
        }
        let response = undefined;
        if (type === 'spot' || type === 'margin') {
            response = await this.privateSpotGetMyTrades(this.extend(request, params));
        }
        else if (type === 'swap') {
            response = await this.privateFuturesGetSettleMyTradesTimerange(this.extend(request, params));
        }
        else if (type === 'future') {
            response = await this.privateDeliveryGetSettleMyTrades(this.extend(request, params));
        }
        else if (type === 'option') {
            response = await this.privateOptionsGetMyTrades(this.extend(request, params));
        }
        else {
            throw new errors.NotSupported(this.id + ' fetchMyTrades() not support this market type.');
        }
        //
        // spot
        //
        //     [
        //         {
        //             "id": "2876130500",
        //             "create_time": "1645464610",
        //             "create_time_ms": "1645464610777.399200",
        //             "currency_pair": "DOGE_USDT",
        //             "side": "sell",
        //             "role": "taker",
        //             "amount": "10.97",
        //             "price": "0.137384",
        //             "order_id": "125924049993",
        //             "fee": "0.00301420496",
        //             "fee_currency": "USDT",
        //             "point_fee": "0",
        //             "gt_fee": "0"
        //         }
        //     ]
        //
        // perpetual swap
        //
        //     [
        //         {
        //             "size": -5,
        //             "order_id": "130264979823",
        //             "id": 26884791,
        //             "role": "taker",
        //             "create_time": 1645465199.5472,
        //             "contract": "DOGE_USDT",
        //             "price": "0.136888"
        //         }
        //     ]
        //
        // future
        //
        //     [
        //         {
        //             "id": 121234231,
        //             "create_time": 1514764800.123,
        //             "contract": "BTC_USDT",
        //             "order_id": "21893289839",
        //             "size": 100,
        //             "price": "100.123",
        //             "role": "taker"
        //         }
        //     ]
        //
        // option
        //
        //     [
        //         {
        //             "underlying_price": "26817.84",
        //             "size": -1,
        //             "contract": "BTC_USDT-20230602-26500-C",
        //             "id": 16,
        //             "role": "taker",
        //             "create_time": 1685594770,
        //             "order_id": 2611026125,
        //             "price": "333"
        //         }
        //     ]
        //
        return this.parseTrades(response, market, since, limit);
    }
    parseTrade(trade, market = undefined) {
        //
        // public
        //
        //  spot:
        //     {
        //         "id": "1334253759",
        //         "create_time": "1626342738",
        //         "create_time_ms": "1626342738331.497000",
        //         "currency_pair": "BTC_USDT",
        //         "side": "sell",
        //         "amount": "0.0022",
        //         "price": "32452.16"
        //     }
        //
        //  swap:
        //
        //    {
        //        "id": "442288327",
        //        "contract": "BTC_USDT",
        //        "create_time": "1739814676.707",
        //        "create_time_ms": "1739814676.707",
        //        "size": "-105",
        //        "price": "95594.8"
        //    }
        //
        //
        // public ws
        //
        //     {
        //         "id": 221994511,
        //         "time": 1580311438.618647,
        //         "price": "9309",
        //         "amount": "0.0019",
        //         "type": "sell"
        //     }
        //
        // spot rest
        //
        //     {
        //         "id": "2876130500",
        //         "create_time": "1645464610",
        //         "create_time_ms": "1645464610777.399200",
        //         "currency_pair": "DOGE_USDT",
        //         "side": "sell",
        //         "role": "taker",
        //         "amount": "10.97",
        //         "price": "0.137384",
        //         "order_id": "125924049993",
        //         "fee": "0.00301420496",
        //         "fee_currency": "USDT",
        //         "point_fee": "1.1",
        //         "gt_fee":"2.2"
        //     }
        //
        // perpetual swap rest
        //
        //     {
        //         "size": -5,
        //         "order_id": "130264979823",
        //         "id": 26884791,
        //         "role": "taker",
        //         "create_time": 1645465199.5472,
        //         "contract": "DOGE_USDT",
        //         "price": "0.136888"
        //     }
        //
        // future rest
        //
        //     {
        //         "id": 121234231,
        //         "create_time": 1514764800.123,
        //         "contract": "BTC_USDT",
        //         "order_id": "21893289839",
        //         "size": 100,
        //         "price": "100.123",
        //         "role": "taker"
        //     }
        //
        // fetchTrades: option
        //
        //     {
        //         "size": -5,
        //         "id": 25,
        //         "create_time": 1682378573,
        //         "contract": "ETH_USDT-20230526-2000-P",
        //         "price": "209.1"
        //     }
        //
        // fetchMyTrades: option
        //
        //     {
        //         "underlying_price": "26817.84",
        //         "size": -1,
        //         "contract": "BTC_USDT-20230602-26500-C",
        //         "id": 16,
        //         "role": "taker",
        //         "create_time": 1685594770,
        //         "order_id": 2611026125,
        //         "price": "333"
        //     }
        //
        const id = this.safeString2(trade, 'id', 'trade_id');
        let timestamp = undefined;
        let msString = this.safeString(trade, 'create_time_ms');
        if (msString !== undefined) {
            msString = Precise["default"].stringMul(msString, '1000');
            msString = msString.slice(0, 13);
            timestamp = this.parseToInt(msString);
        }
        else {
            timestamp = this.safeTimestamp2(trade, 'time', 'create_time');
        }
        const marketId = this.safeString2(trade, 'currency_pair', 'contract');
        const marketType = ('contract' in trade) ? 'contract' : 'spot';
        market = this.safeMarket(marketId, market, '_', marketType);
        let amountString = this.safeString2(trade, 'amount', 'size');
        const priceString = this.safeString(trade, 'price');
        const contractSide = Precise["default"].stringLt(amountString, '0') ? 'sell' : 'buy';
        amountString = Precise["default"].stringAbs(amountString);
        const side = this.safeString2(trade, 'side', 'type', contractSide);
        const orderId = this.safeString(trade, 'order_id');
        const feeAmount = this.safeString(trade, 'fee');
        const gtFee = this.omitZero(this.safeString(trade, 'gt_fee'));
        const pointFee = this.omitZero(this.safeString(trade, 'point_fee'));
        const fees = [];
        if (feeAmount !== undefined) {
            const feeCurrencyId = this.safeString(trade, 'fee_currency');
            let feeCurrencyCode = this.safeCurrencyCode(feeCurrencyId);
            if (feeCurrencyCode === undefined) {
                feeCurrencyCode = this.safeString(market, 'settle');
            }
            fees.push({
                'cost': feeAmount,
                'currency': feeCurrencyCode,
            });
        }
        if (gtFee !== undefined) {
            fees.push({
                'cost': gtFee,
                'currency': 'GT',
            });
        }
        if (pointFee !== undefined) {
            fees.push({
                'cost': pointFee,
                'currency': 'GatePoint',
            });
        }
        const takerOrMaker = this.safeString(trade, 'role');
        return this.safeTrade({
            'info': trade,
            'id': id,
            'timestamp': timestamp,
            'datetime': this.iso8601(timestamp),
            'symbol': market['symbol'],
            'order': orderId,
            'type': undefined,
            'side': side,
            'takerOrMaker': takerOrMaker,
            'price': priceString,
            'amount': amountString,
            'cost': undefined,
            'fee': undefined,
            'fees': fees,
        }, market);
    }
    /**
     * @method
     * @name gate#fetchDeposits
     * @description fetch all deposits made to an account
     * @see https://www.gate.io/docs/developers/apiv4/en/#retrieve-deposit-records
     * @param {string} code unified currency code
     * @param {int} [since] the earliest time in ms to fetch deposits for
     * @param {int} [limit] the maximum number of deposits structures to retrieve
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @param {int} [params.until] end time in ms
     * @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 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.fetchPaginatedCallDynamic('fetchDeposits', code, since, limit, params);
        }
        let request = {};
        let currency = undefined;
        if (code !== undefined) {
            currency = this.currency(code);
            request['currency'] = currency['id']; // todo: currencies have network-junctions
        }
        if (limit !== undefined) {
            request['limit'] = limit;
        }
        if (since !== undefined) {
            const start = this.parseToInt(since / 1000);
            request['from'] = start;
            request['to'] = this.sum(start, 30 * 24 * 60 * 60);
        }
        [request, params] = this.handleUntilOption('to', request, params);
        const response = await this.privateWalletGetDeposits(this.extend(request, params));
        return this.parseTransactions(response, currency);
    }
    /**
     * @method
     * @name gate#fetchWithdrawals
     * @description fetch all withdrawals made from an account
     * @see https://www.gate.io/docs/developers/apiv4/en/#retrieve-withdrawal-records
     * @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] end time in ms
     * @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.fetchPaginatedCallDynamic('fetchWithdrawals', code, since, limit, params);
        }
        let request = {};
        let currency = undefined;
        if (code !== undefined) {
            currency = this.currency(code);
            request['currency'] = currency['id']; // todo: currencies have network-junctions
        }
        if (limit !== undefined) {
            request['limit'] = limit;
        }
        if (since !== undefined) {
            const start = this.parseToInt(since / 1000);
            request['from'] = start;
            request['to'] = this.sum(start, 30 * 24 * 60 * 60);
        }
        [request, params] = this.handleUntilOption('to', request, params);
        const response = await this.privateWalletGetWithdrawals(this.extend(request, params));
        return this.parseTransactions(response, currency);
    }
    /**
     * @method
     * @name gate#withdraw
     * @description make a withdrawal
     * @see https://www.gate.io/docs/developers/apiv4/en/#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);
        this.checkAddress(address);
        await this.loadMarkets();
        const currency = this.currency(code);
        const request = {
            'currency': currency['id'],
            'address': address,
            'amount': this.currencyToPrecision(code, amount),
        };
        if (tag !== undefined) {
            request['memo'] = tag;
        }
        let networkCode = undefined;
        [networkCode, params] = this.handleNetworkCodeAndParams(params);
        if (networkCode !== undefined) {
            request['chain'] = this.networkCodeToId(networkCode);
        }
        const response = await this.privateWithdrawalsPostWithdrawals(this.extend(request, params));
        //
        //    {
        //        "id": "w13389675",
        //        "currency": "USDT",
        //        "amount": "50",
        //        "address": "TUu2rLFrmzUodiWfYki7QCNtv1akL682p1",
        //        "memo": null
        //    }
        //
        return this.parseTransaction(response, currency);
    }
    parseTransactionStatus(status) {
        const statuses = {
            'PEND': 'pending',
            'REQUEST': 'pending',
            'DMOVE': 'pending',
            'MANUAL': 'pending',
            'VERIFY': 'pending',
            'PROCES': 'pending',
            'EXTPEND': 'pending',
            'SPLITPEND': 'pending',
            'CANCEL': 'canceled',
            'FAIL': 'failed',
            'INVALID': 'failed',
            'DONE': 'ok',
            'BCODE': 'ok', // GateCode withdrawal
        };
        return this.safeString(statuses, status, status);
    }
    parseTransactionType(type) {
        const types = {
            'd': 'deposit',
            'w': 'withdrawal',
        };
        return this.safeString(types, type, type);
    }
    parseTransaction(transaction, currency = undefined) {
        //
        // fetchDeposits
        //
        //     {
        //         "id": "d33361395",
        //         "currency": "USDT_TRX",
        //         "address": "TErdnxenuLtXfnMafLbfappYdHtnXQ5U4z",
        //         "amount": "100",
        //         "txid": "ae9374de34e558562fe18cbb1bf9ab4d9eb8aa7669d65541c9fa2a532c1474a0",
        //         "timestamp": "1626345819",
        //         "status": "DONE",
        //         "memo": ""
        //     }
        //
        // withdraw
        //
        //     {
        //         "id":"w64413318",
        //         "currency":"usdt",
        //         "amount":"10150",
        //         "address":"0x0ab891497116f7f5532a4c2f4f7b1784488628e1",
        //         "memo":null,
        //         "status":"REQUEST",
        //         "chain":"eth",
        //         "withdraw_order_id":"",
        //         "fee_amount":"4.15000000"
        //     }
        //
        // fetchWithdrawals
        //
        //     {
        //         "id": "210496",
        //         "timestamp": "1542000000",
        //         "withdraw_order_id": "order_123456",
        //         "currency": "USDT",
        //         "address": "1HkxtBAMrA3tP5ENnYY2CZortjZvFDH5Cs",
        //         "txid": "128988928203223323290",
        //         "block_number": "41575382",
        //         "amount": "222.61",
        //         "fee": "0.01",
        //         "memo": "",
        //         "status": "DONE",
        //         "chain": "TRX"
        //     }
        //
        //     {
        //         "id": "w13389675",
        //         "currency": "USDT",
        //         "amount": "50",
        //         "address": "TUu2rLFrmzUodiWfYki7QCNtv1akL682p1",
        //         "memo": null
        //     }
        //
        //     {
        //         "currency":"usdt",
        //         "address":"0x01c0A9b7b4CdE774AF0f3E47CB4f1c2CCdBa0806",
        //         "amount":"1880",
        //         "chain":"eth"
        //     }
        //
        const id = this.safeString(transaction, 'id');
        let type = undefined;
        let amountString = this.safeString(transaction, 'amount');
        if (id !== undefined) {
            if (id[0] === 'b') {
                // GateCode handling
                type = Precise["default"].stringGt(amountString, '0') ? 'deposit' : 'withdrawal';
                amountString = Precise["default"].stringAbs(amountString);
            }
            else {
                type = this.parseTransactionType(id[0]);
            }
        }
        const feeCostString = this.safeString2(transaction, 'fee', 'fee_amount');
        if (type === 'withdrawal') {
            amountString = Precise["default"].stringSub(amountString, feeCostString);
        }
        const networkId = this.safeStringUpper(transaction, 'chain');
        const currencyId = this.safeString(transaction, 'currency');
        const code = this.safeCurrencyCode(currencyId);
        const txid = this.safeString(transaction, 'txid');
        const rawStatus = this.safeString(transaction, 'status');
        const status = this.parseTransactionStatus(rawStatus);
        const address = this.safeString(transaction, 'address');
        const tag = this.safeString(transaction, 'memo');
        const timestamp = this.safeTimestamp(transaction, 'timestamp');
        return {
            'info': transaction,
            'id': id,
            'txid': txid,
            'currency': code,
            'amount': this.parseNumber(amountString),
            'network': this.networkIdToCode(networkId),
            'address': address,
            'addressTo': undefined,
            'addressFrom': undefined,
            'tag': tag,
            'tagTo': undefined,
            'tagFrom': undefined,
            'status': status,
            'type': type,
            'timestamp': timestamp,
            'datetime': this.iso8601(timestamp),
            'updated': undefined,
            'internal': undefined,
            'comment': undefined,
            'fee': {
                'currency': code,
                'cost': this.parseNumber(feeCostString),
            },
        };
    }
    /**
     * @method
     * @name gate#createOrder
     * @description Create an order on the exchange
     * @see https://www.gate.io/docs/developers/apiv4/en/#create-an-order
     * @see https://www.gate.io/docs/developers/apiv4/en/#create-a-price-triggered-order
     * @see https://www.gate.io/docs/developers/apiv4/en/#create-a-futures-order
     * @see https://www.gate.io/docs/developers/apiv4/en/#create-a-price-triggered-order-2
     * @see https://www.gate.io/docs/developers/apiv4/en/#create-a-futures-order-2
     * @see https://www.gate.io/docs/developers/apiv4/en/#create-a-price-triggered-order-3
     * @see https://www.gate.io/docs/developers/apiv4/en/#create-an-options-order
     * @param {string} symbol Unified CCXT market symbol
     * @param {string} type 'limit' or 'market' *"market" is contract only*
     * @param {string} side 'buy' or 'sell'
     * @param {float} amount the amount of currency to trade
     * @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 at which a trigger order is triggered at
     * @param {string} [params.timeInForce] "GTC", "IOC", or "PO"
     * @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 {string} [params.marginMode] 'cross' or 'isolated' - marginMode for margin trading if not provided this.options['defaultMarginMode'] is used
     * @param {int} [params.iceberg] Amount to display for the iceberg order, Null or 0 for normal orders, Set to -1 to hide the order completely
     * @param {string} [params.text] User defined information
     * @param {string} [params.account] *spot and margin only* "spot", "margin" or "cross_margin"
     * @param {bool} [params.auto_borrow] *margin only* Used in margin or cross margin trading to allow automatic loan of insufficient amount if balance is not enough
     * @param {string} [params.settle] *contract only* Unified Currency Code for settle currency
     * @param {bool} [params.reduceOnly] *contract only* Indicates if this order is to reduce the size of a position
     * @param {bool} [params.close] *contract only* Set as true to close the position, with size set to 0
     * @param {bool} [params.auto_size] *contract only* Set side to close dual-mode position, close_long closes the long side, while close_short the short one, size also needs to be set to 0
     * @param {int} [params.price_type] *contract only* 0 latest deal price, 1 mark price, 2 index price
     * @param {float} [params.cost] *spot market buy only* the quote quantity that can be used as an alternative for the amount
     * @param {bool} [params.unifiedAccount] set to true for creating an order in the unified account
     * @returns {object|undefined} [An order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
     */
    async createOrder(symbol, type, side, amount, price = undefined, params = {}) {
        await this.loadMarkets();
        await this.loadUnifiedStatus();
        const market = this.market(symbol);
        const trigger = this.safeValue(params, 'trigger');
        const triggerPrice = this.safeValue2(params, 'triggerPrice', 'stopPrice');
        const stopLossPrice = this.safeValue(params, 'stopLossPrice', triggerPrice);
        const takeProfitPrice = this.safeValue(params, 'takeProfitPrice');
        const isStopLossOrder = stopLossPrice !== undefined;
        const isTakeProfitOrder = takeProfitPrice !== undefined;
        const isTpsl = isStopLossOrder || isTakeProfitOrder;
        const nonTriggerOrder = !isTpsl && (trigger === undefined);
        const orderRequest = this.createOrderRequest(symbol, type, side, amount, price, params);
        let response = undefined;
        if (market['spot'] || market['margin']) {
            if (nonTriggerOrder) {
                response = await this.privateSpotPostOrders(orderRequest);
            }
            else {
                response = await this.privateSpotPostPriceOrders(orderRequest);
            }
        }
        else if (market['swap']) {
            if (nonTriggerOrder) {
                response = await this.privateFuturesPostSettleOrders(orderRequest);
            }
            else {
                response = await this.privateFuturesPostSettlePriceOrders(orderRequest);
            }
        }
        else if (market['future']) {
            if (nonTriggerOrder) {
                response = await this.privateDeliveryPostSettleOrders(orderRequest);
            }
            else {
                response = await this.privateDeliveryPostSettlePriceOrders(orderRequest);
            }
        }
        else {
            response = await this.privateOptionsPostOrders(orderRequest);
        }
        // const response = await this[method] (this.deepExtend (request, params));
        //
        // spot
        //
        //     {
        //         "id": "95282841887",
        //         "text": "apiv4",
        //         "create_time": "1637383156",
        //         "update_time": "1637383156",
        //         "create_time_ms": 1637383156017,
        //         "update_time_ms": 1637383156017,
        //         "status": "open",
        //         "currency_pair": "ETH_USDT",
        //         "type": "limit",
        //         "account": "spot",
        //         "side": "buy",
        //         "amount": "0.01",
        //         "price": "3500",
        //         "time_in_force": "gtc",
        //         "iceberg": "0",
        //         "left": "0.01",
        //         "fill_price": "0",
        //         "filled_total": "0",
        //         "fee": "0",
        //         "fee_currency": "ETH",
        //         "point_fee": "0",
        //         "gt_fee": "0",
        //         "gt_discount": false,
        //         "rebated_fee": "0",
        //         "rebated_fee_currency": "USDT"
        //     }
        //
        // spot conditional
        //
        //     {"id": 5891843}
        //
        // futures, perpetual swaps and options
        //
        //     {
        //         "id": 95938572327,
        //         "contract": "ETH_USDT",
        //         "mkfr": "0",
        //         "tkfr": "0.0005",
        //         "tif": "gtc",
        //         "is_reduce_only": false,
        //         "create_time": 1637384600.08,
        //         "price": "3000",
        //         "size": 1,
        //         "refr": "0",
        //         "left": 1,
        //         "text": "api",
        //         "fill_price": "0",
        //         "user": 2436035,
        //         "status": "open",
        //         "is_liq": false,
        //         "refu": 0,
        //         "is_close": false,
        //         "iceberg": 0
        //     }
        //
        // futures and perpetual swaps conditionals
        //
        //     {"id": 7615567}
        //
        return this.parseOrder(response, market);
    }
    createOrdersRequest(orders, params = {}) {
        const ordersRequests = [];
        const orderSymbols = [];
        const ordersLength = orders.length;
        if (ordersLength === 0) {
            throw new errors.BadRequest(this.id + ' createOrders() requires at least one order');
        }
        if (ordersLength > 10) {
            throw new errors.BadRequest(this.id + ' createOrders() accepts a maximum of 10 orders at a time');
        }
        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.safeValue(rawOrder, 'params', {});
            const extendedParams = this.extend(orderParams, params); // the request does not accept extra params since it's a list, so we're extending each order with the common params
            const triggerValue = this.safeValueN(orderParams, ['triggerPrice', 'stopPrice', 'takeProfitPrice', 'stopLossPrice']);
            if (triggerValue !== undefined) {
                throw new errors.NotSupported(this.id + ' createOrders() does not support advanced order properties (stopPrice, takeProfitPrice, stopLossPrice)');
            }
            extendedParams['textIsRequired'] = true; // Gate.io requires a text parameter for each order here
            const orderRequest = this.createOrderRequest(marketId, type, side, amount, price, extendedParams);
            ordersRequests.push(orderRequest);
        }
        const symbols = this.marketSymbols(orderSymbols, undefined, false, true, true);
        const market = this.market(symbols[0]);
        if (market['future'] || market['option']) {
            throw new errors.NotSupported(this.id + ' createOrders() does not support futures or options markets');
        }
        return ordersRequests;
    }
    /**
     * @method
     * @name gate#createOrders
     * @description create a list of trade orders
     * @see https://www.gate.io/docs/developers/apiv4/en/#get-a-single-order-2
     * @see https://www.gate.io/docs/developers/apiv4/en/#create-a-batch-of-orders
     * @see https://www.gate.io/docs/developers/apiv4/en/#create-a-batch-of-futures-orders
     * @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();
        await this.loadUnifiedStatus();
        const ordersRequests = this.createOrdersRequest(orders, params);
        const firstOrder = orders[0];
        const market = this.market(firstOrder['symbol']);
        let response = undefined;
        if (market['spot']) {
            response = await this.privateSpotPostBatchOrders(ordersRequests);
        }
        else if (market['swap']) {
            response = await this.privateFuturesPostSettleBatchOrders(ordersRequests);
        }
        return this.parseOrders(response);
    }
    createOrderRequest(symbol, type, side, amount, price = undefined, params = {}) {
        const market = this.market(symbol);
        const contract = market['contract'];
        const trigger = this.safeValue(params, 'trigger');
        const triggerPrice = this.safeValue2(params, 'triggerPrice', 'stopPrice');
        const stopLossPrice = this.safeValue(params, 'stopLossPrice', triggerPrice);
        const takeProfitPrice = this.safeValue(params, 'takeProfitPrice');
        const isStopLossOrder = stopLossPrice !== undefined;
        const isTakeProfitOrder = takeProfitPrice !== undefined;
        const isTpsl = isStopLossOrder || isTakeProfitOrder;
        if (isStopLossOrder && isTakeProfitOrder) {
            throw new errors.ExchangeError(this.id + ' createOrder() stopLossPrice and takeProfitPrice cannot both be defined');
        }
        const reduceOnly = this.safeValue(params, 'reduceOnly');
        const exchangeSpecificTimeInForce = this.safeStringLowerN(params, ['timeInForce', 'tif', 'time_in_force']);
        let postOnly = undefined;
        [postOnly, params] = this.handlePostOnly(type === 'market', exchangeSpecificTimeInForce === 'poc', params);
        let timeInForce = this.handleTimeInForce(params);
        if (postOnly) {
            timeInForce = 'poc';
        }
        // we only omit the unified params here
        // this is because the other params will get extended into the request
        params = this.omit(params, ['stopPrice', 'triggerPrice', 'stopLossPrice', 'takeProfitPrice', 'reduceOnly', 'timeInForce', 'postOnly']);
        const isLimitOrder = (type === 'limit');
        const isMarketOrder = (type === 'market');
        if (isLimitOrder && price === undefined) {
            throw new errors.ArgumentsRequired(this.id + ' createOrder () requires a price argument for ' + type + ' orders');
        }
        if (isMarketOrder) {
            if ((timeInForce === 'poc') || (timeInForce === 'gtc')) {
                throw new errors.ExchangeError(this.id + ' createOrder () timeInForce for market order can only be "FOK" or "IOC"');
            }
            else {
                if (timeInForce === undefined) {
                    const defaultTif = this.safeString(this.options, 'defaultTimeInForce', 'IOC');
                    const exchangeSpecificTif = this.safeString(this.options['timeInForce'], defaultTif, 'ioc');
                    timeInForce = exchangeSpecificTif;
                }
            }
            if (contract) {
                price = 0;
            }
        }
        if (contract) {
            const isClose = this.safeValue(params, 'close');
            if (isClose) {
                amount = 0;
            }
            else {
                const amountToPrecision = this.amountToPrecision(symbol, amount);
                const signedAmount = (side === 'sell') ? Precise["default"].stringNeg(amountToPrecision) : amountToPrecision;
                amount = parseInt(signedAmount);
            }
        }
        let request = undefined;
        const nonTriggerOrder = !isTpsl && (trigger === undefined);
        if (nonTriggerOrder) {
            if (contract) {
                // contract order
                request = {
                    'contract': market['id'],
                    'size': amount, // int64, positive = bid, negative = ask
                    // 'iceberg': 0, // int64, display size for iceberg order, 0 for non-iceberg, note that you will have to pay the taker fee for the hidden size
                    // 'close': false, // true to close the position, with size set to 0
                    // 'reduce_only': false, // St as true to be reduce-only order
                    // 'tif': 'gtc', // gtc, ioc, poc PendingOrCancelled == postOnly order
                    // 'text': clientOrderId, // 't-abcdef1234567890',
                    // 'auto_size': '', // close_long, close_short, note size also needs to be set to 0
                };
                if (!market['option']) {
                    request['settle'] = market['settleId']; // filled in prepareRequest above
                }
                if (isMarketOrder) {
                    request['price'] = '0'; // set to 0 for market orders
                }
                else {
                    request['price'] = (price === 0) ? '0' : this.priceToPrecision(symbol, price);
                }
                if (reduceOnly !== undefined) {
                    request['reduce_only'] = reduceOnly;
                }
                if (timeInForce !== undefined) {
                    request['tif'] = timeInForce;
                }
            }
            else {
                let marginMode = undefined;
                [marginMode, params] = this.getMarginMode(false, params);
                // spot order
                request = {
                    // 'text': clientOrderId, // 't-abcdef1234567890',
                    'currency_pair': market['id'],
                    'type': type,
                    'account': marginMode,
                    'side': side,
                    // 'time_in_force': 'gtc', // gtc, ioc, poc PendingOrCancelled == postOnly order
                    // 'iceberg': 0, // amount to display for the iceberg order, null or 0 for normal orders, set to -1 to hide the order completely
                    // 'auto_borrow': false, // used in margin or cross margin trading to allow automatic loan of insufficient amount if balance is not enough
                    // 'auto_repay': false, // automatic repayment for automatic borrow loan generated by cross margin order, diabled by default
                };
                if (isMarketOrder && (side === 'buy')) {
                    let quoteAmount = undefined;
                    let createMarketBuyOrderRequiresPrice = true;
                    [createMarketBuyOrderRequiresPrice, params] = this.handleOptionAndParams(params, 'createOrder', 'createMarketBuyOrderRequiresPrice', true);
                    const cost = this.safeNumber(params, 'cost');
                    params = this.omit(params, 'cost');
                    if (cost !== undefined) {
                        quoteAmount = this.costToPrecision(symbol, cost);
                    }
                    else if (createMarketBuyOrderRequiresPrice) {
                        if (price === 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 (quote quantity) in the amount argument');
                        }
                        else {
                            const amountString = this.numberToString(amount);
                            const priceString = this.numberToString(price);
                            const costRequest = Precise["default"].stringMul(amountString, priceString);
                            quoteAmount = this.costToPrecision(symbol, costRequest);
                        }
                    }
                    else {
                        quoteAmount = this.costToPrecision(symbol, amount);
                    }
                    request['amount'] = quoteAmount;
                }
                else {
                    request['amount'] = this.amountToPrecision(symbol, amount);
                }
                if (isLimitOrder) {
                    request['price'] = this.priceToPrecision(symbol, price);
                }
                if (timeInForce !== undefined) {
                    request['time_in_force'] = timeInForce;
                }
            }
            let clientOrderId = this.safeString2(params, 'text', 'clientOrderId');
            const textIsRequired = this.safeBool(params, 'textIsRequired', false);
            if (clientOrderId !== undefined) {
                // user-defined, must follow the rules if not empty
                //     prefixed with t-
                //     no longer than 28 bytes without t- prefix
                //     can only include 0-9, A-Z, a-z, underscores (_), hyphens (-) or dots (.)
                if (clientOrderId.length > 28) {
                    throw new errors.BadRequest(this.id + ' createOrder () clientOrderId or text param must be up to 28 characters');
                }
                params = this.omit(params, ['text', 'clientOrderId', 'textIsRequired']);
                if (clientOrderId[0] !== 't') {
                    clientOrderId = 't-' + clientOrderId;
                }
                request['text'] = clientOrderId;
            }
            else {
                if (textIsRequired) {
                    // batchOrders requires text in the request
                    request['text'] = 't-' + this.uuid16();
                }
            }
        }
        else {
            if (market['option']) {
                throw new errors.NotSupported(this.id + ' createOrder() conditional option orders are not supported');
            }
            if (contract) {
                // contract conditional order
                request = {
                    'initial': {
                        'contract': market['id'],
                        'size': amount, // positive = buy, negative = sell, set to 0 to close the position
                        // 'price': (price === 0) ? '0' : this.priceToPrecision (symbol, price), // set to 0 to use market price
                        // 'close': false, // set to true if trying to close the position
                        // 'tif': 'gtc', // gtc, ioc, if using market price, only ioc is supported
                        // 'text': clientOrderId, // web, api, app
                        // 'reduce_only': false,
                    },
                    'settle': market['settleId'],
                };
                if (type === 'market') {
                    request['initial']['price'] = '0';
                }
                else {
                    request['initial']['price'] = (price === 0) ? '0' : this.priceToPrecision(symbol, price);
                }
                if (trigger === undefined) {
                    let rule = undefined;
                    let triggerOrderPrice = undefined;
                    if (isStopLossOrder) {
                        // we let trigger orders be aliases for stopLoss orders because
                        // gateio doesn't accept conventional trigger orders for spot markets
                        rule = (side === 'buy') ? 1 : 2;
                        triggerOrderPrice = this.priceToPrecision(symbol, stopLossPrice);
                    }
                    else if (isTakeProfitOrder) {
                        rule = (side === 'buy') ? 2 : 1;
                        triggerOrderPrice = this.priceToPrecision(symbol, takeProfitPrice);
                    }
                    const priceType = this.safeInteger(params, 'price_type', 0);
                    if (priceType < 0 || priceType > 2) {
                        throw new errors.BadRequest(this.id + ' createOrder () price_type should be 0 latest deal price, 1 mark price, 2 index price');
                    }
                    params = this.omit(params, ['price_type']);
                    request['trigger'] = {
                        // 'strategy_type': 0, // 0 = by price, 1 = by price gap, only 0 is supported currently
                        'price_type': priceType,
                        'price': this.priceToPrecision(symbol, triggerOrderPrice),
                        'rule': rule, // 1 means price_type >= price, 2 means price_type <= price
                        // 'expiration': expiration, how many seconds to wait for the condition to be triggered before cancelling the order
                    };
                }
                if (reduceOnly !== undefined) {
                    request['initial']['reduce_only'] = reduceOnly;
                }
                if (timeInForce !== undefined) {
                    request['initial']['tif'] = timeInForce;
                }
            }
            else {
                // spot conditional order
                const options = this.safeValue(this.options, 'createOrder', {});
                let marginMode = undefined;
                [marginMode, params] = this.getMarginMode(true, params);
                if (timeInForce === undefined) {
                    timeInForce = 'gtc';
                }
                request = {
                    'put': {
                        'type': type,
                        'side': side,
                        'price': this.priceToPrecision(symbol, price),
                        'amount': this.amountToPrecision(symbol, amount),
                        'account': marginMode,
                        'time_in_force': timeInForce, // gtc, ioc (ioc is for taker only, so shouldnt't be in conditional order)
                    },
                    'market': market['id'],
                };
                if (trigger === undefined) {
                    const defaultExpiration = this.safeInteger(options, 'expiration');
                    const expiration = this.safeInteger(params, 'expiration', defaultExpiration);
                    let rule = undefined;
                    let triggerOrderPrice = undefined;
                    if (isStopLossOrder) {
                        // we let trigger orders be aliases for stopLoss orders because
                        // gateio doesn't accept conventional trigger orders for spot markets
                        rule = (side === 'buy') ? '>=' : '<=';
                        triggerOrderPrice = this.priceToPrecision(symbol, stopLossPrice);
                    }
                    else if (isTakeProfitOrder) {
                        rule = (side === 'buy') ? '<=' : '>=';
                        triggerOrderPrice = this.priceToPrecision(symbol, takeProfitPrice);
                    }
                    request['trigger'] = {
                        'price': this.priceToPrecision(symbol, triggerOrderPrice),
                        'rule': rule,
                        'expiration': expiration, // required, how long (in seconds) to wait for the condition to be triggered before cancelling the order
                    };
                }
            }
        }
        return this.extend(request, params);
    }
    /**
     * @method
     * @name gate#createMarketBuyOrderWithCost
     * @description create a market buy order by providing the symbol and cost
     * @see https://www.gate.io/docs/developers/apiv4/en/#create-an-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
     * @param {bool} [params.unifiedAccount] set to true for creating a unified account order
     * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
     */
    async createMarketBuyOrderWithCost(symbol, cost, params = {}) {
        await this.loadMarkets();
        await this.loadUnifiedStatus();
        const market = this.market(symbol);
        if (!market['spot']) {
            throw new errors.NotSupported(this.id + ' createMarketBuyOrderWithCost() supports spot orders only');
        }
        params['createMarketBuyOrderRequiresPrice'] = false;
        return await this.createOrder(symbol, 'market', 'buy', cost, undefined, params);
    }
    editOrderRequest(id, symbol, type, side, amount = undefined, price = undefined, params = {}) {
        const market = this.market(symbol);
        let marketType = undefined;
        [marketType, params] = this.handleMarketTypeAndParams('editOrder', market, params);
        let account = this.convertTypeToAccount(marketType);
        let isUnifiedAccount = false;
        [isUnifiedAccount, params] = this.handleOptionAndParams(params, 'editOrder', 'unifiedAccount');
        if (isUnifiedAccount) {
            account = 'unified';
        }
        const isLimitOrder = (type === 'limit');
        if (account === 'spot') {
            if (!isLimitOrder) {
                // exchange doesn't have market orders for spot
                throw new errors.InvalidOrder(this.id + ' editOrder() does not support ' + type + ' orders for ' + marketType + ' markets');
            }
        }
        const request = {
            'order_id': id.toString(),
            'currency_pair': market['id'],
            'account': account,
        };
        if (amount !== undefined) {
            if (market['spot']) {
                request['amount'] = this.amountToPrecision(symbol, amount);
            }
            else {
                if (side === 'sell') {
                    request['size'] = this.parseToNumeric(Precise["default"].stringNeg(this.amountToPrecision(symbol, amount)));
                }
                else {
                    request['size'] = this.parseToNumeric(this.amountToPrecision(symbol, amount));
                }
            }
        }
        if (price !== undefined) {
            request['price'] = this.priceToPrecision(symbol, price);
        }
        if (!market['spot']) {
            request['settle'] = market['settleId'];
        }
        return this.extend(request, params);
    }
    /**
     * @method
     * @name gate#editOrder
     * @description edit a trade order, gate currently only supports the modification of the price or amount fields
     * @see https://www.gate.io/docs/developers/apiv4/en/#amend-an-order
     * @see https://www.gate.io/docs/developers/apiv4/en/#amend-an-order-2
     * @param {string} id 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 the currency you want to trade in units of the base currency
     * @param {float} [price] the price at which the order is to be fulfilled, in units of the quote currency, ignored in market orders
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @param {bool} [params.unifiedAccount] set to true for editing an order in a unified account
     * @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();
        await this.loadUnifiedStatus();
        const market = this.market(symbol);
        const extendedRequest = this.editOrderRequest(id, symbol, type, side, amount, price, params);
        let response = undefined;
        if (market['spot']) {
            response = await this.privateSpotPatchOrdersOrderId(extendedRequest);
        }
        else {
            response = await this.privateFuturesPutSettleOrdersOrderId(extendedRequest);
        }
        //
        //     {
        //         "id": "243233276443",
        //         "text": "apiv4",
        //         "create_time": "1670908873",
        //         "update_time": "1670914102",
        //         "create_time_ms": 1670908873077,
        //         "update_time_ms": 1670914102241,
        //         "status": "open",
        //         "currency_pair": "ADA_USDT",
        //         "type": "limit",
        //         "account": "spot",
        //         "side": "sell",
        //         "amount": "10",
        //         "price": "0.6",
        //         "time_in_force": "gtc",
        //         "iceberg": "0",
        //         "left": "10",
        //         "fill_price": "0",
        //         "filled_total": "0",
        //         "fee": "0",
        //         "fee_currency": "USDT",
        //         "point_fee": "0",
        //         "gt_fee": "0",
        //         "gt_maker_fee": "0",
        //         "gt_taker_fee": "0",
        //         "gt_discount": false,
        //         "rebated_fee": "0",
        //         "rebated_fee_currency": "ADA"
        //     }
        //
        return this.parseOrder(response, market);
    }
    parseOrderStatus(status) {
        const statuses = {
            'open': 'open',
            '_new': 'open',
            'filled': 'closed',
            'cancelled': 'canceled',
            'liquidated': 'closed',
            'ioc': 'canceled',
            'failed': 'canceled',
            'expired': 'canceled',
            'finished': 'closed',
            'finish': 'closed',
            'succeeded': 'closed',
        };
        return this.safeString(statuses, status, status);
    }
    parseOrder(order, market = undefined) {
        //
        // SPOT
        // createOrder/cancelOrder/fetchOrder/editOrder
        //
        //    {
        //        "id": "62364648575",
        //        "text": "apiv4",
        //        "create_time": "1626354834",
        //        "update_time": "1626354834",
        //        "create_time_ms": "1626354833544",
        //        "update_time_ms": "1626354833544",
        //        "status": "open",
        //        "currency_pair": "BTC_USDT",
        //        "type": "limit",
        //        "account": "spot",
        //        "side": "buy",
        //        "amount": "0.0001",
        //        "price": "30000",
        //        "time_in_force": "gtc",
        //        "iceberg": "0",
        //        "left": "0.0001",
        //        "fill_price": "0",
        //        "filled_total": "0",
        //        "fee": "0",
        //        "fee_currency": "BTC",
        //        "point_fee": "0",
        //        "gt_fee": "0",
        //        "gt_discount": true,
        //        "rebated_fee": "0",
        //        "rebated_fee_currency": "USDT"
        //     }
        //
        // SPOT TRIGGER ORDERS
        // createOrder
        //
        //    {
        //        "id": 12604556
        //    }
        //
        // fetchOrder/cancelOrder
        //
        //    {
        //        "market": "ADA_USDT",
        //        "user": 6392049,
        //        "trigger": {
        //            "price": "1.08", // stopPrice
        //            "rule": "\u003e=",
        //            "expiration": 86400
        //        },
        //        "put": {
        //            "type": "limit",
        //            "side": "buy",
        //            "price": "1.08", // order price
        //            "amount": "1.00000000000000000000",
        //            "account": "normal",
        //            "time_in_force": "gtc"
        //        },
        //        "id": 71639298,
        //        "ctime": 1643945985,
        //        "status": "open"
        //    }
        //
        // FUTURE, SWAP AND OPTION
        // createOrder/cancelOrder/fetchOrder
        //
        //    {
        //        "id": 123028481731,
        //        "contract": "ADA_USDT",
        //        "mkfr": "-0.00005",
        //        "tkfr": "0.00048",
        //        "tif": "ioc",
        //        "is_reduce_only": false,
        //        "create_time": 1643950262.68,
        //        "finish_time": 1643950262.68,
        //        "price": "0",
        //        "size": 1,
        //        "refr": "0",
        //        "left":0,
        //        "text": "api",
        //        "fill_price": "1.05273",
        //        "user":6329238,
        //        "finish_as": "filled",
        //        "status": "finished",
        //        "is_liq": false,
        //        "refu":0,
        //        "is_close": false,
        //        "iceberg": 0
        //    }
        //
        // TRIGGER ORDERS (FUTURE AND SWAP)
        // createOrder
        //
        //    {
        //        "id": 12604556
        //    }
        //
        // fetchOrder/cancelOrder
        //
        //    {
        //        "user": 6320300,
        //        "trigger": {
        //            "strategy_type": 0,
        //            "price_type": 0,
        //            "price": "1.03", // stopPrice
        //            "rule": 2,
        //            "expiration": 0
        //        },
        //        "initial": {
        //            "contract": "ADA_USDT",
        //            "size": -1,
        //            "price": "1.02",
        //            "tif": "gtc",
        //            "text": "",
        //            "iceberg": 0,
        //            "is_close": false,
        //            "is_reduce_only": false,
        //            "auto_size": ""
        //        },
        //        "id": 126393906,
        //        "trade_id": 0,
        //        "status": "open",
        //        "reason": "",
        //        "create_time": 1643953482,
        //        "finish_time": 1643953482,
        //        "is_stop_order": false,
        //        "stop_trigger": {
        //            "rule": 0,
        //            "trigger_price": "",
        //            "order_price": ""
        //        },
        //        "me_order_id": 0,
        //        "order_type": ""
        //    }
        //
        //    {
        //        "text": "t-d18baf9ac44d82e2",
        //        "succeeded": false,
        //        "label": "BALANCE_NOT_ENOUGH",
        //        "message": "Not enough balance"
        //    }
        //
        //  {"user_id":10406147,"id":"id","succeeded":false,"message":"INVALID_PROTOCOL","label":"INVALID_PROTOCOL"}
        //
        const succeeded = this.safeBool(order, 'succeeded', true);
        if (!succeeded) {
            // cancelOrders response
            return this.safeOrder({
                'clientOrderId': this.safeString(order, 'text'),
                'info': order,
                'status': 'rejected',
                'id': this.safeString(order, 'id'),
            });
        }
        const put = this.safeValue2(order, 'put', 'initial', {});
        const trigger = this.safeValue(order, 'trigger', {});
        let contract = this.safeString(put, 'contract');
        let type = this.safeString(put, 'type');
        let timeInForce = this.safeStringUpper2(put, 'time_in_force', 'tif');
        let amount = this.safeString2(put, 'amount', 'size');
        let side = this.safeString(put, 'side');
        let price = this.safeString(put, 'price');
        contract = this.safeString(order, 'contract', contract);
        type = this.safeString(order, 'type', type);
        timeInForce = this.safeStringUpper2(order, 'time_in_force', 'tif', timeInForce);
        if (timeInForce === 'POC') {
            timeInForce = 'PO';
        }
        const postOnly = (timeInForce === 'PO');
        amount = this.safeString2(order, 'amount', 'size', amount);
        side = this.safeString(order, 'side', side);
        price = this.safeString(order, 'price', price);
        let remainingString = this.safeString(order, 'left');
        let cost = this.safeString(order, 'filled_total');
        const triggerPrice = this.safeNumber(trigger, 'price');
        let average = this.safeNumber2(order, 'avg_deal_price', 'fill_price');
        if (triggerPrice) {
            remainingString = amount;
            cost = '0';
        }
        if (contract) {
            const isMarketOrder = Precise["default"].stringEquals(price, '0') && (timeInForce === 'IOC');
            type = isMarketOrder ? 'market' : 'limit';
            side = Precise["default"].stringGt(amount, '0') ? 'buy' : 'sell';
        }
        const rawStatus = this.safeStringN(order, ['finish_as', 'status', 'open']);
        let timestamp = this.safeInteger(order, 'create_time_ms');
        if (timestamp === undefined) {
            timestamp = this.safeTimestamp2(order, 'create_time', 'ctime');
        }
        let lastTradeTimestamp = this.safeInteger(order, 'update_time_ms');
        if (lastTradeTimestamp === undefined) {
            lastTradeTimestamp = this.safeTimestamp2(order, 'update_time', 'finish_time');
        }
        let marketType = 'contract';
        if (('currency_pair' in order) || ('market' in order)) {
            marketType = 'spot';
        }
        const exchangeSymbol = this.safeString2(order, 'currency_pair', 'market', contract);
        const symbol = this.safeSymbol(exchangeSymbol, market, '_', marketType);
        // Everything below this(above return) is related to fees
        const fees = [];
        const gtFee = this.safeString(order, 'gt_fee');
        if (gtFee !== undefined) {
            fees.push({
                'currency': 'GT',
                'cost': gtFee,
            });
        }
        const fee = this.safeString(order, 'fee');
        if (fee !== undefined) {
            fees.push({
                'currency': this.safeCurrencyCode(this.safeString(order, 'fee_currency')),
                'cost': fee,
            });
        }
        const rebate = this.safeString(order, 'rebated_fee');
        if (rebate !== undefined) {
            fees.push({
                'currency': this.safeCurrencyCode(this.safeString(order, 'rebated_fee_currency')),
                'cost': Precise["default"].stringNeg(rebate),
            });
        }
        const numFeeCurrencies = fees.length;
        const multipleFeeCurrencies = numFeeCurrencies > 1;
        const status = this.parseOrderStatus(rawStatus);
        let remaining = Precise["default"].stringAbs(remainingString);
        // handle spot market buy
        const account = this.safeString(order, 'account'); // using this instead of market type because of the conflicting ids
        if (account === 'spot') {
            const averageString = this.safeString(order, 'avg_deal_price');
            average = this.parseNumber(averageString);
            if ((type === 'market') && (side === 'buy')) {
                remaining = Precise["default"].stringDiv(remainingString, averageString);
                price = undefined; // arrives as 0
                cost = amount;
                amount = Precise["default"].stringDiv(amount, averageString);
            }
        }
        return this.safeOrder({
            'id': this.safeString(order, 'id'),
            'clientOrderId': this.safeString(order, 'text'),
            'timestamp': timestamp,
            'datetime': this.iso8601(timestamp),
            'lastTradeTimestamp': lastTradeTimestamp,
            'status': status,
            'symbol': symbol,
            'type': type,
            'timeInForce': timeInForce,
            'postOnly': postOnly,
            'reduceOnly': this.safeValue(order, 'is_reduce_only'),
            'side': side,
            'price': price,
            'triggerPrice': triggerPrice,
            'average': average,
            'amount': Precise["default"].stringAbs(amount),
            'cost': Precise["default"].stringAbs(cost),
            'filled': undefined,
            'remaining': remaining,
            'fee': multipleFeeCurrencies ? undefined : this.safeValue(fees, 0),
            'fees': multipleFeeCurrencies ? fees : [],
            'trades': undefined,
            'info': order,
        }, market);
    }
    fetchOrderRequest(id, symbol = undefined, params = {}) {
        const market = (symbol === undefined) ? undefined : this.market(symbol);
        const trigger = this.safeBoolN(params, ['trigger', 'is_stop_order', 'stop'], false);
        params = this.omit(params, ['is_stop_order', 'stop', 'trigger']);
        let clientOrderId = this.safeString2(params, 'text', 'clientOrderId');
        let orderId = id;
        if (clientOrderId !== undefined) {
            params = this.omit(params, ['text', 'clientOrderId']);
            if (clientOrderId[0] !== 't') {
                clientOrderId = 't-' + clientOrderId;
            }
            orderId = clientOrderId;
        }
        const [type, query] = this.handleMarketTypeAndParams('fetchOrder', market, params);
        const contract = (type === 'swap') || (type === 'future') || (type === 'option');
        const [request, requestParams] = contract ? this.prepareRequest(market, type, query) : this.spotOrderPrepareRequest(market, trigger, query);
        request['order_id'] = orderId.toString();
        return [request, requestParams];
    }
    /**
     * @method
     * @name gate#fetchOrder
     * @description Retrieves information on an order
     * @see https://www.gate.io/docs/developers/apiv4/en/#get-a-single-order
     * @see https://www.gate.io/docs/developers/apiv4/en/#get-a-single-order-2
     * @see https://www.gate.io/docs/developers/apiv4/en/#get-a-single-order-3
     * @see https://www.gate.io/docs/developers/apiv4/en/#get-a-single-order-4
     * @param {string} id Order id
     * @param {string} symbol Unified market symbol, *required for spot and margin*
     * @param {object} [params] Parameters specified by the exchange api
     * @param {bool} [params.trigger] True if the order being fetched is a trigger order
     * @param {string} [params.marginMode] 'cross' or 'isolated' - marginMode for margin trading if not provided this.options['defaultMarginMode'] is used
     * @param {string} [params.type] 'spot', 'swap', or 'future', if not provided this.options['defaultMarginMode'] is used
     * @param {string} [params.settle] 'btc' or 'usdt' - settle currency for perpetual swap and future - market settle currency is used if symbol !== undefined, default="usdt" for swap and "btc" for future
     * @param {bool} [params.unifiedAccount] set to true for fetching a unified account order
     * @returns An [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
     */
    async fetchOrder(id, symbol = undefined, params = {}) {
        await this.loadMarkets();
        await this.loadUnifiedStatus();
        const market = (symbol === undefined) ? undefined : this.market(symbol);
        const result = this.handleMarketTypeAndParams('fetchOrder', market, params);
        const type = this.safeString(result, 0);
        const trigger = this.safeBoolN(params, ['trigger', 'is_stop_order', 'stop'], false);
        const [request, requestParams] = this.fetchOrderRequest(id, symbol, params);
        let response = undefined;
        if (type === 'spot' || type === 'margin') {
            if (trigger) {
                response = await this.privateSpotGetPriceOrdersOrderId(this.extend(request, requestParams));
            }
            else {
                response = await this.privateSpotGetOrdersOrderId(this.extend(request, requestParams));
            }
        }
        else if (type === 'swap') {
            if (trigger) {
                response = await this.privateFuturesGetSettlePriceOrdersOrderId(this.extend(request, requestParams));
            }
            else {
                response = await this.privateFuturesGetSettleOrdersOrderId(this.extend(request, requestParams));
            }
        }
        else if (type === 'future') {
            if (trigger) {
                response = await this.privateDeliveryGetSettlePriceOrdersOrderId(this.extend(request, requestParams));
            }
            else {
                response = await this.privateDeliveryGetSettleOrdersOrderId(this.extend(request, requestParams));
            }
        }
        else if (type === 'option') {
            response = await this.privateOptionsGetOrdersOrderId(this.extend(request, requestParams));
        }
        else {
            throw new errors.NotSupported(this.id + ' fetchOrder() not support this market type');
        }
        return this.parseOrder(response, market);
    }
    /**
     * @method
     * @name gate#fetchOpenOrders
     * @description fetch all unfilled currently open orders
     * @see https://www.gate.io/docs/developers/apiv4/en/#list-all-open-orders
     * @see https://www.gate.io/docs/developers/apiv4/en/#retrieve-running-auto-order-list
     * @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 {bool} [params.trigger] true for fetching trigger orders
     * @param {string} [params.type] spot, margin, swap or future, if not provided this.options['defaultType'] is used
     * @param {string} [params.marginMode] 'cross' or 'isolated' - marginMode for type='margin', if not provided this.options['defaultMarginMode'] is used
     * @param {bool} [params.unifiedAccount] set to true for fetching unified account orders
     * @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
     */
    async fetchOpenOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
        return await this.fetchOrdersByStatus('open', symbol, since, limit, params);
    }
    /**
     * @method
     * @name gate#fetchClosedOrders
     * @description fetches information on multiple closed orders made by the user
     * @see https://www.gate.io/docs/developers/apiv4/en/#list-orders
     * @see https://www.gate.io/docs/developers/apiv4/en/#retrieve-running-auto-order-list
     * @see https://www.gate.io/docs/developers/apiv4/en/#list-futures-orders
     * @see https://www.gate.io/docs/developers/apiv4/en/#list-all-auto-orders
     * @see https://www.gate.io/docs/developers/apiv4/en/#list-futures-orders-2
     * @see https://www.gate.io/docs/developers/apiv4/en/#list-all-auto-orders-2
     * @see https://www.gate.io/docs/developers/apiv4/en/#list-options-orders
     * @see https://www.gate.io/docs/developers/apiv4/en/#list-futures-orders-by-time-range
     * @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 {bool} [params.trigger] true for fetching trigger orders
     * @param {string} [params.type] spot, swap or future, if not provided this.options['defaultType'] is used
     * @param {string} [params.marginMode] 'cross' or 'isolated' - marginMode for margin trading if not provided this.options['defaultMarginMode'] is used
     * @param {boolean} [params.historical] *swap only* true for using historical endpoint
     * @param {bool} [params.unifiedAccount] set to true for fetching unified account orders
     * @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();
        await this.loadUnifiedStatus();
        const until = this.safeInteger(params, 'until');
        let market = undefined;
        if (symbol !== undefined) {
            market = this.market(symbol);
            symbol = market['symbol'];
        }
        const res = this.handleMarketTypeAndParams('fetchClosedOrders', market, params);
        const type = this.safeString(res, 0);
        let useHistorical = false;
        [useHistorical, params] = this.handleOptionAndParams(params, 'fetchClosedOrders', 'historical', false);
        if (!useHistorical && ((since === undefined && until === undefined) || (type !== 'swap'))) {
            return await this.fetchOrdersByStatus('finished', symbol, since, limit, params);
        }
        params = this.omit(params, 'type');
        let request = {};
        [request, params] = this.prepareRequest(market, type, params);
        if (since !== undefined) {
            request['from'] = this.parseToInt(since / 1000);
        }
        if (until !== undefined) {
            params = this.omit(params, 'until');
            request['to'] = this.parseToInt(until / 1000);
        }
        if (limit !== undefined) {
            request['limit'] = limit;
        }
        const response = await this.privateFuturesGetSettleOrdersTimerange(this.extend(request, params));
        return this.parseOrders(response, market, since, limit);
    }
    prepareOrdersByStatusRequest(status, symbol = undefined, since = undefined, limit = undefined, params = {}) {
        let market = undefined;
        if (symbol !== undefined) {
            market = this.market(symbol);
            symbol = market['symbol'];
        }
        let trigger = undefined;
        [trigger, params] = this.handleParamBool2(params, 'trigger', 'stop');
        let type = undefined;
        [type, params] = this.handleMarketTypeAndParams('fetchOrdersByStatus', market, params);
        const spot = (type === 'spot') || (type === 'margin');
        let request = {};
        [request, params] = spot ? this.multiOrderSpotPrepareRequest(market, trigger, params) : this.prepareRequest(market, type, params);
        if (spot && trigger) {
            request = this.omit(request, 'account');
        }
        if (status === 'closed') {
            status = 'finished';
        }
        request['status'] = status;
        if (limit !== undefined) {
            request['limit'] = limit;
        }
        if (spot) {
            if (since !== undefined) {
                request['from'] = this.parseToInt(since / 1000);
            }
            const until = this.safeInteger(params, 'until');
            if (until !== undefined) {
                params = this.omit(params, 'until');
                request['to'] = this.parseToInt(until / 1000);
            }
        }
        const [lastId, finalParams] = this.handleParamString2(params, 'lastId', 'last_id');
        if (lastId !== undefined) {
            request['last_id'] = lastId;
        }
        return [request, finalParams];
    }
    async fetchOrdersByStatus(status, symbol = undefined, since = undefined, limit = undefined, params = {}) {
        await this.loadMarkets();
        await this.loadUnifiedStatus();
        let market = undefined;
        if (symbol !== undefined) {
            market = this.market(symbol);
            symbol = market['symbol'];
        }
        // don't omit here, omits done in prepareOrdersByStatusRequest
        const trigger = this.safeBool2(params, 'trigger', 'stop');
        const res = this.handleMarketTypeAndParams('fetchOrdersByStatus', market, params);
        const type = this.safeString(res, 0);
        const [request, requestParams] = this.prepareOrdersByStatusRequest(status, symbol, since, limit, params);
        const spot = (type === 'spot') || (type === 'margin');
        const openStatus = (status === 'open');
        const openSpotOrders = spot && openStatus && !trigger;
        let response = undefined;
        if (spot) {
            if (!trigger) {
                if (openStatus) {
                    response = await this.privateSpotGetOpenOrders(this.extend(request, requestParams));
                }
                else {
                    response = await this.privateSpotGetOrders(this.extend(request, requestParams));
                }
            }
            else {
                response = await this.privateSpotGetPriceOrders(this.extend(request, requestParams));
            }
        }
        else if (type === 'swap') {
            if (trigger) {
                response = await this.privateFuturesGetSettlePriceOrders(this.extend(request, requestParams));
            }
            else {
                response = await this.privateFuturesGetSettleOrders(this.extend(request, requestParams));
            }
        }
        else if (type === 'future') {
            if (trigger) {
                response = await this.privateDeliveryGetSettlePriceOrders(this.extend(request, requestParams));
            }
            else {
                response = await this.privateDeliveryGetSettleOrders(this.extend(request, requestParams));
            }
        }
        else if (type === 'option') {
            response = await this.privateOptionsGetOrders(this.extend(request, requestParams));
        }
        else {
            throw new errors.NotSupported(this.id + ' fetchOrders() not support this market type');
        }
        //
        // spot open orders
        //
        //    [
        //        {
        //            "currency_pair": "ADA_USDT",
        //            "total": 2,
        //            "orders": [
        //                {
        //                    "id": "155498539874",
        //                    "text": "apiv4",
        //                    "create_time": "1652406843",
        //                    "update_time": "1652406843",
        //                    "create_time_ms": 1652406843295,
        //                    "update_time_ms": 1652406843295,
        //                    "status": "open",
        //                    "currency_pair": "ADA_USDT",
        //                    "type": "limit",
        //                    "account": "spot",
        //                    "side": "buy",
        //                    "amount": "3",
        //                    "price": "0.35",
        //                    "time_in_force": "gtc",
        //                    "iceberg": "0",
        //                    "left": "3",
        //                    "fill_price": "0",
        //                    "filled_total": "0",
        //                    "fee": "0",
        //                    "fee_currency": "ADA",
        //                    "point_fee": "0",
        //                    "gt_fee": "0",
        //                    "gt_discount": false,
        //                    "rebated_fee": "0",
        //                    "rebated_fee_currency": "USDT"
        //                },
        //                ...
        //            ]
        //        },
        //        ...
        //    ]
        //
        // spot
        //
        //    [
        //        {
        //           "id": "8834234273",
        //           "text": "3",
        //           "create_time": "1635406193",
        //           "update_time": "1635406193",
        //           "create_time_ms": 1635406193361,
        //           "update_time_ms": 1635406193361,
        //           "status": "closed",
        //           "currency_pair": "BTC_USDT",
        //           "type": "limit",
        //           "account": "spot", // margin for margin orders
        //           "side": "sell",
        //           "amount": "0.0002",
        //           "price": "58904.01",
        //           "time_in_force": "gtc",
        //           "iceberg": "0",
        //           "left": "0.0000",
        //           "fill_price": "11.790516",
        //           "filled_total": "11.790516",
        //           "fee": "0.023581032",
        //           "fee_currency": "USDT",
        //           "point_fee": "0",
        //           "gt_fee": "0",
        //           "gt_discount": false,
        //           "rebated_fee_currency": "BTC"
        //        }
        //    ]
        //
        // spot trigger
        //
        //    [
        //        {
        //            "market": "ADA_USDT",
        //            "user": 10406147,
        //            "trigger": {
        //                "price": "0.65",
        //                "rule": "\u003c=",
        //                "expiration": 86400
        //            },
        //            "put": {
        //                "type": "limit",
        //                "side": "sell",
        //                "price": "0.65",
        //                "amount": "2.00000000000000000000",
        //                "account": "normal",  // margin for margin orders
        //                "time_in_force": "gtc"
        //            },
        //            "id": 8449909,
        //            "ctime": 1652188982,
        //            "status": "open"
        //        }
        //    ]
        //
        // swap
        //
        //    [
        //        {
        //           "status": "finished",
        //           "size": -1,
        //           "left": 0,
        //           "id": 82750739203,
        //           "is_liq": false,
        //           "is_close": false,
        //           "contract": "BTC_USDT",
        //           "text": "web",
        //           "fill_price": "60721.3",
        //           "finish_as": "filled",
        //           "iceberg": 0,
        //           "tif": "ioc",
        //           "is_reduce_only": true,
        //           "create_time": 1635403475.412,
        //           "finish_time": 1635403475.4127,
        //           "price": "0"
        //        }
        //    ]
        //
        // option
        //
        //     [
        //         {
        //             "id": 2593450699,
        //             "contract": "BTC_USDT-20230601-27500-C",
        //             "mkfr": "0.0003",
        //             "tkfr": "0.0003",
        //             "tif": "gtc",
        //             "is_reduce_only": false,
        //             "create_time": 1685503873,
        //             "price": "200",
        //             "size": 1,
        //             "refr": "0",
        //             "left": 1,
        //             "text": "api",
        //             "fill_price": "0",
        //             "user": 5691076,
        //             "status": "open",
        //             "is_liq": false,
        //             "refu": 0,
        //             "is_close": false,
        //             "iceberg": 0
        //         }
        //     ]
        //
        let result = response;
        if (openSpotOrders) {
            result = [];
            for (let i = 0; i < response.length; i++) {
                const ordersInner = this.safeValue(response[i], 'orders');
                result = this.arrayConcat(result, ordersInner);
            }
        }
        const orders = this.parseOrders(result, market, since, limit);
        return this.filterBySymbolSinceLimit(orders, symbol, since, limit);
    }
    /**
     * @method
     * @name gate#cancelOrder
     * @description Cancels an open order
     * @see https://www.gate.io/docs/developers/apiv4/en/#cancel-a-single-order
     * @see https://www.gate.io/docs/developers/apiv4/en/#cancel-a-single-order-2
     * @see https://www.gate.io/docs/developers/apiv4/en/#cancel-a-single-order-3
     * @see https://www.gate.io/docs/developers/apiv4/en/#cancel-a-single-order-4
     * @param {string} id Order id
     * @param {string} symbol Unified market symbol
     * @param {object} [params] Parameters specified by the exchange api
     * @param {bool} [params.trigger] True if the order to be cancelled is a trigger order
     * @param {bool} [params.unifiedAccount] set to true for canceling unified account orders
     * @returns An [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
     */
    async cancelOrder(id, symbol = undefined, params = {}) {
        await this.loadMarkets();
        await this.loadUnifiedStatus();
        const market = (symbol === undefined) ? undefined : this.market(symbol);
        const trigger = this.safeBoolN(params, ['is_stop_order', 'stop', 'trigger'], false);
        params = this.omit(params, ['is_stop_order', 'stop', 'trigger']);
        const [type, query] = this.handleMarketTypeAndParams('cancelOrder', market, params);
        const [request, requestParams] = (type === 'spot' || type === 'margin') ? this.spotOrderPrepareRequest(market, trigger, query) : this.prepareRequest(market, type, query);
        request['order_id'] = id;
        let response = undefined;
        if (type === 'spot' || type === 'margin') {
            if (trigger) {
                response = await this.privateSpotDeletePriceOrdersOrderId(this.extend(request, requestParams));
            }
            else {
                response = await this.privateSpotDeleteOrdersOrderId(this.extend(request, requestParams));
            }
        }
        else if (type === 'swap') {
            if (trigger) {
                response = await this.privateFuturesDeleteSettlePriceOrdersOrderId(this.extend(request, requestParams));
            }
            else {
                response = await this.privateFuturesDeleteSettleOrdersOrderId(this.extend(request, requestParams));
            }
        }
        else if (type === 'future') {
            if (trigger) {
                response = await this.privateDeliveryDeleteSettlePriceOrdersOrderId(this.extend(request, requestParams));
            }
            else {
                response = await this.privateDeliveryDeleteSettleOrdersOrderId(this.extend(request, requestParams));
            }
        }
        else if (type === 'option') {
            response = await this.privateOptionsDeleteOrdersOrderId(this.extend(request, requestParams));
        }
        else {
            throw new errors.NotSupported(this.id + ' cancelOrder() not support this market type');
        }
        //
        // spot
        //
        //     {
        //         "id": "95282841887",
        //         "text": "apiv4",
        //         "create_time": "1637383156",
        //         "update_time": "1637383235",
        //         "create_time_ms": 1637383156017,
        //         "update_time_ms": 1637383235085,
        //         "status": "cancelled",
        //         "currency_pair": "ETH_USDT",
        //         "type": "limit",
        //         "account": "spot",
        //         "side": "buy",
        //         "amount": "0.01",
        //         "price": "3500",
        //         "time_in_force": "gtc",
        //         "iceberg": "0",
        //         "left": "0.01",
        //         "fill_price": "0",
        //         "filled_total": "0",
        //         "fee": "0",
        //         "fee_currency": "ETH",
        //         "point_fee": "0",
        //         "gt_fee": "0",
        //         "gt_discount": false,
        //         "rebated_fee": "0",
        //         "rebated_fee_currency": "USDT"
        //     }
        //
        // spot conditional
        //
        //     {
        //         "market": "ETH_USDT",
        //         "user": 2436035,
        //         "trigger": {
        //             "price": "3500",
        //             "rule": "\u003c=",
        //             "expiration": 86400
        //         },
        //         "put": {
        //             "type": "limit",
        //             "side": "buy",
        //             "price": "3500",
        //             "amount": "0.01000000000000000000",
        //             "account": "normal",
        //             "time_in_force": "gtc"
        //         },
        //         "id": 5891843,
        //         "ctime": 1637382379,
        //         "ftime": 1637382673,
        //         "status": "canceled"
        //     }
        //
        // swap, future and option
        //
        //     {
        //         "id": "82241928192",
        //         "contract": "BTC_USDT",
        //         "mkfr": "0",
        //         "tkfr": "0.0005",
        //         "tif": "gtc",
        //         "is_reduce_only": false,
        //         "create_time": "1635196145.06",
        //         "finish_time": "1635196233.396",
        //         "price": "61000",
        //         "size": "4",
        //         "refr": "0",
        //         "left": "4",
        //         "text": "web",
        //         "fill_price": "0",
        //         "user": "6693577",
        //         "finish_as": "cancelled",
        //         "status": "finished",
        //         "is_liq": false,
        //         "refu": "0",
        //         "is_close": false,
        //         "iceberg": "0",
        //     }
        //
        return this.parseOrder(response, market);
    }
    /**
     * @method
     * @name gate#cancelOrders
     * @description cancel multiple orders
     * @see https://www.gate.io/docs/developers/apiv4/en/#cancel-a-batch-of-orders-with-an-id-list
     * @see https://www.gate.io/docs/developers/apiv4/en/#cancel-a-batch-of-orders-with-an-id-list-2
     * @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 {bool} [params.unifiedAccount] set to true for canceling unified account orders
     * @returns {object} an list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
     */
    async cancelOrders(ids, symbol = undefined, params = {}) {
        await this.loadMarkets();
        await this.loadUnifiedStatus();
        let market = undefined;
        if (symbol !== undefined) {
            market = this.market(symbol);
        }
        let type = undefined;
        const defaultSettle = (market === undefined) ? 'usdt' : market['settle'];
        const settle = this.safeStringLower(params, 'settle', defaultSettle);
        [type, params] = this.handleMarketTypeAndParams('cancelOrders', market, params);
        const isSpot = (type === 'spot');
        if (isSpot && (symbol === undefined)) {
            throw new errors.ArgumentsRequired(this.id + ' cancelOrders requires a symbol argument for spot markets');
        }
        if (isSpot) {
            const ordersRequests = [];
            for (let i = 0; i < ids.length; i++) {
                const id = ids[i];
                const orderItem = {
                    'id': id,
                    'symbol': symbol,
                };
                ordersRequests.push(orderItem);
            }
            return await this.cancelOrdersForSymbols(ordersRequests, params);
        }
        const request = {
            'settle': settle,
        };
        const finalList = [request]; // hacky but needs to be done here
        for (let i = 0; i < ids.length; i++) {
            finalList.push(ids[i]);
        }
        const response = await this.privateFuturesPostSettleBatchCancelOrders(finalList);
        return this.parseOrders(response);
    }
    /**
     * @method
     * @name gate#cancelOrdersForSymbols
     * @description cancel multiple orders for multiple symbols
     * @see https://www.gate.io/docs/developers/apiv4/en/#cancel-a-batch-of-orders-with-an-id-list
     * @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
     * @param {string[]} [params.clientOrderIds] client order ids
     * @param {bool} [params.unifiedAccount] set to true for canceling unified account orders
     * @returns {object} an list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
     */
    async cancelOrdersForSymbols(orders, params = {}) {
        await this.loadMarkets();
        await this.loadUnifiedStatus();
        const ordersRequests = [];
        for (let i = 0; i < orders.length; i++) {
            const order = orders[i];
            const symbol = this.safeString(order, 'symbol');
            const market = this.market(symbol);
            if (!market['spot']) {
                throw new errors.NotSupported(this.id + ' cancelOrdersForSymbols() supports only spot markets');
            }
            const id = this.safeString(order, 'id');
            const orderItem = {
                'id': id,
                'currency_pair': market['id'],
            };
            ordersRequests.push(orderItem);
        }
        const response = await this.privateSpotPostCancelBatchOrders(ordersRequests);
        //
        // [
        //     {
        //       "currency_pair": "BTC_USDT",
        //       "id": "123456"
        //     }
        // ]
        //
        return this.parseOrders(response);
    }
    /**
     * @method
     * @name gate#cancelAllOrders
     * @description cancel all open orders
     * @see https://www.gate.io/docs/developers/apiv4/en/#cancel-all-open-orders-in-specified-currency-pair
     * @see https://www.gate.io/docs/developers/apiv4/en/#cancel-all-open-orders-matched
     * @see https://www.gate.io/docs/developers/apiv4/en/#cancel-all-open-orders-matched-2
     * @see https://www.gate.io/docs/developers/apiv4/en/#cancel-all-open-orders-matched-3
     * @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 {bool} [params.unifiedAccount] set to true for canceling unified account orders
     * @returns {object[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
     */
    async cancelAllOrders(symbol = undefined, params = {}) {
        await this.loadMarkets();
        await this.loadUnifiedStatus();
        const market = (symbol === undefined) ? undefined : this.market(symbol);
        const trigger = this.safeBool2(params, 'stop', 'trigger');
        params = this.omit(params, ['stop', 'trigger']);
        const [type, query] = this.handleMarketTypeAndParams('cancelAllOrders', market, params);
        const [request, requestParams] = (type === 'spot') ? this.multiOrderSpotPrepareRequest(market, trigger, query) : this.prepareRequest(market, type, query);
        let response = undefined;
        if (type === 'spot' || type === 'margin') {
            if (trigger) {
                response = await this.privateSpotDeletePriceOrders(this.extend(request, requestParams));
            }
            else {
                response = await this.privateSpotDeleteOrders(this.extend(request, requestParams));
            }
        }
        else if (type === 'swap') {
            if (trigger) {
                response = await this.privateFuturesDeleteSettlePriceOrders(this.extend(request, requestParams));
            }
            else {
                response = await this.privateFuturesDeleteSettleOrders(this.extend(request, requestParams));
            }
        }
        else if (type === 'future') {
            if (trigger) {
                response = await this.privateDeliveryDeleteSettlePriceOrders(this.extend(request, requestParams));
            }
            else {
                response = await this.privateDeliveryDeleteSettleOrders(this.extend(request, requestParams));
            }
        }
        else if (type === 'option') {
            response = await this.privateOptionsDeleteOrders(this.extend(request, requestParams));
        }
        else {
            throw new errors.NotSupported(this.id + ' cancelAllOrders() not support this market type');
        }
        //
        //    [
        //        {
        //            "id": 139797004085,
        //            "contract": "ADA_USDT",
        //            "mkfr": "0",
        //            "tkfr": "0.0005",
        //            "tif": "gtc",
        //            "is_reduce_only": false,
        //            "create_time": 1647911169.343,
        //            "finish_time": 1647911226.849,
        //            "price": "0.8",
        //            "size": 1,
        //            "refr": "0.3",
        //            "left": 1,
        //            "text": "api",
        //            "fill_price": "0",
        //            "user": 6693577,
        //            "finish_as": "cancelled",
        //            "status": "finished",
        //            "is_liq": false,
        //            "refu": 2436035,
        //            "is_close": false,
        //            "iceberg": 0
        //        }
        //        ...
        //    ]
        //
        return this.parseOrders(response, market);
    }
    /**
     * @method
     * @name gate#transfer
     * @description transfer currency internally between wallets on the same account
     * @see https://www.gate.io/docs/developers/apiv4/en/#transfer-between-trading-accounts
     * @param {string} code unified currency code for currency being transferred
     * @param {float} amount the amount of currency to transfer
     * @param {string} fromAccount the account to transfer currency from
     * @param {string} toAccount the account to transfer currency to
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @param {string} [params.symbol] Unified market symbol *required for type == margin*
     * @returns A [transfer structure]{@link https://docs.ccxt.com/#/?id=transfer-structure}
     */
    async transfer(code, amount, fromAccount, toAccount, params = {}) {
        await this.loadMarkets();
        const currency = this.currency(code);
        const fromId = this.convertTypeToAccount(fromAccount);
        const toId = this.convertTypeToAccount(toAccount);
        const truncated = this.currencyToPrecision(code, amount);
        const request = {
            'currency': currency['id'],
            'amount': truncated,
        };
        if (!(fromId in this.options['accountsByType'])) {
            request['from'] = 'margin';
            request['currency_pair'] = fromId;
        }
        else {
            request['from'] = fromId;
        }
        if (!(toId in this.options['accountsByType'])) {
            request['to'] = 'margin';
            request['currency_pair'] = toId;
        }
        else {
            request['to'] = toId;
        }
        if (fromId === 'margin' || toId === 'margin') {
            const symbol = this.safeString2(params, 'symbol', 'currency_pair');
            if (symbol === undefined) {
                throw new errors.ArgumentsRequired(this.id + ' transfer requires params["symbol"] for isolated margin transfers');
            }
            const market = this.market(symbol);
            request['currency_pair'] = market['id'];
            params = this.omit(params, 'symbol');
        }
        if ((toId === 'futures') || (toId === 'delivery') || (fromId === 'futures') || (fromId === 'delivery')) {
            request['settle'] = currency['id']; // todo: currencies have network-junctions
        }
        const response = await this.privateWalletPostTransfers(this.extend(request, params));
        //
        // according to the docs (however actual response seems to be an empty string '')
        //
        //    {
        //        "currency": "BTC",
        //        "from": "spot",
        //        "to": "margin",
        //        "amount": "1",
        //        "currency_pair": "BTC_USDT"
        //    }
        //
        return this.parseTransfer(response, currency);
    }
    parseTransfer(transfer, currency = undefined) {
        //
        //    {
        //        "currency": "BTC",
        //        "from": "spot",
        //        "to": "margin",
        //        "amount": "1",
        //        "currency_pair": "BTC_USDT"
        //    }
        //
        return {
            'id': this.safeString(transfer, 'tx_id'),
            'timestamp': undefined,
            'datetime': undefined,
            'currency': this.safeCurrencyCode(undefined, currency),
            'amount': undefined,
            'fromAccount': undefined,
            'toAccount': undefined,
            'status': undefined,
            'info': transfer,
        };
    }
    /**
     * @method
     * @name gate#setLeverage
     * @description set the level of leverage for a market
     * @see https://www.gate.io/docs/developers/apiv4/en/#update-position-leverage
     * @see https://www.gate.io/docs/developers/apiv4/en/#update-position-leverage-2
     * @param {float} leverage the rate of leverage
     * @param {string} symbol unified market symbol
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @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');
        }
        // WARNING: THIS WILL INCREASE LIQUIDATION PRICE FOR OPEN ISOLATED LONG POSITIONS
        // AND DECREASE LIQUIDATION PRICE FOR OPEN ISOLATED SHORT POSITIONS
        if ((leverage < 0) || (leverage > 100)) {
            throw new errors.BadRequest(this.id + ' setLeverage() leverage should be between 1 and 100');
        }
        await this.loadMarkets();
        const market = this.market(symbol);
        const [request, query] = this.prepareRequest(market, undefined, params);
        const defaultMarginMode = this.safeString2(this.options, 'marginMode', 'defaultMarginMode');
        const crossLeverageLimit = this.safeString(query, 'cross_leverage_limit');
        let marginMode = this.safeString(query, 'marginMode', defaultMarginMode);
        let stringifiedMargin = this.numberToString(leverage);
        if (crossLeverageLimit !== undefined) {
            marginMode = 'cross';
            stringifiedMargin = crossLeverageLimit;
        }
        if (marginMode === 'cross' || marginMode === 'cross_margin') {
            request['cross_leverage_limit'] = stringifiedMargin;
            request['leverage'] = '0';
        }
        else {
            request['leverage'] = stringifiedMargin;
        }
        let response = undefined;
        if (market['swap']) {
            response = await this.privateFuturesPostSettlePositionsContractLeverage(this.extend(request, query));
        }
        else if (market['future']) {
            response = await this.privateDeliveryPostSettlePositionsContractLeverage(this.extend(request, query));
        }
        else {
            throw new errors.NotSupported(this.id + ' setLeverage() not support this market type');
        }
        //
        //     {
        //         "value": "0",
        //         "leverage": "5",
        //         "mode": "single",
        //         "realised_point": "0",
        //         "contract": "BTC_USDT",
        //         "entry_price": "0",
        //         "mark_price": "62035.86",
        //         "history_point": "0",
        //         "realised_pnl": "0",
        //         "close_order": null,
        //         "size": 0,
        //         "cross_leverage_limit": "0",
        //         "pending_orders": 0,
        //         "adl_ranking": 6,
        //         "maintenance_rate": "0.005",
        //         "unrealised_pnl": "0",
        //         "user": 2436035,
        //         "leverage_max": "100",
        //         "history_pnl": "0",
        //         "risk_limit": "1000000",
        //         "margin": "0",
        //         "last_close_pnl": "0",
        //         "liq_price": "0"
        //     }
        //
        return response;
    }
    parsePosition(position, market = undefined) {
        //
        // swap and future
        //
        //     {
        //         "value": "4.60516",
        //         "leverage": "0",
        //         "mode": "single",
        //         "realised_point": "0",
        //         "contract": "BTC_USDT",
        //         "entry_price": "46030.3",
        //         "mark_price": "46051.6",
        //         "history_point": "0",
        //         "realised_pnl": "-0.002301515",
        //         "close_order": null,
        //         "size": 1,
        //         "cross_leverage_limit": "0",
        //         "pending_orders": 0,
        //         "adl_ranking": 5,
        //         "maintenance_rate": "0.004",
        //         "unrealised_pnl": "0.00213",
        //         "user": 5691076,
        //         "leverage_max": "125",
        //         "history_pnl": "0",
        //         "risk_limit": "1000000",
        //         "margin": "8.997698485",
        //         "last_close_pnl": "0",
        //         "liq_price": "0",
        //         "update_time": 1705034246,
        //         "update_id": 1,
        //         "initial_margin": "0",
        //         "maintenance_margin": "0",
        //         "open_time": 1705034246,
        //         "trade_max_size": "0"
        //     }
        //
        // option
        //
        //     {
        //         "close_order": null,
        //         "size": 1,
        //         "vega": "5.29756",
        //         "theta": "-98.98917",
        //         "gamma": "0.00056",
        //         "delta": "0.68691",
        //         "contract": "BTC_USDT-20230602-26500-C",
        //         "entry_price": "529",
        //         "unrealised_pnl": "-1.0131",
        //         "user": 5691076,
        //         "mark_price": "427.69",
        //         "underlying_price": "26810.2",
        //         "underlying": "BTC_USDT",
        //         "realised_pnl": "-0.08042877",
        //         "mark_iv": "0.4224",
        //         "pending_orders": 0
        //     }
        //
        // fetchPositionsHistory (swap and future)
        //
        //    {
        //        "contract": "SLERF_USDT",         // Futures contract
        //        "text": "web",                    // Text of close order
        //        "long_price": "0.766306",         // When 'side' is 'long,' it indicates the opening average price; when 'side' is 'short,' it indicates the closing average price.
        //        "pnl": "-23.41702352",            // PNL
        //        "pnl_pnl": "-22.7187",            // Position P/L
        //        "pnl_fee": "-0.06527125",         // Transaction Fees
        //        "pnl_fund": "-0.63305227",        // Funding Fees
        //        "accum_size": "100",
        //        "time": 1711279263,               // Position close time
        //        "short_price": "0.539119",        // When 'side' is 'long,' it indicates the opening average price; when 'side' is 'short,' it indicates the closing average price
        //        "side": "long",                   // Position side, long or short
        //        "max_size": "100",                // Max Trade Size
        //        "first_open_time": 1711037985     // First Open Time
        //    }
        //
        const contract = this.safeString(position, 'contract');
        market = this.safeMarket(contract, market, '_', 'contract');
        const size = this.safeString2(position, 'size', 'accum_size');
        let side = this.safeString(position, 'side');
        if (side === undefined) {
            if (Precise["default"].stringGt(size, '0')) {
                side = 'long';
            }
            else if (Precise["default"].stringLt(size, '0')) {
                side = 'short';
            }
        }
        const maintenanceRate = this.safeString(position, 'maintenance_rate');
        const notional = this.safeString(position, 'value');
        const leverage = this.safeString(position, 'leverage');
        let marginMode = undefined;
        if (leverage !== undefined) {
            if (leverage === '0') {
                marginMode = 'cross';
            }
            else {
                marginMode = 'isolated';
            }
        }
        // Initial Position Margin = ( Position Value / Leverage ) + Close Position Fee
        // *The default leverage under the full position is the highest leverage in the market.
        // *Trading fee is charged as Taker Fee Rate (0.075%).
        let feePaid = this.safeString(position, 'pnl_fee');
        let initialMarginString = undefined;
        if (feePaid === undefined) {
            const takerFee = '0.00075';
            feePaid = Precise["default"].stringMul(takerFee, notional);
            initialMarginString = Precise["default"].stringAdd(Precise["default"].stringDiv(notional, leverage), feePaid);
        }
        let timestamp = this.safeTimestamp2(position, 'open_time', 'first_open_time');
        if (timestamp === 0) {
            timestamp = undefined;
        }
        return this.safePosition({
            'info': position,
            'id': undefined,
            'symbol': this.safeString(market, 'symbol'),
            'timestamp': timestamp,
            'datetime': this.iso8601(timestamp),
            'lastUpdateTimestamp': this.safeTimestamp2(position, 'update_time', 'time'),
            'initialMargin': this.parseNumber(initialMarginString),
            'initialMarginPercentage': this.parseNumber(Precise["default"].stringDiv(initialMarginString, notional)),
            'maintenanceMargin': this.parseNumber(Precise["default"].stringMul(maintenanceRate, notional)),
            'maintenanceMarginPercentage': this.parseNumber(maintenanceRate),
            'entryPrice': this.safeNumber(position, 'entry_price'),
            'notional': this.parseNumber(notional),
            'leverage': this.safeNumber(position, 'leverage'),
            'unrealizedPnl': this.safeNumber(position, 'unrealised_pnl'),
            'realizedPnl': this.safeNumber2(position, 'realised_pnl', 'pnl'),
            'contracts': this.parseNumber(Precise["default"].stringAbs(size)),
            'contractSize': this.safeNumber(market, 'contractSize'),
            'marginRatio': undefined,
            'liquidationPrice': this.safeNumber(position, 'liq_price'),
            'markPrice': this.safeNumber(position, 'mark_price'),
            'lastPrice': undefined,
            'collateral': this.safeNumber(position, 'margin'),
            'marginMode': marginMode,
            'side': side,
            'percentage': undefined,
            'stopLossPrice': undefined,
            'takeProfitPrice': undefined,
        });
    }
    /**
     * @method
     * @name gate#fetchPosition
     * @description fetch data on an open contract position
     * @see https://www.gate.io/docs/developers/apiv4/en/#get-single-position
     * @see https://www.gate.io/docs/developers/apiv4/en/#get-single-position-2
     * @see https://www.gate.io/docs/developers/apiv4/en/#get-specified-contract-position
     * @param {string} symbol unified market symbol of the market the position is held in
     * @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 = {}) {
        await this.loadMarkets();
        const market = this.market(symbol);
        if (!market['contract']) {
            throw new errors.BadRequest(this.id + ' fetchPosition() supports contract markets only');
        }
        let request = {};
        [request, params] = this.prepareRequest(market, market['type'], params);
        const extendedRequest = this.extend(request, params);
        let response = undefined;
        if (market['swap']) {
            response = await this.privateFuturesGetSettlePositionsContract(extendedRequest);
        }
        else if (market['future']) {
            response = await this.privateDeliveryGetSettlePositionsContract(extendedRequest);
        }
        else if (market['type'] === 'option') {
            response = await this.privateOptionsGetPositionsContract(extendedRequest);
        }
        //
        // swap and future
        //
        //     {
        //         "value": "4.60516",
        //         "leverage": "0",
        //         "mode": "single",
        //         "realised_point": "0",
        //         "contract": "BTC_USDT",
        //         "entry_price": "46030.3",
        //         "mark_price": "46051.6",
        //         "history_point": "0",
        //         "realised_pnl": "-0.002301515",
        //         "close_order": null,
        //         "size": 1,
        //         "cross_leverage_limit": "0",
        //         "pending_orders": 0,
        //         "adl_ranking": 5,
        //         "maintenance_rate": "0.004",
        //         "unrealised_pnl": "0.00213",
        //         "user": 5691076,
        //         "leverage_max": "125",
        //         "history_pnl": "0",
        //         "risk_limit": "1000000",
        //         "margin": "8.997698485",
        //         "last_close_pnl": "0",
        //         "liq_price": "0",
        //         "update_time": 1705034246,
        //         "update_id": 1,
        //         "initial_margin": "0",
        //         "maintenance_margin": "0",
        //         "open_time": 1705034246,
        //         "trade_max_size": "0"
        //     }
        //
        // option
        //
        //     {
        //         "close_order": null,
        //         "size": 1,
        //         "vega": "5.29756",
        //         "theta": "-98.98917",
        //         "gamma": "0.00056",
        //         "delta": "0.68691",
        //         "contract": "BTC_USDT-20230602-26500-C",
        //         "entry_price": "529",
        //         "unrealised_pnl": "-1.0131",
        //         "user": 5691076,
        //         "mark_price": "427.69",
        //         "underlying_price": "26810.2",
        //         "underlying": "BTC_USDT",
        //         "realised_pnl": "-0.08042877",
        //         "mark_iv": "0.4224",
        //         "pending_orders": 0
        //     }
        //
        return this.parsePosition(response, market);
    }
    /**
     * @method
     * @name gate#fetchPositions
     * @description fetch all open positions
     * @see https://www.gate.io/docs/developers/apiv4/en/#list-all-positions-of-a-user
     * @see https://www.gate.io/docs/developers/apiv4/en/#list-all-positions-of-a-user-2
     * @see https://www.gate.io/docs/developers/apiv4/en/#list-user-s-positions-of-specified-underlying
     * @param {string[]|undefined} symbols Not used by gate, but parsed internally by CCXT
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @param {string} [params.settle] 'btc' or 'usdt' - settle currency for perpetual swap and future - default="usdt" for swap and "btc" for future
     * @param {string} [params.type] swap, future or option, if not provided this.options['defaultType'] is used
     * @returns {object[]} a list of [position structure]{@link https://docs.ccxt.com/#/?id=position-structure}
     */
    async fetchPositions(symbols = undefined, params = {}) {
        await this.loadMarkets();
        let market = undefined;
        symbols = this.marketSymbols(symbols, undefined, true, true, true);
        if (symbols !== undefined) {
            const symbolsLength = symbols.length;
            if (symbolsLength > 0) {
                market = this.market(symbols[0]);
            }
        }
        let type = undefined;
        let request = {};
        [type, params] = this.handleMarketTypeAndParams('fetchPositions', market, params);
        if ((type === undefined) || (type === 'spot')) {
            type = 'swap'; // default to swap
        }
        if (type === 'option') {
            if (symbols !== undefined) {
                const marketId = market['id'];
                const optionParts = marketId.split('-');
                request['underlying'] = this.safeString(optionParts, 0);
            }
        }
        else {
            [request, params] = this.prepareRequest(undefined, type, params);
        }
        let response = undefined;
        if (type === 'swap') {
            response = await this.privateFuturesGetSettlePositions(this.extend(request, params));
        }
        else if (type === 'future') {
            response = await this.privateDeliveryGetSettlePositions(this.extend(request, params));
        }
        else if (type === 'option') {
            response = await this.privateOptionsGetPositions(this.extend(request, params));
        }
        //
        // swap and future
        //
        //     [
        //         {
        //             "value": "4.602828",
        //             "leverage": "0",
        //             "mode": "single",
        //             "realised_point": "0",
        //             "contract": "BTC_USDT",
        //             "entry_price": "46030.3",
        //             "mark_price": "46028.28",
        //             "history_point": "0",
        //             "realised_pnl": "-0.002301515",
        //             "close_order": null,
        //             "size": 1,
        //             "cross_leverage_limit": "0",
        //             "pending_orders": 0,
        //             "adl_ranking": 5,
        //             "maintenance_rate": "0.004",
        //             "unrealised_pnl": "-0.000202",
        //             "user": 5691076,
        //             "leverage_max": "125",
        //             "history_pnl": "0",
        //             "risk_limit": "1000000",
        //             "margin": "8.997698485",
        //             "last_close_pnl": "0",
        //             "liq_price": "0",
        //             "update_time": 1705034246,
        //             "update_id": 1,
        //             "initial_margin": "0",
        //             "maintenance_margin": "0",
        //             "open_time": 1705034246,
        //             "trade_max_size": "0"
        //         }
        //     ]
        //
        // option
        //
        //     [
        //         {
        //             "close_order": null,
        //             "size": 0,
        //             "vega": "0.01907",
        //             "theta": "-3.04888",
        //             "gamma": "0.00001",
        //             "delta": "0.0011",
        //             "contract": "BTC_USDT-20230601-27500-C",
        //             "entry_price": "0",
        //             "unrealised_pnl": "0",
        //             "user": 5691076,
        //             "mark_price": "0.07",
        //             "underlying_price": "26817.27",
        //             "underlying": "BTC_USDT",
        //             "realised_pnl": "0",
        //             "mark_iv": "0.4339",
        //             "pending_orders": 0
        //         }
        //     ]
        //
        return this.parsePositions(response, symbols);
    }
    /**
     * @method
     * @name gate#fetchLeverageTiers
     * @description retrieve information on the maximum leverage, and maintenance margin for trades of varying trade sizes
     * @see https://www.gate.io/docs/developers/apiv4/en/#list-all-futures-contracts
     * @see https://www.gate.io/docs/developers/apiv4/en/#list-all-futures-contracts-2
     * @param {string[]} [symbols] list of unified market symbols
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @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();
        const [type, query] = this.handleMarketTypeAndParams('fetchLeverageTiers', undefined, params);
        const [request, requestParams] = this.prepareRequest(undefined, type, query);
        if (type !== 'future' && type !== 'swap') {
            throw new errors.BadRequest(this.id + ' fetchLeverageTiers only supports swap and future');
        }
        let response = undefined;
        if (type === 'swap') {
            response = await this.publicFuturesGetSettleContracts(this.extend(request, requestParams));
        }
        else if (type === 'future') {
            response = await this.publicDeliveryGetSettleContracts(this.extend(request, requestParams));
        }
        else {
            throw new errors.NotSupported(this.id + ' fetchLeverageTiers() not support this market type');
        }
        //
        // Perpetual swap
        //
        //    [
        //        {
        //            "name": "BTC_USDT",
        //            "type": "direct",
        //            "quanto_multiplier": "0.0001",
        //            "ref_discount_rate": "0",
        //            "order_price_deviate": "0.5",
        //            "maintenance_rate": "0.005",
        //            "mark_type": "index",
        //            "last_price": "38026",
        //            "mark_price": "37985.6",
        //            "index_price": "37954.92",
        //            "funding_rate_indicative": "0.000219",
        //            "mark_price_round": "0.01",
        //            "funding_offset": 0,
        //            "in_delisting": false,
        //            "risk_limit_base": "1000000",
        //            "interest_rate": "0.0003",
        //            "order_price_round": "0.1",
        //            "order_size_min": 1,
        //            "ref_rebate_rate": "0.2",
        //            "funding_interval": 28800,
        //            "risk_limit_step": "1000000",
        //            "leverage_min": "1",
        //            "leverage_max": "100",
        //            "risk_limit_max": "8000000",
        //            "maker_fee_rate": "-0.00025",
        //            "taker_fee_rate": "0.00075",
        //            "funding_rate": "0.002053",
        //            "order_size_max": 1000000,
        //            "funding_next_apply": 1610035200,
        //            "short_users": 977,
        //            "config_change_time": 1609899548,
        //            "trade_size": 28530850594,
        //            "position_size": 5223816,
        //            "long_users": 455,
        //            "funding_impact_value": "60000",
        //            "orders_limit": 50,
        //            "trade_id": 10851092,
        //            "orderbook_id": 2129638396
        //        }
        //    ]
        //
        // Delivery Futures
        //
        //    [
        //        {
        //            "name": "BTC_USDT_20200814",
        //            "underlying": "BTC_USDT",
        //            "cycle": "WEEKLY",
        //            "type": "direct",
        //            "quanto_multiplier": "0.0001",
        //            "mark_type": "index",
        //            "last_price": "9017",
        //            "mark_price": "9019",
        //            "index_price": "9005.3",
        //            "basis_rate": "0.185095",
        //            "basis_value": "13.7",
        //            "basis_impact_value": "100000",
        //            "settle_price": "0",
        //            "settle_price_interval": 60,
        //            "settle_price_duration": 1800,
        //            "settle_fee_rate": "0.0015",
        //            "expire_time": 1593763200,
        //            "order_price_round": "0.1",
        //            "mark_price_round": "0.1",
        //            "leverage_min": "1",
        //            "leverage_max": "100",
        //            "maintenance_rate": "1000000",
        //            "risk_limit_base": "140.726652109199",
        //            "risk_limit_step": "1000000",
        //            "risk_limit_max": "8000000",
        //            "maker_fee_rate": "-0.00025",
        //            "taker_fee_rate": "0.00075",
        //            "ref_discount_rate": "0",
        //            "ref_rebate_rate": "0.2",
        //            "order_price_deviate": "0.5",
        //            "order_size_min": 1,
        //            "order_size_max": 1000000,
        //            "orders_limit": 50,
        //            "orderbook_id": 63,
        //            "trade_id": 26,
        //            "trade_size": 435,
        //            "position_size": 130,
        //            "config_change_time": 1593158867,
        //            "in_delisting": false
        //        }
        //    ]
        //
        return this.parseLeverageTiers(response, symbols, 'name');
    }
    /**
     * @method
     * @name gate#fetchMarketLeverageTiers
     * @description retrieve information on the maximum leverage, and maintenance margin for trades of varying trade sizes for a single market
     * @see https://www.gate.io/docs/developers/apiv4/en/#list-risk-limit-tiers
     * @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();
        const market = this.market(symbol);
        const [type, query] = this.handleMarketTypeAndParams('fetchMarketLeverageTiers', market, params);
        const [request, requestParams] = this.prepareRequest(market, type, query);
        if (type !== 'future' && type !== 'swap') {
            throw new errors.BadRequest(this.id + ' fetchMarketLeverageTiers only supports swap and future');
        }
        const response = await this.privateFuturesGetSettleRiskLimitTiers(this.extend(request, requestParams));
        //
        //     [
        //         {
        //             "maintenance_rate": "0.004",
        //             "tier": 1,
        //             "initial_rate": "0.008",
        //             "leverage_max": "125",
        //             "risk_limit": "1000000"
        //         }
        //     ]
        //
        return this.parseMarketLeverageTiers(response, market);
    }
    parseEmulatedLeverageTiers(info, market = undefined) {
        const marketId = this.safeString(info, 'name');
        const maintenanceMarginUnit = this.safeString(info, 'maintenance_rate'); // '0.005',
        const leverageMax = this.safeString(info, 'leverage_max'); // '100',
        const riskLimitStep = this.safeString(info, 'risk_limit_step'); // '1000000',
        const riskLimitMax = this.safeString(info, 'risk_limit_max'); // '16000000',
        const initialMarginUnit = Precise["default"].stringDiv('1', leverageMax);
        let maintenanceMarginRate = maintenanceMarginUnit;
        let initialMarginRatio = initialMarginUnit;
        let floor = '0';
        const tiers = [];
        while (Precise["default"].stringLt(floor, riskLimitMax)) {
            const cap = Precise["default"].stringAdd(floor, riskLimitStep);
            tiers.push({
                'tier': this.parseNumber(Precise["default"].stringDiv(cap, riskLimitStep)),
                'symbol': this.safeSymbol(marketId, market, undefined, 'contract'),
                'currency': this.safeString(market, 'settle'),
                'minNotional': this.parseNumber(floor),
                'maxNotional': this.parseNumber(cap),
                'maintenanceMarginRate': this.parseNumber(maintenanceMarginRate),
                'maxLeverage': this.parseNumber(Precise["default"].stringDiv('1', initialMarginRatio)),
                'info': info,
            });
            maintenanceMarginRate = Precise["default"].stringAdd(maintenanceMarginRate, maintenanceMarginUnit);
            initialMarginRatio = Precise["default"].stringAdd(initialMarginRatio, initialMarginUnit);
            floor = cap;
        }
        return tiers;
    }
    parseMarketLeverageTiers(info, market = undefined) {
        //
        //     [
        //         {
        //             "maintenance_rate": "0.004",
        //             "tier": 1,
        //             "initial_rate": "0.008",
        //             "leverage_max": "125",
        //             "risk_limit": "1000000"
        //         }
        //     ]
        //
        if (!Array.isArray(info)) {
            return this.parseEmulatedLeverageTiers(info, market);
        }
        let minNotional = 0;
        const tiers = [];
        for (let i = 0; i < info.length; i++) {
            const item = info[i];
            const maxNotional = this.safeNumber(item, 'risk_limit');
            tiers.push({
                'tier': this.sum(i, 1),
                'symbol': market['symbol'],
                'currency': market['base'],
                'minNotional': minNotional,
                'maxNotional': maxNotional,
                'maintenanceMarginRate': this.safeNumber(item, 'maintenance_rate'),
                'maxLeverage': this.safeNumber(item, 'leverage_max'),
                'info': item,
            });
            minNotional = maxNotional;
        }
        return tiers;
    }
    /**
     * @method
     * @name gate#repayMargin
     * @description repay borrowed margin and interest
     * @see https://www.gate.io/docs/apiv4/en/#repay-a-loan
     * @param {string} symbol unified market symbol
     * @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
     * @param {string} [params.mode] 'all' or 'partial' payment mode, extra parameter required for isolated margin
     * @param {string} [params.id] '34267567' loan id, extra parameter required for isolated margin
     * @returns {object} a [margin loan structure]{@link https://docs.ccxt.com/#/?id=margin-loan-structure}
     */
    async repayIsolatedMargin(symbol, code, amount, params = {}) {
        await this.loadMarkets();
        const currency = this.currency(code);
        const request = {
            'currency': currency['id'].toUpperCase(),
            'amount': this.currencyToPrecision(code, amount),
        };
        const market = this.market(symbol);
        request['currency_pair'] = market['id'];
        request['type'] = 'repay';
        const response = await this.privateMarginPostUniLoans(this.extend(request, params));
        //
        // empty response
        //
        return this.parseMarginLoan(response, currency);
    }
    /**
     * @method
     * @name gate#repayCrossMargin
     * @description repay cross margin borrowed margin and interest
     * @see https://www.gate.io/docs/developers/apiv4/en/#cross-margin-repayments
     * @see https://www.gate.io/docs/developers/apiv4/en/#borrow-or-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
     * @param {string} [params.mode] 'all' or 'partial' payment mode, extra parameter required for isolated margin
     * @param {string} [params.id] '34267567' loan id, extra parameter required for isolated margin
     * @param {boolean} [params.unifiedAccount] set to true for repaying in the unified account
     * @returns {object} a [margin loan structure]{@link https://docs.ccxt.com/#/?id=margin-loan-structure}
     */
    async repayCrossMargin(code, amount, params = {}) {
        await this.loadMarkets();
        await this.loadUnifiedStatus();
        const currency = this.currency(code);
        const request = {
            'currency': currency['id'].toUpperCase(),
            'amount': this.currencyToPrecision(code, amount),
        };
        let isUnifiedAccount = false;
        [isUnifiedAccount, params] = this.handleOptionAndParams(params, 'repayCrossMargin', 'unifiedAccount');
        let response = undefined;
        if (isUnifiedAccount) {
            request['type'] = 'repay';
            response = await this.privateUnifiedPostLoans(this.extend(request, params));
        }
        else {
            response = await this.privateMarginPostCrossRepayments(this.extend(request, params));
            response = this.safeDict(response, 0);
            //
            //     [
            //         {
            //             "id": "17",
            //             "create_time": 1620381696159,
            //             "update_time": 1620381696159,
            //             "currency": "EOS",
            //             "amount": "110.553635",
            //             "text": "web",
            //             "status": 2,
            //             "repaid": "110.506649705159",
            //             "repaid_interest": "0.046985294841",
            //             "unpaid_interest": "0.0000074393366667"
            //         }
            //     ]
            //
        }
        return this.parseMarginLoan(response, currency);
    }
    /**
     * @method
     * @name gate#borrowIsolatedMargin
     * @description create a loan to borrow margin
     * @see https://www.gate.io/docs/developers/apiv4/en/#marginuni
     * @param {string} symbol unified market symbol, required for isolated margin
     * @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
     * @param {string} [params.rate] '0.0002' or '0.002' extra parameter required for isolated margin
     * @returns {object} a [margin loan structure]{@link https://docs.ccxt.com/#/?id=margin-loan-structure}
     */
    async borrowIsolatedMargin(symbol, code, amount, params = {}) {
        await this.loadMarkets();
        const currency = this.currency(code);
        const request = {
            'currency': currency['id'].toUpperCase(),
            'amount': this.currencyToPrecision(code, amount),
        };
        let response = undefined;
        const market = this.market(symbol);
        request['currency_pair'] = market['id'];
        request['type'] = 'borrow';
        response = await this.privateMarginPostUniLoans(this.extend(request, params));
        //
        //     {
        //         "id": "34267567",
        //         "create_time": "1656394778",
        //         "expire_time": "1657258778",
        //         "status": "loaned",
        //         "side": "borrow",
        //         "currency": "USDT",
        //         "rate": "0.0002",
        //         "amount": "100",
        //         "days": 10,
        //         "auto_renew": false,
        //         "currency_pair": "LTC_USDT",
        //         "left": "0",
        //         "repaid": "0",
        //         "paid_interest": "0",
        //         "unpaid_interest": "0.003333333333"
        //     }
        //
        return this.parseMarginLoan(response, currency);
    }
    /**
     * @method
     * @name gate#borrowMargin
     * @description create a loan to borrow margin
     * @see https://www.gate.io/docs/apiv4/en/#create-a-cross-margin-borrow-loan
     * @see https://www.gate.io/docs/developers/apiv4/en/#borrow-or-repay
     * @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
     * @param {string} [params.rate] '0.0002' or '0.002' extra parameter required for isolated margin
     * @param {boolean} [params.unifiedAccount] set to true for borrowing in the unified account
     * @returns {object} a [margin loan structure]{@link https://docs.ccxt.com/#/?id=margin-loan-structure}
     */
    async borrowCrossMargin(code, amount, params = {}) {
        await this.loadMarkets();
        await this.loadUnifiedStatus();
        const currency = this.currency(code);
        const request = {
            'currency': currency['id'].toUpperCase(),
            'amount': this.currencyToPrecision(code, amount),
        };
        let isUnifiedAccount = false;
        [isUnifiedAccount, params] = this.handleOptionAndParams(params, 'borrowCrossMargin', 'unifiedAccount');
        let response = undefined;
        if (isUnifiedAccount) {
            request['type'] = 'borrow';
            response = await this.privateUnifiedPostLoans(this.extend(request, params));
        }
        else {
            response = await this.privateMarginPostCrossLoans(this.extend(request, params));
            //
            //     {
            //         "id": "17",
            //         "create_time": 1620381696159,
            //         "update_time": 1620381696159,
            //         "currency": "EOS",
            //         "amount": "110.553635",
            //         "text": "web",
            //         "status": 2,
            //         "repaid": "110.506649705159",
            //         "repaid_interest": "0.046985294841",
            //         "unpaid_interest": "0.0000074393366667"
            //     }
            //
        }
        return this.parseMarginLoan(response, currency);
    }
    parseMarginLoan(info, currency = undefined) {
        //
        // Cross
        //
        //     {
        //         "id": "17",
        //         "create_time": 1620381696159,
        //         "update_time": 1620381696159,
        //         "currency": "EOS",
        //         "amount": "110.553635",
        //         "text": "web",
        //         "status": 2,
        //         "repaid": "110.506649705159",
        //         "repaid_interest": "0.046985294841",
        //         "unpaid_interest": "0.0000074393366667"
        //     }
        //
        // Isolated
        //
        //     {
        //         "id": "34267567",
        //         "create_time": "1656394778",
        //         "expire_time": "1657258778",
        //         "status": "loaned",
        //         "side": "borrow",
        //         "currency": "USDT",
        //         "rate": "0.0002",
        //         "amount": "100",
        //         "days": 10,
        //         "auto_renew": false,
        //         "currency_pair": "LTC_USDT",
        //         "left": "0",
        //         "repaid": "0",
        //         "paid_interest": "0",
        //         "unpaid_interest": "0.003333333333"
        //     }
        //
        const marginMode = this.safeString2(this.options, 'defaultMarginMode', 'marginMode', 'cross');
        let timestamp = this.safeInteger(info, 'create_time');
        if (marginMode === 'isolated') {
            timestamp = this.safeTimestamp(info, 'create_time');
        }
        const currencyId = this.safeString(info, 'currency');
        const marketId = this.safeString(info, 'currency_pair');
        return {
            'id': this.safeInteger(info, 'id'),
            'currency': this.safeCurrencyCode(currencyId, currency),
            'amount': this.safeNumber(info, 'amount'),
            'symbol': this.safeSymbol(marketId, undefined, '_', 'margin'),
            'timestamp': timestamp,
            'datetime': this.iso8601(timestamp),
            'info': info,
        };
    }
    /**
     * @method
     * @name gate#fetchBorrowInterest
     * @description fetch the interest owed by the user for borrowing currency for margin trading
     * @see https://www.gate.io/docs/developers/apiv4/en/#list-interest-records
     * @see https://www.gate.io/docs/developers/apiv4/en/#interest-records-for-the-cross-margin-account
     * @see https://www.gate.io/docs/developers/apiv4/en/#list-interest-records-2
     * @param {string} [code] unified currency code
     * @param {string} [symbol] unified market symbol when fetching interest in isolated markets
     * @param {int} [since] the earliest time in ms to fetch borrow interest for
     * @param {int} [limit] the maximum number of structures to retrieve
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @param {boolean} [params.unifiedAccount] set to true for fetching borrow interest in the unified account
     * @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();
        await this.loadUnifiedStatus();
        let isUnifiedAccount = false;
        [isUnifiedAccount, params] = this.handleOptionAndParams(params, 'fetchBorrowInterest', 'unifiedAccount');
        let request = {};
        [request, params] = this.handleUntilOption('to', request, params);
        let currency = undefined;
        if (code !== undefined) {
            currency = this.currency(code);
            request['currency'] = currency['id'];
        }
        let market = undefined;
        if (symbol !== undefined) {
            market = this.market(symbol);
        }
        if (since !== undefined) {
            request['from'] = since;
        }
        if (limit !== undefined) {
            request['limit'] = limit;
        }
        let response = undefined;
        let marginMode = undefined;
        [marginMode, params] = this.handleMarginModeAndParams('fetchBorrowInterest', params, 'cross');
        if (isUnifiedAccount) {
            response = await this.privateUnifiedGetInterestRecords(this.extend(request, params));
        }
        else if (marginMode === 'isolated') {
            if (market !== undefined) {
                request['currency_pair'] = market['id'];
            }
            response = await this.privateMarginGetUniInterestRecords(this.extend(request, params));
        }
        else if (marginMode === 'cross') {
            response = await this.privateMarginGetCrossInterestRecords(this.extend(request, params));
        }
        const interest = this.parseBorrowInterests(response, market);
        return this.filterByCurrencySinceLimit(interest, code, since, limit);
    }
    parseBorrowInterest(info, market = undefined) {
        const marketId = this.safeString(info, 'currency_pair');
        market = this.safeMarket(marketId, market);
        const marginMode = (marketId !== undefined) ? 'isolated' : 'cross';
        const timestamp = this.safeInteger(info, 'create_time');
        return {
            'info': info,
            'symbol': this.safeString(market, 'symbol'),
            'currency': this.safeCurrencyCode(this.safeString(info, 'currency')),
            'interest': this.safeNumber(info, 'interest'),
            'interestRate': this.safeNumber(info, 'actual_rate'),
            'amountBorrowed': undefined,
            'marginMode': marginMode,
            'timestamp': timestamp,
            'datetime': this.iso8601(timestamp),
        };
    }
    nonce() {
        return this.milliseconds() - this.options['timeDifference'];
    }
    sign(path, api = [], method = 'GET', params = {}, headers = undefined, body = undefined) {
        const authentication = api[0]; // public, private
        const type = api[1]; // spot, margin, future, delivery
        let query = this.omit(params, this.extractParams(path));
        const containsSettle = path.indexOf('settle') > -1;
        if (containsSettle && path.endsWith('batch_cancel_orders')) { // weird check to prevent $settle in php and converting {settle} to array(settle)
            // special case where we need to extract the settle from the path
            // but the body is an array of strings
            const settle = this.safeDict(params, 0);
            path = this.implodeParams(path, settle);
            // remove the first element from params
            const newParams = [];
            const anyParams = params;
            for (let i = 1; i < anyParams.length; i++) {
                newParams.push(params[i]);
            }
            params = newParams;
            query = newParams;
        }
        else if (Array.isArray(params)) {
            // endpoints like createOrders use an array instead of an object
            // so we infer the settle from one of the elements
            // they have to be all the same so relying on the first one is fine
            const first = this.safeValue(params, 0, {});
            path = this.implodeParams(path, first);
        }
        else {
            path = this.implodeParams(path, params);
        }
        const endPart = (path === '') ? '' : ('/' + path);
        let entirePath = '/' + type + endPart;
        if ((type === 'subAccounts') || (type === 'withdrawals')) {
            entirePath = endPart;
        }
        let url = this.urls['api'][authentication][type];
        if (url === undefined) {
            throw new errors.NotSupported(this.id + ' does not have a testnet for the ' + type + ' market type.');
        }
        url += entirePath;
        if (authentication === 'public') {
            if (Object.keys(query).length) {
                url += '?' + this.urlencode(query);
            }
        }
        else {
            this.checkRequiredCredentials();
            let queryString = '';
            let requiresURLEncoding = false;
            if (((type === 'futures') || (type === 'delivery')) && method === 'POST') {
                const pathParts = path.split('/');
                const secondPart = this.safeString(pathParts, 1, '');
                requiresURLEncoding = (secondPart.indexOf('dual') >= 0) || (secondPart.indexOf('positions') >= 0);
            }
            if ((method === 'GET') || (method === 'DELETE') || requiresURLEncoding || (method === 'PATCH')) {
                if (Object.keys(query).length) {
                    queryString = this.urlencode(query);
                    // https://github.com/ccxt/ccxt/issues/25570
                    if (queryString.indexOf('currencies=') >= 0 && queryString.indexOf('%2C') >= 0) {
                        queryString = queryString.replaceAll('%2C', ',');
                    }
                    url += '?' + queryString;
                }
                if (method === 'PATCH') {
                    body = this.json(query);
                }
            }
            else {
                const urlQueryParams = this.safeValue(query, 'query', {});
                if (Object.keys(urlQueryParams).length) {
                    queryString = this.urlencode(urlQueryParams);
                    url += '?' + queryString;
                }
                query = this.omit(query, 'query');
                body = this.json(query);
            }
            const bodyPayload = (body === undefined) ? '' : body;
            const bodySignature = this.hash(this.encode(bodyPayload), sha512.sha512);
            const nonce = this.nonce();
            const timestamp = this.parseToInt(nonce / 1000);
            const timestampString = timestamp.toString();
            const signaturePath = '/api/' + this.version + entirePath;
            const payloadArray = [method.toUpperCase(), signaturePath, queryString, bodySignature, timestampString];
            // eslint-disable-next-line quotes
            const payload = payloadArray.join("\n");
            const signature = this.hmac(this.encode(payload), this.encode(this.secret), sha512.sha512);
            headers = {
                'KEY': this.apiKey,
                'Timestamp': timestampString,
                'SIGN': signature,
                'Content-Type': 'application/json',
            };
        }
        return { 'url': url, 'method': method, 'body': body, 'headers': headers };
    }
    async modifyMarginHelper(symbol, amount, params = {}) {
        await this.loadMarkets();
        const market = this.market(symbol);
        const [request, query] = this.prepareRequest(market, undefined, params);
        request['change'] = this.numberToString(amount);
        let response = undefined;
        if (market['swap']) {
            response = await this.privateFuturesPostSettlePositionsContractMargin(this.extend(request, query));
        }
        else if (market['future']) {
            response = await this.privateDeliveryPostSettlePositionsContractMargin(this.extend(request, query));
        }
        else {
            throw new errors.NotSupported(this.id + ' modifyMarginHelper() not support this market type');
        }
        return this.parseMarginModification(response, market);
    }
    parseMarginModification(data, market = undefined) {
        //
        //     {
        //         "value": "11.9257",
        //         "leverage": "5",
        //         "mode": "single",
        //         "realised_point": "0",
        //         "contract": "ETH_USDT",
        //         "entry_price": "1203.45",
        //         "mark_price": "1192.57",
        //         "history_point": "0",
        //         "realised_pnl": "-0.00577656",
        //         "close_order": null,
        //         "size": "1",
        //         "cross_leverage_limit": "0",
        //         "pending_orders": "0",
        //         "adl_ranking": "5",
        //         "maintenance_rate": "0.005",
        //         "unrealised_pnl": "-0.1088",
        //         "user": "1486602",
        //         "leverage_max": "100",
        //         "history_pnl": "0",
        //         "risk_limit": "1000000",
        //         "margin": "5.415925875",
        //         "last_close_pnl": "0",
        //         "liq_price": "665.69"
        //     }
        //
        const contract = this.safeString(data, 'contract');
        market = this.safeMarket(contract, market, '_', 'contract');
        const total = this.safeNumber(data, 'margin');
        return {
            'info': data,
            'symbol': market['symbol'],
            'type': undefined,
            'marginMode': 'isolated',
            'amount': undefined,
            'total': total,
            'code': this.safeValue(market, 'quote'),
            'status': 'ok',
            'timestamp': undefined,
            'datetime': undefined,
        };
    }
    /**
     * @method
     * @name gate#reduceMargin
     * @description remove margin from a position
     * @see https://www.gate.io/docs/developers/apiv4/en/#update-position-margin
     * @see https://www.gate.io/docs/developers/apiv4/en/#update-position-margin-2
     * @param {string} symbol unified market symbol
     * @param {float} amount the amount of margin to remove
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {object} a [margin structure]{@link https://docs.ccxt.com/#/?id=reduce-margin-structure}
     */
    async reduceMargin(symbol, amount, params = {}) {
        return await this.modifyMarginHelper(symbol, -amount, params);
    }
    /**
     * @method
     * @name gate#addMargin
     * @description add margin
     * @see https://www.gate.io/docs/developers/apiv4/en/#update-position-margin
     * @see https://www.gate.io/docs/developers/apiv4/en/#update-position-margin-2
     * @param {string} symbol unified market symbol
     * @param {float} amount amount of margin to add
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {object} a [margin structure]{@link https://docs.ccxt.com/#/?id=add-margin-structure}
     */
    async addMargin(symbol, amount, params = {}) {
        return await this.modifyMarginHelper(symbol, amount, params);
    }
    /**
     * @method
     * @name gate#fetchOpenInterest
     * @description Retrieves the open interest of a currency
     * @see https://www.gate.io/docs/developers/apiv4/en/#futures-stats
     * @param {string} symbol Unified CCXT market symbol
     * @param {string} timeframe "5m", "15m", "30m", "1h", "4h", "1d"
     * @param {int} [since] the time(ms) of the earliest record to retrieve as a unix timestamp
     * @param {int} [limit] default 30
     * @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 {object} an open interest structure{@link https://docs.ccxt.com/#/?id=open-interest-structure}
     */
    async fetchOpenInterestHistory(symbol, timeframe = '5m', since = undefined, limit = undefined, params = {}) {
        await this.loadMarkets();
        let paginate = false;
        [paginate, params] = this.handleOptionAndParams(params, 'fetchOpenInterestHistory', 'paginate', false);
        if (paginate) {
            return await this.fetchPaginatedCallDeterministic('fetchOpenInterestHistory', symbol, since, limit, timeframe, params, 100);
        }
        const market = this.market(symbol);
        if (!market['swap']) {
            throw new errors.BadRequest(this.id + ' fetchOpenInterest() supports swap markets only');
        }
        const request = {
            'contract': market['id'],
            'settle': market['settleId'],
            'interval': this.safeString(this.timeframes, timeframe, timeframe),
        };
        if (limit !== undefined) {
            request['limit'] = limit;
        }
        if (since !== undefined) {
            request['from'] = since;
        }
        const response = await this.publicFuturesGetSettleContractStats(this.extend(request, params));
        //
        //    [
        //        {
        //            "long_liq_size": "0",
        //            "short_liq_size": "0",
        //            "short_liq_usd": "0",
        //            "lsr_account": "3.2808988764045",
        //            "mark_price": "0.34619",
        //            "top_lsr_size": "0",
        //            "time": "1674057000",
        //            "short_liq_amount": "0",
        //            "long_liq_amount": "0",
        //            "open_interest_usd": "9872386.7775",
        //            "top_lsr_account": "0",
        //            "open_interest": "2851725",
        //            "long_liq_usd": "0",
        //            "lsr_taker": "9.3765153315902"
        //        },
        //        ...
        //    ]
        //
        return this.parseOpenInterestsHistory(response, market, since, limit);
    }
    parseOpenInterest(interest, market = undefined) {
        //
        //    {
        //        "long_liq_size": "0",
        //        "short_liq_size": "0",
        //        "short_liq_usd": "0",
        //        "lsr_account": "3.2808988764045",
        //        "mark_price": "0.34619",
        //        "top_lsr_size": "0",
        //        "time": "1674057000",
        //        "short_liq_amount": "0",
        //        "long_liq_amount": "0",
        //        "open_interest_usd": "9872386.7775",
        //        "top_lsr_account": "0",
        //        "open_interest": "2851725",
        //        "long_liq_usd": "0",
        //        "lsr_taker": "9.3765153315902"
        //    }
        //
        const timestamp = this.safeTimestamp(interest, 'time');
        return {
            'symbol': this.safeString(market, 'symbol'),
            'openInterestAmount': this.safeNumber(interest, 'open_interest'),
            'openInterestValue': this.safeNumber(interest, 'open_interest_usd'),
            'timestamp': timestamp,
            'datetime': this.iso8601(timestamp),
            'info': interest,
        };
    }
    /**
     * @method
     * @name gate#fetchSettlementHistory
     * @description fetches historical settlement records
     * @see https://www.gate.io/docs/developers/apiv4/en/#list-settlement-history-2
     * @param {string} symbol unified market symbol of the settlement history, required on gate
     * @param {int} [since] timestamp in ms
     * @param {int} [limit] number of records
     * @param {object} [params] exchange specific params
     * @returns {object[]} a list of [settlement history objects]{@link https://docs.ccxt.com/#/?id=settlement-history-structure}
     */
    async fetchSettlementHistory(symbol = undefined, since = undefined, limit = undefined, params = {}) {
        if (symbol === undefined) {
            throw new errors.ArgumentsRequired(this.id + ' fetchSettlementHistory() requires a symbol argument');
        }
        await this.loadMarkets();
        const market = this.market(symbol);
        let type = undefined;
        [type, params] = this.handleMarketTypeAndParams('fetchSettlementHistory', market, params);
        if (type !== 'option') {
            throw new errors.NotSupported(this.id + ' fetchSettlementHistory() supports option markets only');
        }
        const marketId = market['id'];
        const optionParts = marketId.split('-');
        const request = {
            'underlying': this.safeString(optionParts, 0),
        };
        if (since !== undefined) {
            request['from'] = since;
        }
        if (limit !== undefined) {
            request['limit'] = limit;
        }
        const response = await this.publicOptionsGetSettlements(this.extend(request, params));
        //
        //     [
        //         {
        //             "time": 1685952000,
        //             "profit": "18.266806892718",
        //             "settle_price": "26826.68068927182",
        //             "fee": "0.040240021034",
        //             "contract": "BTC_USDT-20230605-25000-C",
        //             "strike_price": "25000"
        //         }
        //     ]
        //
        const settlements = this.parseSettlements(response, market);
        const sorted = this.sortBy(settlements, 'timestamp');
        return this.filterBySymbolSinceLimit(sorted, symbol, since, limit);
    }
    /**
     * @method
     * @name gate#fetchMySettlementHistory
     * @description fetches historical settlement records of the user
     * @see https://www.gate.io/docs/developers/apiv4/en/#list-my-options-settlements
     * @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
     * @returns {object[]} a list of [settlement history objects]
     */
    async fetchMySettlementHistory(symbol = undefined, since = undefined, limit = undefined, params = {}) {
        if (symbol === undefined) {
            throw new errors.ArgumentsRequired(this.id + ' fetchMySettlementHistory() requires a symbol argument');
        }
        await this.loadMarkets();
        const market = this.market(symbol);
        let type = undefined;
        [type, params] = this.handleMarketTypeAndParams('fetchMySettlementHistory', market, params);
        if (type !== 'option') {
            throw new errors.NotSupported(this.id + ' fetchMySettlementHistory() supports option markets only');
        }
        const marketId = market['id'];
        const optionParts = marketId.split('-');
        const request = {
            'underlying': this.safeString(optionParts, 0),
            'contract': marketId,
        };
        if (since !== undefined) {
            request['from'] = since;
        }
        if (limit !== undefined) {
            request['limit'] = limit;
        }
        const response = await this.privateOptionsGetMySettlements(this.extend(request, params));
        //
        //     [
        //         {
        //             "size": -1,
        //             "settle_profit": "0",
        //             "contract": "BTC_USDT-20220624-26000-C",
        //             "strike_price": "26000",
        //             "time": 1656057600,
        //             "settle_price": "20917.461281337048",
        //             "underlying": "BTC_USDT",
        //             "realised_pnl": "-0.00116042",
        //             "fee": "0"
        //         }
        //     ]
        //
        const result = this.safeValue(response, 'result', {});
        const data = this.safeValue(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
        //
        //     {
        //         "time": 1685952000,
        //         "profit": "18.266806892718",
        //         "settle_price": "26826.68068927182",
        //         "fee": "0.040240021034",
        //         "contract": "BTC_USDT-20230605-25000-C",
        //         "strike_price": "25000"
        //     }
        //
        // fetchMySettlementHistory
        //
        //     {
        //         "size": -1,
        //         "settle_profit": "0",
        //         "contract": "BTC_USDT-20220624-26000-C",
        //         "strike_price": "26000",
        //         "time": 1656057600,
        //         "settle_price": "20917.461281337048",
        //         "underlying": "BTC_USDT",
        //         "realised_pnl": "-0.00116042",
        //         "fee": "0"
        //     }
        //
        const timestamp = this.safeTimestamp(settlement, 'time');
        const marketId = this.safeString(settlement, 'contract');
        return {
            'info': settlement,
            'symbol': this.safeSymbol(marketId, market),
            'price': this.safeNumber(settlement, 'settle_price'),
            'timestamp': timestamp,
            'datetime': this.iso8601(timestamp),
        };
    }
    parseSettlements(settlements, market) {
        //
        // fetchSettlementHistory
        //
        //     [
        //         {
        //             "time": 1685952000,
        //             "profit": "18.266806892718",
        //             "settle_price": "26826.68068927182",
        //             "fee": "0.040240021034",
        //             "contract": "BTC_USDT-20230605-25000-C",
        //             "strike_price": "25000"
        //         }
        //     ]
        //
        // fetchMySettlementHistory
        //
        //     [
        //         {
        //             "size": -1,
        //             "settle_profit": "0",
        //             "contract": "BTC_USDT-20220624-26000-C",
        //             "strike_price": "26000",
        //             "time": 1656057600,
        //             "settle_price": "20917.461281337048",
        //             "underlying": "BTC_USDT",
        //             "realised_pnl": "-0.00116042",
        //             "fee": "0"
        //         }
        //     ]
        //
        const result = [];
        for (let i = 0; i < settlements.length; i++) {
            result.push(this.parseSettlement(settlements[i], market));
        }
        return result;
    }
    /**
     * @method
     * @name gate#fetchLedger
     * @description fetch the history of changes, actions done by the user or operations that altered the balance of the user
     * @see https://www.gate.io/docs/developers/apiv4/en/#query-account-book
     * @see https://www.gate.io/docs/developers/apiv4/en/#list-margin-account-balance-change-history
     * @see https://www.gate.io/docs/developers/apiv4/en/#query-account-book-2
     * @see https://www.gate.io/docs/developers/apiv4/en/#query-account-book-3
     * @see https://www.gate.io/docs/developers/apiv4/en/#list-account-changing-history
     * @param {string} [code] unified currency code
     * @param {int} [since] timestamp in ms of the earliest ledger entry
     * @param {int} [limit] max number of ledger entries to return
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @param {int} [params.until] end time in ms
     * @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 [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.fetchPaginatedCallDynamic('fetchLedger', code, since, limit, params);
        }
        let type = undefined;
        let currency = undefined;
        let response = undefined;
        let request = {};
        [type, params] = this.handleMarketTypeAndParams('fetchLedger', undefined, params);
        if ((type === 'spot') || (type === 'margin')) {
            if (code !== undefined) {
                currency = this.currency(code);
                request['currency'] = currency['id']; // todo: currencies have network-junctions
            }
        }
        if ((type === 'swap') || (type === 'future')) {
            const defaultSettle = (type === 'swap') ? 'usdt' : 'btc';
            const settle = this.safeStringLower(params, 'settle', defaultSettle);
            params = this.omit(params, 'settle');
            request['settle'] = settle;
        }
        if (since !== undefined) {
            request['from'] = since;
        }
        if (limit !== undefined) {
            request['limit'] = limit;
        }
        [request, params] = this.handleUntilOption('to', request, params);
        if (type === 'spot') {
            response = await this.privateSpotGetAccountBook(this.extend(request, params));
        }
        else if (type === 'margin') {
            response = await this.privateMarginGetAccountBook(this.extend(request, params));
        }
        else if (type === 'swap') {
            response = await this.privateFuturesGetSettleAccountBook(this.extend(request, params));
        }
        else if (type === 'future') {
            response = await this.privateDeliveryGetSettleAccountBook(this.extend(request, params));
        }
        else if (type === 'option') {
            response = await this.privateOptionsGetAccountBook(this.extend(request, params));
        }
        //
        // spot
        //
        //     [
        //         {
        //             "id": "123456",
        //             "time": 1547633726123,
        //             "currency": "BTC",
        //             "change": "1.03",
        //             "balance": "4.59316525194",
        //             "type": "margin_in"
        //         }
        //     ]
        //
        // margin
        //
        //     [
        //         {
        //             "id": "123456",
        //             "time": "1547633726",
        //             "time_ms": 1547633726123,
        //             "currency": "BTC",
        //             "currency_pair": "BTC_USDT",
        //             "change": "1.03",
        //             "balance": "4.59316525194"
        //         }
        //     ]
        //
        // swap and future
        //
        //     [
        //         {
        //             "time": 1682294400.123456,
        //             "change": "0.000010152188",
        //             "balance": "4.59316525194",
        //             "text": "ETH_USD:6086261",
        //             "type": "fee"
        //         }
        //     ]
        //
        // option
        //
        //     [
        //         {
        //             "time": 1685594770,
        //             "change": "3.33",
        //             "balance": "29.87911771",
        //             "text": "BTC_USDT-20230602-26500-C:2611026125",
        //             "type": "prem"
        //         }
        //     ]
        //
        return this.parseLedger(response, currency, since, limit);
    }
    parseLedgerEntry(item, currency = undefined) {
        //
        // spot
        //
        //     {
        //         "id": "123456",
        //         "time": 1547633726123,
        //         "currency": "BTC",
        //         "change": "1.03",
        //         "balance": "4.59316525194",
        //         "type": "margin_in"
        //     }
        //
        // margin
        //
        //     {
        //         "id": "123456",
        //         "time": "1547633726",
        //         "time_ms": 1547633726123,
        //         "currency": "BTC",
        //         "currency_pair": "BTC_USDT",
        //         "change": "1.03",
        //         "balance": "4.59316525194"
        //     }
        //
        // swap and future
        //
        //     {
        //         "time": 1682294400.123456,
        //         "change": "0.000010152188",
        //         "balance": "4.59316525194",
        //         "text": "ETH_USD:6086261",
        //         "type": "fee"
        //     }
        //
        // option
        //
        //     {
        //         "time": 1685594770,
        //         "change": "3.33",
        //         "balance": "29.87911771",
        //         "text": "BTC_USDT-20230602-26500-C:2611026125",
        //         "type": "prem"
        //     }
        //
        let direction = undefined;
        let amount = this.safeString(item, 'change');
        if (Precise["default"].stringLt(amount, '0')) {
            direction = 'out';
            amount = Precise["default"].stringAbs(amount);
        }
        else {
            direction = 'in';
        }
        const currencyId = this.safeString(item, 'currency');
        currency = this.safeCurrency(currencyId, currency);
        const type = this.safeString(item, 'type');
        const rawTimestamp = this.safeString(item, 'time');
        let timestamp = undefined;
        if (rawTimestamp.length > 10) {
            timestamp = parseInt(rawTimestamp);
        }
        else {
            timestamp = parseInt(rawTimestamp) * 1000;
        }
        const balanceString = this.safeString(item, 'balance');
        const changeString = this.safeString(item, 'change');
        const before = this.parseNumber(Precise["default"].stringSub(balanceString, changeString));
        return this.safeLedgerEntry({
            'info': item,
            'id': this.safeString(item, 'id'),
            'direction': direction,
            'account': undefined,
            'referenceAccount': undefined,
            'referenceId': undefined,
            'type': this.parseLedgerEntryType(type),
            'currency': this.safeCurrencyCode(currencyId, currency),
            'amount': this.parseNumber(amount),
            'timestamp': timestamp,
            'datetime': this.iso8601(timestamp),
            'before': before,
            'after': this.safeNumber(item, 'balance'),
            'status': undefined,
            'fee': undefined,
        }, currency);
    }
    parseLedgerEntryType(type) {
        const ledgerType = {
            'deposit': 'deposit',
            'withdraw': 'withdrawal',
            'sub_account_transfer': 'transfer',
            'margin_in': 'transfer',
            'margin_out': 'transfer',
            'margin_funding_in': 'transfer',
            'margin_funding_out': 'transfer',
            'cross_margin_in': 'transfer',
            'cross_margin_out': 'transfer',
            'copy_trading_in': 'transfer',
            'copy_trading_out': 'transfer',
            'quant_in': 'transfer',
            'quant_out': 'transfer',
            'futures_in': 'transfer',
            'futures_out': 'transfer',
            'delivery_in': 'transfer',
            'delivery_out': 'transfer',
            'new_order': 'trade',
            'order_fill': 'trade',
            'referral_fee': 'rebate',
            'order_fee': 'fee',
            'interest': 'interest',
            'lend': 'loan',
            'redeem': 'loan',
            'profit': 'interest',
            'flash_swap_buy': 'trade',
            'flash_swap_sell': 'trade',
            'unknown': 'unknown',
            'set': 'settlement',
            'prem': 'trade',
            'point_refr': 'rebate',
            'point_fee': 'fee',
            'point_dnw': 'deposit/withdraw',
            'fund': 'fee',
            'refr': 'rebate',
            'fee': 'fee',
            'pnl': 'trade',
            'dnw': 'deposit/withdraw',
        };
        return this.safeString(ledgerType, type, type);
    }
    /**
     * @method
     * @name gate#setPositionMode
     * @description set dual/hedged mode to true or false for a swap market, make sure all positions are closed and no orders are open before setting dual mode
     * @see https://www.gate.io/docs/developers/apiv4/en/#enable-or-disable-dual-mode
     * @param {bool} hedged set to true to enable dual mode
     * @param {string|undefined} symbol if passed, dual mode is set for all markets with the same settle currency
     * @param {object} params extra parameters specific to the exchange API endpoint
     * @param {string} params.settle settle currency
     * @returns {object} response from the exchange
     */
    async setPositionMode(hedged, symbol = undefined, params = {}) {
        const market = (symbol !== undefined) ? this.market(symbol) : undefined;
        const [request, query] = this.prepareRequest(market, 'swap', params);
        request['dual_mode'] = hedged;
        return await this.privateFuturesPostSettleDualMode(this.extend(request, query));
    }
    /**
     * @method
     * @name gate#fetchUnderlyingAssets
     * @description fetches the market ids of underlying assets for a specific contract market type
     * @see https://www.gate.io/docs/developers/apiv4/en/#list-all-underlyings
     * @param {object} [params] exchange specific params
     * @param {string} [params.type] the contract market type, 'option', 'swap' or 'future', the default is 'option'
     * @returns {object[]} a list of [underlying assets]{@link https://docs.ccxt.com/#/?id=underlying-assets-structure}
     */
    async fetchUnderlyingAssets(params = {}) {
        await this.loadMarkets();
        let marketType = undefined;
        [marketType, params] = this.handleMarketTypeAndParams('fetchUnderlyingAssets', undefined, params);
        if ((marketType === undefined) || (marketType === 'spot')) {
            marketType = 'option';
        }
        if (marketType !== 'option') {
            throw new errors.NotSupported(this.id + ' fetchUnderlyingAssets() supports option markets only');
        }
        const response = await this.publicOptionsGetUnderlyings(params);
        //
        //    [
        //        {
        //            "index_time": "1646915796",
        //            "name": "BTC_USDT",
        //            "index_price": "39142.73"
        //        }
        //    ]
        //
        const underlyings = [];
        for (let i = 0; i < response.length; i++) {
            const underlying = response[i];
            const name = this.safeString(underlying, 'name');
            if (name !== undefined) {
                underlyings.push(name);
            }
        }
        return underlyings;
    }
    /**
     * @method
     * @name gate#fetchLiquidations
     * @description retrieves the public liquidations of a trading pair
     * @see https://www.gate.io/docs/developers/apiv4/en/#retrieve-liquidation-history
     * @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 {int} [params.until] timestamp in ms of the latest liquidation
     * @returns {object} an array of [liquidation structures]{@link https://docs.ccxt.com/#/?id=liquidation-structure}
     */
    async fetchLiquidations(symbol, since = undefined, limit = undefined, params = {}) {
        await this.loadMarkets();
        const market = this.market(symbol);
        if (!market['swap']) {
            throw new errors.NotSupported(this.id + ' fetchLiquidations() supports swap markets only');
        }
        let request = {
            'settle': market['settleId'],
            'contract': market['id'],
        };
        if (since !== undefined) {
            request['from'] = since;
        }
        if (limit !== undefined) {
            request['limit'] = limit;
        }
        [request, params] = this.handleUntilOption('to', request, params);
        const response = await this.publicFuturesGetSettleLiqOrders(this.extend(request, params));
        //
        //     [
        //         {
        //             "contract": "BTC_USDT",
        //             "left": 0,
        //             "size": -165,
        //             "fill_price": "28070",
        //             "order_price": "28225",
        //             "time": 1696736132
        //         },
        //     ]
        //
        return this.parseLiquidations(response, market, since, limit);
    }
    /**
     * @method
     * @name gate#fetchMyLiquidations
     * @description retrieves the users liquidated positions
     * @see https://www.gate.io/docs/developers/apiv4/en/#list-liquidation-history
     * @see https://www.gate.io/docs/developers/apiv4/en/#list-liquidation-history-2
     * @see https://www.gate.io/docs/developers/apiv4/en/#list-user-s-liquidation-history-of-specified-underlying
     * @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
     * @returns {object} an array of [liquidation structures]{@link https://docs.ccxt.com/#/?id=liquidation-structure}
     */
    async fetchMyLiquidations(symbol = undefined, since = undefined, limit = undefined, params = {}) {
        if (symbol === undefined) {
            throw new errors.ArgumentsRequired(this.id + ' fetchMyLiquidations() requires a symbol argument');
        }
        await this.loadMarkets();
        const market = this.market(symbol);
        const request = {
            'contract': market['id'],
        };
        let response = undefined;
        if ((market['swap']) || (market['future'])) {
            if (limit !== undefined) {
                request['limit'] = limit;
            }
            request['settle'] = market['settleId'];
        }
        else if (market['option']) {
            const marketId = market['id'];
            const optionParts = marketId.split('-');
            request['underlying'] = this.safeString(optionParts, 0);
        }
        if (market['swap']) {
            response = await this.privateFuturesGetSettleLiquidates(this.extend(request, params));
        }
        else if (market['future']) {
            response = await this.privateDeliveryGetSettleLiquidates(this.extend(request, params));
        }
        else if (market['option']) {
            response = await this.privateOptionsGetPositionClose(this.extend(request, params));
        }
        else {
            throw new errors.NotSupported(this.id + ' fetchMyLiquidations() does not support ' + market['type'] + ' orders');
        }
        //
        // swap and future
        //
        //     [
        //         {
        //             "time": 1548654951,
        //             "contract": "BTC_USDT",
        //             "size": 600,
        //             "leverage": "25",
        //             "margin": "0.006705256878",
        //             "entry_price": "3536.123",
        //             "liq_price": "3421.54",
        //             "mark_price": "3420.27",
        //             "order_id": 317393847,
        //             "order_price": "3405",
        //             "fill_price": "3424",
        //             "left": 0
        //         }
        //     ]
        //
        // option
        //
        //     [
        //         {
        //             "time": 1631764800,
        //             "pnl": "-42914.291",
        //             "settle_size": "-10001",
        //             "side": "short",
        //             "contract": "BTC_USDT-20210916-5000-C",
        //             "text": "settled"
        //         }
        //     ]
        //
        return this.parseLiquidations(response, market, since, limit);
    }
    parseLiquidation(liquidation, market = undefined) {
        //
        // fetchLiquidations
        //
        //     {
        //         "contract": "BTC_USDT",
        //         "left": 0,
        //         "size": -165,
        //         "fill_price": "28070",
        //         "order_price": "28225",
        //         "time": 1696736132
        //     }
        //
        // swap and future: fetchMyLiquidations
        //
        //     {
        //         "time": 1548654951,
        //         "contract": "BTC_USDT",
        //         "size": 600,
        //         "leverage": "25",
        //         "margin": "0.006705256878",
        //         "entry_price": "3536.123",
        //         "liq_price": "3421.54",
        //         "mark_price": "3420.27",
        //         "order_id": 317393847,
        //         "order_price": "3405",
        //         "fill_price": "3424",
        //         "left": 0
        //     }
        //
        // option: fetchMyLiquidations
        //
        //     {
        //         "time": 1631764800,
        //         "pnl": "-42914.291",
        //         "settle_size": "-10001",
        //         "side": "short",
        //         "contract": "BTC_USDT-20210916-5000-C",
        //         "text": "settled"
        //     }
        //
        const marketId = this.safeString(liquidation, 'contract');
        const timestamp = this.safeTimestamp(liquidation, 'time');
        const size = this.safeString2(liquidation, 'size', 'settle_size');
        const left = this.safeString(liquidation, 'left', '0');
        const contractsString = Precise["default"].stringAbs(Precise["default"].stringSub(size, left));
        const contractSizeString = this.safeString(market, 'contractSize');
        const priceString = this.safeString2(liquidation, 'liq_price', 'fill_price');
        const baseValueString = Precise["default"].stringMul(contractsString, contractSizeString);
        let quoteValueString = this.safeString(liquidation, 'pnl');
        if (quoteValueString === undefined) {
            quoteValueString = Precise["default"].stringMul(baseValueString, priceString);
        }
        return this.safeLiquidation({
            'info': liquidation,
            'symbol': this.safeSymbol(marketId, market),
            'contracts': this.parseNumber(contractsString),
            'contractSize': this.parseNumber(contractSizeString),
            'price': this.parseNumber(priceString),
            'baseValue': this.parseNumber(baseValueString),
            'quoteValue': this.parseNumber(Precise["default"].stringAbs(quoteValueString)),
            'timestamp': timestamp,
            'datetime': this.iso8601(timestamp),
        });
    }
    /**
     * @method
     * @name gate#fetchGreeks
     * @description fetches an option contracts greeks, financial metrics used to measure the factors that affect the price of an options contract
     * @see https://www.gate.io/docs/developers/apiv4/en/#list-tickers-of-options-contracts
     * @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 = {
            'underlying': market['info']['underlying'],
        };
        const response = await this.publicOptionsGetTickers(this.extend(request, params));
        //
        //     [
        //         {
        //             "vega": "1.78992",
        //             "leverage": "6.2096777055417",
        //             "ask_iv": "0.6245",
        //             "delta": "-0.69397",
        //             "last_price": "0",
        //             "theta": "-2.5723",
        //             "bid1_price": "222.9",
        //             "mark_iv": "0.5909",
        //             "name": "ETH_USDT-20231201-2300-P",
        //             "bid_iv": "0.5065",
        //             "ask1_price": "243.6",
        //             "mark_price": "236.57",
        //             "position_size": 0,
        //             "bid1_size": 368,
        //             "ask1_size": -335,
        //             "gamma": "0.00116"
        //         },
        //     ]
        //
        const marketId = market['id'];
        for (let i = 0; i < response.length; i++) {
            const entry = response[i];
            const entryMarketId = this.safeString(entry, 'name');
            if (entryMarketId === marketId) {
                return this.parseGreeks(entry, market);
            }
        }
        return undefined;
    }
    parseGreeks(greeks, market = undefined) {
        //
        //     {
        //         "vega": "1.78992",
        //         "leverage": "6.2096777055417",
        //         "ask_iv": "0.6245",
        //         "delta": "-0.69397",
        //         "last_price": "0",
        //         "theta": "-2.5723",
        //         "bid1_price": "222.9",
        //         "mark_iv": "0.5909",
        //         "name": "ETH_USDT-20231201-2300-P",
        //         "bid_iv": "0.5065",
        //         "ask1_price": "243.6",
        //         "mark_price": "236.57",
        //         "position_size": 0,
        //         "bid1_size": 368,
        //         "ask1_size": -335,
        //         "gamma": "0.00116"
        //     }
        //
        const marketId = this.safeString(greeks, 'name');
        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, 'bid1_size'),
            'askSize': this.safeNumber(greeks, 'ask1_size'),
            'bidImpliedVolatility': this.safeNumber(greeks, 'bid_iv'),
            'askImpliedVolatility': this.safeNumber(greeks, 'ask_iv'),
            'markImpliedVolatility': this.safeNumber(greeks, 'mark_iv'),
            'bidPrice': this.safeNumber(greeks, 'bid1_price'),
            'askPrice': this.safeNumber(greeks, 'ask1_price'),
            'markPrice': this.safeNumber(greeks, 'mark_price'),
            'lastPrice': this.safeNumber(greeks, 'last_price'),
            'underlyingPrice': this.parseNumber(market['info']['underlying_price']),
            'info': greeks,
        };
    }
    /**
     * @method
     * @name gate#closePosition
     * @description closes open positions for a market
     * @see https://www.gate.io/docs/developers/apiv4/en/#create-a-futures-order
     * @see https://www.gate.io/docs/developers/apiv4/en/#create-a-futures-order-2
     * @see https://www.gate.io/docs/developers/apiv4/en/#create-an-options-order
     * @param {string} symbol Unified CCXT market symbol
     * @param {string} side 'buy' or 'sell'
     * @param {object} [params] extra parameters specific to the okx api endpoint
     * @returns {object[]} [A list of position structures]{@link https://docs.ccxt.com/#/?id=position-structure}
     */
    async closePosition(symbol, side = undefined, params = {}) {
        const request = {
            'close': true,
        };
        params = this.extend(request, params);
        if (side === undefined) {
            side = ''; // side is not used but needs to be present, otherwise crashes in php
        }
        return await this.createOrder(symbol, 'market', side, 0, undefined, params);
    }
    /**
     * @method
     * @name gate#fetchLeverage
     * @description fetch the set leverage for a market
     * @see https://www.gate.io/docs/developers/apiv4/en/#get-unified-account-information
     * @see https://www.gate.io/docs/developers/apiv4/en/#get-detail-of-lending-market
     * @see https://www.gate.io/docs/developers/apiv4/en/#query-one-single-margin-currency-pair-deprecated
     * @param {string} symbol unified market symbol
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @param {boolean} [params.unified] default false, set to true for fetching the unified accounts leverage
     * @returns {object} a [leverage structure]{@link https://docs.ccxt.com/#/?id=leverage-structure}
     */
    async fetchLeverage(symbol, params = {}) {
        await this.loadMarkets();
        let market = undefined;
        if (symbol !== undefined) {
            // unified account does not require a symbol
            market = this.market(symbol);
        }
        const request = {};
        let response = undefined;
        const isUnified = this.safeBool(params, 'unified');
        params = this.omit(params, 'unified');
        if (market['spot']) {
            request['currency_pair'] = market['id'];
            if (isUnified) {
                response = await this.publicMarginGetUniCurrencyPairsCurrencyPair(this.extend(request, params));
                //
                //     {
                //         "currency_pair": "BTC_USDT",
                //         "base_min_borrow_amount": "0.0001",
                //         "quote_min_borrow_amount": "1",
                //         "leverage": "10"
                //     }
                //
            }
            else {
                response = await this.publicMarginGetCurrencyPairsCurrencyPair(this.extend(request, params));
                //
                //     {
                //         "id": "BTC_USDT",
                //         "base": "BTC",
                //         "quote": "USDT",
                //         "leverage": 10,
                //         "min_base_amount": "0.0001",
                //         "min_quote_amount": "1",
                //         "max_quote_amount": "40000000",
                //         "status": 1
                //     }
                //
            }
        }
        else if (isUnified) {
            response = await this.privateUnifiedGetAccounts(this.extend(request, params));
            //
            //     {
            //         "user_id": 10001,
            //         "locked": false,
            //         "balances": {
            //             "ETH": {
            //                 "available": "0",
            //                 "freeze": "0",
            //                 "borrowed": "0.075393666654",
            //                 "negative_liab": "0",
            //                 "futures_pos_liab": "0",
            //                 "equity": "1016.1",
            //                 "total_freeze": "0",
            //                 "total_liab": "0"
            //             },
            //             "POINT": {
            //                 "available": "9999999999.017023138734",
            //                 "freeze": "0",
            //                 "borrowed": "0",
            //                 "negative_liab": "0",
            //                 "futures_pos_liab": "0",
            //                 "equity": "12016.1",
            //                 "total_freeze": "0",
            //                 "total_liab": "0"
            //             },
            //             "USDT": {
            //                 "available": "0.00000062023",
            //                 "freeze": "0",
            //                 "borrowed": "0",
            //                 "negative_liab": "0",
            //                 "futures_pos_liab": "0",
            //                 "equity": "16.1",
            //                 "total_freeze": "0",
            //                 "total_liab": "0"
            //             }
            //         },
            //         "total": "230.94621713",
            //         "borrowed": "161.66395521",
            //         "total_initial_margin": "1025.0524665088",
            //         "total_margin_balance": "3382495.944473949183",
            //         "total_maintenance_margin": "205.01049330176",
            //         "total_initial_margin_rate": "3299.827135672679",
            //         "total_maintenance_margin_rate": "16499.135678363399",
            //         "total_available_margin": "3381470.892007440383",
            //         "unified_account_total": "3381470.892007440383",
            //         "unified_account_total_liab": "0",
            //         "unified_account_total_equity": "100016.1",
            //         "leverage": "2"
            //     }
            //
        }
        else {
            throw new errors.NotSupported(this.id + ' fetchLeverage() does not support ' + market['type'] + ' markets');
        }
        return this.parseLeverage(response, market);
    }
    /**
     * @method
     * @name gate#fetchLeverages
     * @description fetch the set leverage for all leverage markets, only spot margin is supported on gate
     * @see https://www.gate.io/docs/developers/apiv4/en/#list-lending-markets
     * @see https://www.gate.io/docs/developers/apiv4/en/#list-all-supported-currency-pairs-supported-in-margin-trading-deprecated
     * @param {string[]} symbols a list of unified market symbols
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @param {boolean} [params.unified] default false, set to true for fetching unified account leverages
     * @returns {object} a list of [leverage structures]{@link https://docs.ccxt.com/#/?id=leverage-structure}
     */
    async fetchLeverages(symbols = undefined, params = {}) {
        await this.loadMarkets();
        symbols = this.marketSymbols(symbols);
        let response = undefined;
        const isUnified = this.safeBool(params, 'unified');
        params = this.omit(params, 'unified');
        let marketIdRequest = 'id';
        if (isUnified) {
            marketIdRequest = 'currency_pair';
            response = await this.publicMarginGetUniCurrencyPairs(params);
            //
            //     [
            //         {
            //             "currency_pair": "1INCH_USDT",
            //             "base_min_borrow_amount": "8",
            //             "quote_min_borrow_amount": "1",
            //             "leverage": "3"
            //         },
            //     ]
            //
        }
        else {
            response = await this.publicMarginGetCurrencyPairs(params);
            //
            //     [
            //         {
            //             "id": "1CAT_USDT",
            //             "base": "1CAT",
            //             "quote": "USDT",
            //             "leverage": 3,
            //             "min_base_amount": "71",
            //             "min_quote_amount": "1",
            //             "max_quote_amount": "10000",
            //             "status": 1
            //         },
            //     ]
            //
        }
        return this.parseLeverages(response, symbols, marketIdRequest, 'spot');
    }
    parseLeverage(leverage, market = undefined) {
        const marketId = this.safeString2(leverage, 'currency_pair', 'id');
        const leverageValue = this.safeInteger(leverage, 'leverage');
        return {
            'info': leverage,
            'symbol': this.safeSymbol(marketId, market, '_', 'spot'),
            'marginMode': undefined,
            'longLeverage': leverageValue,
            'shortLeverage': leverageValue,
        };
    }
    /**
     * @method
     * @name gate#fetchOption
     * @description fetches option data that is commonly found in an option chain
     * @see https://www.gate.io/docs/developers/apiv4/en/#query-specified-contract-detail
     * @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 = {
            'contract': market['id'],
        };
        const response = await this.publicOptionsGetContractsContract(this.extend(request, params));
        //
        //     {
        //         "is_active": true,
        //         "mark_price_round": "0.01",
        //         "settle_fee_rate": "0.00015",
        //         "bid1_size": 30,
        //         "taker_fee_rate": "0.0003",
        //         "price_limit_fee_rate": "0.1",
        //         "order_price_round": "0.1",
        //         "tag": "month",
        //         "ref_rebate_rate": "0",
        //         "name": "ETH_USDT-20240628-4500-C",
        //         "strike_price": "4500",
        //         "ask1_price": "280.5",
        //         "ref_discount_rate": "0",
        //         "order_price_deviate": "0.2",
        //         "ask1_size": -19,
        //         "mark_price_down": "155.45",
        //         "orderbook_id": 11724695,
        //         "is_call": true,
        //         "last_price": "188.7",
        //         "mark_price": "274.26",
        //         "underlying": "ETH_USDT",
        //         "create_time": 1688024882,
        //         "settle_limit_fee_rate": "0.1",
        //         "orders_limit": 10,
        //         "mark_price_up": "403.83",
        //         "position_size": 80,
        //         "order_size_max": 10000,
        //         "position_limit": 100000,
        //         "multiplier": "0.01",
        //         "order_size_min": 1,
        //         "trade_size": 229,
        //         "underlying_price": "3326.6",
        //         "maker_fee_rate": "0.0003",
        //         "expiration_time": 1719561600,
        //         "trade_id": 15,
        //         "bid1_price": "269.3"
        //     }
        //
        return this.parseOption(response, undefined, market);
    }
    /**
     * @method
     * @name gate#fetchOptionChain
     * @description fetches data for an underlying asset that is commonly found in an option chain
     * @see https://www.gate.io/docs/developers/apiv4/en/#list-all-the-contracts-with-specified-underlying-and-expiration-time
     * @param {string} code base currency to fetch an option chain for
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @param {string} [params.underlying] the underlying asset, can be obtained from fetchUnderlyingAssets ()
     * @param {int} [params.expiration] unix timestamp of the expiration time
     * @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 = {
            'underlying': currency['code'] + '_USDT', // todo: currency['id'].toUpperCase () &  network junctions
        };
        const response = await this.publicOptionsGetContracts(this.extend(request, params));
        //
        //     [
        //         {
        //             "is_active": true,
        //             "mark_price_round": "0.1",
        //             "settle_fee_rate": "0.00015",
        //             "bid1_size": 434,
        //             "taker_fee_rate": "0.0003",
        //             "price_limit_fee_rate": "0.1",
        //             "order_price_round": "1",
        //             "tag": "day",
        //             "ref_rebate_rate": "0",
        //             "name": "BTC_USDT-20240324-63500-P",
        //             "strike_price": "63500",
        //             "ask1_price": "387",
        //             "ref_discount_rate": "0",
        //             "order_price_deviate": "0.15",
        //             "ask1_size": -454,
        //             "mark_price_down": "124.3",
        //             "orderbook_id": 29600,
        //             "is_call": false,
        //             "last_price": "0",
        //             "mark_price": "366.6",
        //             "underlying": "BTC_USDT",
        //             "create_time": 1711118829,
        //             "settle_limit_fee_rate": "0.1",
        //             "orders_limit": 10,
        //             "mark_price_up": "630",
        //             "position_size": 0,
        //             "order_size_max": 10000,
        //             "position_limit": 10000,
        //             "multiplier": "0.01",
        //             "order_size_min": 1,
        //             "trade_size": 0,
        //             "underlying_price": "64084.65",
        //             "maker_fee_rate": "0.0003",
        //             "expiration_time": 1711267200,
        //             "trade_id": 0,
        //             "bid1_price": "307"
        //         },
        //     ]
        //
        return this.parseOptionChain(response, undefined, 'name');
    }
    parseOption(chain, currency = undefined, market = undefined) {
        //
        //     {
        //         "is_active": true,
        //         "mark_price_round": "0.1",
        //         "settle_fee_rate": "0.00015",
        //         "bid1_size": 434,
        //         "taker_fee_rate": "0.0003",
        //         "price_limit_fee_rate": "0.1",
        //         "order_price_round": "1",
        //         "tag": "day",
        //         "ref_rebate_rate": "0",
        //         "name": "BTC_USDT-20240324-63500-P",
        //         "strike_price": "63500",
        //         "ask1_price": "387",
        //         "ref_discount_rate": "0",
        //         "order_price_deviate": "0.15",
        //         "ask1_size": -454,
        //         "mark_price_down": "124.3",
        //         "orderbook_id": 29600,
        //         "is_call": false,
        //         "last_price": "0",
        //         "mark_price": "366.6",
        //         "underlying": "BTC_USDT",
        //         "create_time": 1711118829,
        //         "settle_limit_fee_rate": "0.1",
        //         "orders_limit": 10,
        //         "mark_price_up": "630",
        //         "position_size": 0,
        //         "order_size_max": 10000,
        //         "position_limit": 10000,
        //         "multiplier": "0.01",
        //         "order_size_min": 1,
        //         "trade_size": 0,
        //         "underlying_price": "64084.65",
        //         "maker_fee_rate": "0.0003",
        //         "expiration_time": 1711267200,
        //         "trade_id": 0,
        //         "bid1_price": "307"
        //     }
        //
        const marketId = this.safeString(chain, 'name');
        market = this.safeMarket(marketId, market);
        const timestamp = this.safeTimestamp(chain, 'create_time');
        return {
            'info': chain,
            'currency': undefined,
            'symbol': market['symbol'],
            'timestamp': timestamp,
            'datetime': this.iso8601(timestamp),
            'impliedVolatility': undefined,
            'openInterest': undefined,
            'bidPrice': this.safeNumber(chain, 'bid1_price'),
            'askPrice': this.safeNumber(chain, 'ask1_price'),
            'midPrice': undefined,
            'markPrice': this.safeNumber(chain, 'mark_price'),
            'lastPrice': this.safeNumber(chain, 'last_price'),
            'underlyingPrice': this.safeNumber(chain, 'underlying_price'),
            'change': undefined,
            'percentage': undefined,
            'baseVolume': undefined,
            'quoteVolume': undefined,
        };
    }
    /**
     * @method
     * @name gate#fetchPositionsHistory
     * @description fetches historical positions
     * @see https://www.gate.io/docs/developers/apiv4/#list-position-close-history
     * @see https://www.gate.io/docs/developers/apiv4/#list-position-close-history-2
     * @param {string[]} symbols unified conract symbols, must all have the same settle currency and the same market type
     * @param {int} [since] the earliest time in ms to fetch positions for
     * @param {int} [limit] the maximum amount of records to fetch, default=1000
     * @param {object} params extra parameters specific to the exchange api endpoint
     * @param {int} [params.until] the latest time in ms to fetch positions for
     *
     * EXCHANGE SPECIFIC PARAMETERS
     * @param {int} [params.offset] list offset, starting from 0
     * @param {string} [params.side] long or short
     * @param {string} [params.pnl] query profit or loss
     * @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;
        if (symbols !== undefined) {
            const symbolsLength = symbols.length;
            if (symbolsLength === 1) {
                market = this.market(symbols[0]);
            }
        }
        let marketType = undefined;
        [marketType, params] = this.handleMarketTypeAndParams('fetchPositionsHistory', market, params, 'swap');
        const until = this.safeInteger(params, 'until');
        params = this.omit(params, 'until');
        let request = {};
        [request, params] = this.prepareRequest(market, marketType, params);
        if (limit !== undefined) {
            request['limit'] = limit;
        }
        if (since !== undefined) {
            request['from'] = this.parseToInt(since / 1000);
        }
        if (until !== undefined) {
            request['to'] = this.parseToInt(until / 1000);
        }
        let response = undefined;
        if (marketType === 'swap') {
            response = await this.privateFuturesGetSettlePositionClose(this.extend(request, params));
        }
        else if (marketType === 'future') {
            response = await this.privateDeliveryGetSettlePositionClose(this.extend(request, params));
        }
        else {
            throw new errors.NotSupported(this.id + ' fetchPositionsHistory() does not support markets of type ' + marketType);
        }
        //
        //    [
        //        {
        //            "contract": "SLERF_USDT",
        //            "text": "web",
        //            "long_price": "0.766306",
        //            "pnl": "-23.41702352",
        //            "pnl_pnl": "-22.7187",
        //            "pnl_fee": "-0.06527125",
        //            "pnl_fund": "-0.63305227",
        //            "accum_size": "100",
        //            "time": 1711279263,
        //            "short_price": "0.539119",
        //            "side": "long",
        //            "max_size": "100",
        //            "first_open_time": 1711037985
        //        },
        //        ...
        //    ]
        //
        return this.parsePositions(response, symbols, params);
    }
    handleErrors(code, reason, url, method, headers, body, response, requestHeaders, requestBody) {
        if (response === undefined) {
            return undefined;
        }
        //
        //    {"label": "ORDER_NOT_FOUND", "message": "Order not found"}
        //    {"label": "INVALID_PARAM_VALUE", "message": "invalid argument: status"}
        //    {"label": "INVALID_PARAM_VALUE", "message": "invalid argument: Trigger.rule"}
        //    {"label": "INVALID_PARAM_VALUE", "message": "invalid argument: trigger.expiration invalid range"}
        //    {"label": "INVALID_ARGUMENT", "detail": "invalid size"}
        //    {"user_id":10406147,"id":"id","succeeded":false,"message":"INVALID_PROTOCOL","label":"INVALID_PROTOCOL"}
        //
        const label = this.safeString(response, 'label');
        if (label !== undefined) {
            const feedback = this.id + ' ' + body;
            this.throwExactlyMatchedException(this.exceptions['exact'], label, feedback);
            throw new errors.ExchangeError(feedback);
        }
        return undefined;
    }
}

module.exports = gate;