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

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

from ccxt.base.exchange import Exchange
from ccxt.abstract.htx import ImplicitAPI
import hashlib
from ccxt.base.types import Account, Any, Balances, BorrowInterest, Currencies, Currency, DepositAddress, Int, IsolatedBorrowRate, IsolatedBorrowRates, LedgerEntry, LeverageTier, LeverageTiers, Market, Num, Order, OrderBook, OrderRequest, OrderSide, OrderType, Position, Str, Strings, Ticker, Tickers, FundingRate, FundingRates, Trade, TradingFeeInterface, Transaction, TransferEntry
from typing import List
from ccxt.base.errors import ExchangeError
from ccxt.base.errors import AuthenticationError
from ccxt.base.errors import PermissionDenied
from ccxt.base.errors import AccountNotEnabled
from ccxt.base.errors import ArgumentsRequired
from ccxt.base.errors import BadRequest
from ccxt.base.errors import BadSymbol
from ccxt.base.errors import InsufficientFunds
from ccxt.base.errors import InvalidOrder
from ccxt.base.errors import OrderNotFound
from ccxt.base.errors import NotSupported
from ccxt.base.errors import OperationFailed
from ccxt.base.errors import RateLimitExceeded
from ccxt.base.errors import ExchangeNotAvailable
from ccxt.base.errors import OnMaintenance
from ccxt.base.errors import RequestTimeout
from ccxt.base.decimal_to_precision import TRUNCATE
from ccxt.base.decimal_to_precision import TICK_SIZE
from ccxt.base.precise import Precise


class htx(Exchange, ImplicitAPI):

    def describe(self) -> Any:
        return self.deep_extend(super(htx, self).describe(), {
            'id': 'htx',
            'name': 'HTX',
            'countries': ['CN'],
            'rateLimit': 100,
            'userAgent': self.userAgents['chrome100'],
            'certified': True,
            'version': 'v1',
            'hostname': 'api.huobi.pro',  # api.testnet.huobi.pro
            'pro': True,
            'has': {
                'CORS': None,
                'spot': True,
                'margin': True,
                'swap': True,
                'future': True,
                'option': None,
                'addMargin': None,
                'borrowCrossMargin': True,
                'borrowIsolatedMargin': True,
                'cancelAllOrders': True,
                'cancelAllOrdersAfter': True,
                'cancelOrder': True,
                'cancelOrders': True,
                'closeAllPositions': False,
                'closePosition': True,
                'createDepositAddress': None,
                'createMarketBuyOrderWithCost': True,
                'createMarketOrderWithCost': False,
                'createMarketSellOrderWithCost': False,
                'createOrder': True,
                'createOrders': True,
                'createReduceOnlyOrder': False,
                'createStopLimitOrder': True,
                'createStopLossOrder': True,
                'createStopMarketOrder': True,
                'createStopOrder': True,
                'createTakeProfitOrder': True,
                'createTrailingPercentOrder': True,
                'createTriggerOrder': True,
                'fetchAccounts': True,
                'fetchBalance': True,
                'fetchBidsAsks': None,
                'fetchBorrowInterest': True,
                'fetchBorrowRateHistories': None,
                'fetchBorrowRateHistory': None,
                'fetchCanceledOrders': None,
                'fetchClosedOrder': None,
                'fetchClosedOrders': True,
                'fetchCrossBorrowRate': False,
                'fetchCrossBorrowRates': False,
                'fetchCurrencies': True,
                'fetchDeposit': None,
                'fetchDepositAddress': True,
                'fetchDepositAddresses': None,
                'fetchDepositAddressesByNetwork': True,
                'fetchDeposits': True,
                'fetchDepositWithdrawFee': 'emulated',
                'fetchDepositWithdrawFees': True,
                'fetchFundingHistory': True,
                'fetchFundingRate': True,
                'fetchFundingRateHistory': True,
                'fetchFundingRates': True,
                'fetchIndexOHLCV': True,
                'fetchIsolatedBorrowRate': False,
                'fetchIsolatedBorrowRates': True,
                'fetchL3OrderBook': None,
                'fetchLastPrices': True,
                'fetchLedger': True,
                'fetchLedgerEntry': None,
                'fetchLeverage': False,
                'fetchLeverageTiers': True,
                'fetchLiquidations': True,
                'fetchMarginAdjustmentHistory': False,
                'fetchMarketLeverageTiers': 'emulated',
                'fetchMarkets': True,
                'fetchMarkOHLCV': True,
                'fetchMyLiquidations': False,
                'fetchMyTrades': True,
                'fetchOHLCV': True,
                'fetchOpenInterest': True,
                'fetchOpenInterestHistory': True,
                'fetchOpenInterests': True,
                'fetchOpenOrder': None,
                'fetchOpenOrders': True,
                'fetchOrder': True,
                'fetchOrderBook': True,
                'fetchOrderBooks': None,
                'fetchOrders': True,
                'fetchOrderTrades': True,
                'fetchPosition': True,
                'fetchPositionHistory': 'emulated',
                'fetchPositions': True,
                'fetchPositionsHistory': False,
                'fetchPositionsRisk': False,
                'fetchPremiumIndexOHLCV': True,
                'fetchSettlementHistory': True,
                'fetchStatus': True,
                'fetchTicker': True,
                'fetchTickers': True,
                'fetchTime': True,
                'fetchTrades': True,
                'fetchTradingFee': True,
                'fetchTradingFees': False,
                'fetchTradingLimits': True,
                'fetchTransactionFee': None,
                'fetchTransactionFees': None,
                'fetchTransactions': None,
                'fetchTransfers': None,
                'fetchWithdrawAddresses': True,
                'fetchWithdrawal': None,
                'fetchWithdrawals': True,
                'fetchWithdrawalWhitelist': None,
                'reduceMargin': None,
                'repayCrossMargin': True,
                'repayIsolatedMargin': True,
                'setLeverage': True,
                'setMarginMode': False,
                'setPositionMode': True,
                'signIn': None,
                'transfer': True,
                'withdraw': True,
            },
            'timeframes': {
                '1m': '1min',
                '5m': '5min',
                '15m': '15min',
                '30m': '30min',
                '1h': '60min',
                '4h': '4hour',
                '1d': '1day',
                '1w': '1week',
                '1M': '1mon',
                '1y': '1year',
            },
            'urls': {
                # 'test': {
                #     'market': 'https://api.testnet.huobi.pro',
                #     'public': 'https://api.testnet.huobi.pro',
                #     'private': 'https://api.testnet.huobi.pro',
                # },
                'logo': 'https://user-images.githubusercontent.com/1294454/76137448-22748a80-604e-11ea-8069-6e389271911d.jpg',
                'hostnames': {
                    'contract': 'api.hbdm.com',
                    'spot': 'api.huobi.pro',
                    'status': {
                        'spot': 'status.huobigroup.com',
                        'future': {
                            'inverse': 'status-dm.huobigroup.com',
                            'linear': 'status-linear-swap.huobigroup.com',  # USDT-Margined Contracts
                        },
                        'swap': {
                            'inverse': 'status-swap.huobigroup.com',
                            'linear': 'status-linear-swap.huobigroup.com',  # USDT-Margined Contracts
                        },
                    },
                    # recommended for AWS
                    # 'contract': 'api.hbdm.vn',
                    # 'spot': 'api-aws.huobi.pro',
                },
                'api': {
                    'status': 'https://{hostname}',
                    'contract': 'https://{hostname}',
                    'spot': 'https://{hostname}',
                    'public': 'https://{hostname}',
                    'private': 'https://{hostname}',
                    'v2Public': 'https://{hostname}',
                    'v2Private': 'https://{hostname}',
                },
                'www': 'https://www.huobi.com',
                'referral': {
                    'url': 'https://www.htx.com.vc/invite/en-us/1h?invite_code=6rmm2223',
                    'discount': 0.15,
                },
                'doc': [
                    'https://huobiapi.github.io/docs/spot/v1/en/',
                    'https://huobiapi.github.io/docs/dm/v1/en/',
                    'https://huobiapi.github.io/docs/coin_margined_swap/v1/en/',
                    'https://huobiapi.github.io/docs/usdt_swap/v1/en/',
                    'https://www.huobi.com/en-us/opend/newApiPages/',
                ],
                'fees': 'https://www.huobi.com/about/fee/',
            },
            'api': {
                # ------------------------------------------------------------
                # old api definitions
                'v2Public': {
                    'get': {
                        'reference/currencies': 1,  # 币链参考信息
                        'market-status': 1,  # 获取当前市场状态
                    },
                },
                'v2Private': {
                    'get': {
                        'account/ledger': 1,
                        'account/withdraw/quota': 1,
                        'account/withdraw/address': 1,  # 提币地址查询(限母用户可用)
                        'account/deposit/address': 1,
                        'account/repayment': 5,  # 还币交易记录查询
                        'reference/transact-fee-rate': 1,
                        'account/asset-valuation': 0.2,  # 获取账户资产估值
                        'point/account': 5,  # 点卡余额查询
                        'sub-user/user-list': 1,  # 获取子用户列表
                        'sub-user/user-state': 1,  # 获取特定子用户的用户状态
                        'sub-user/account-list': 1,  # 获取特定子用户的账户列表
                        'sub-user/deposit-address': 1,  # 子用户充币地址查询
                        'sub-user/query-deposit': 1,  # 子用户充币记录查询
                        'user/api-key': 1,  # 母子用户API key信息查询
                        'user/uid': 1,  # 母子用户获取用户UID
                        'algo-orders/opening': 1,  # 查询未触发OPEN策略委托
                        'algo-orders/history': 1,  # 查询策略委托历史
                        'algo-orders/specific': 1,  # 查询特定策略委托
                        'c2c/offers': 1,  # 查询借入借出订单
                        'c2c/offer': 1,  # 查询特定借入借出订单及其交易记录
                        'c2c/transactions': 1,  # 查询借入借出交易记录
                        'c2c/repayment': 1,  # 查询还币交易记录
                        'c2c/account': 1,  # 查询账户余额
                        'etp/reference': 1,  # 基础参考信息
                        'etp/transactions': 5,  # 获取杠杆ETP申赎记录
                        'etp/transaction': 5,  # 获取特定杠杆ETP申赎记录
                        'etp/rebalance': 1,  # 获取杠杆ETP调仓记录
                        'etp/limit': 1,  # 获取ETP持仓限额
                    },
                    'post': {
                        'account/transfer': 1,
                        'account/repayment': 5,  # 归还借币（全仓逐仓通用）
                        'point/transfer': 5,  # 点卡划转
                        'sub-user/management': 1,  # 冻结/解冻子用户
                        'sub-user/creation': 1,  # 子用户创建
                        'sub-user/tradable-market': 1,  # 设置子用户交易权限
                        'sub-user/transferability': 1,  # 设置子用户资产转出权限
                        'sub-user/api-key-generation': 1,  # 子用户API key创建
                        'sub-user/api-key-modification': 1,  # 修改子用户API key
                        'sub-user/api-key-deletion': 1,  # 删除子用户API key
                        'sub-user/deduct-mode': 1,  # 设置子用户手续费抵扣模式
                        'algo-orders': 1,  # 策略委托下单
                        'algo-orders/cancel-all-after': 1,  # 自动撤销订单
                        'algo-orders/cancellation': 1,  # 策略委托（触发前）撤单
                        'c2c/offer': 1,  # 借入借出下单
                        'c2c/cancellation': 1,  # 借入借出撤单
                        'c2c/cancel-all': 1,  # 撤销所有借入借出订单
                        'c2c/repayment': 1,  # 还币
                        'c2c/transfer': 1,  # 资产划转
                        'etp/creation': 5,  # 杠杆ETP换入
                        'etp/redemption': 5,  # 杠杆ETP换出
                        'etp/{transactId}/cancel': 10,  # 杠杆ETP单个撤单
                        'etp/batch-cancel': 50,  # 杠杆ETP批量撤单
                    },
                },
                'public': {
                    'get': {
                        'common/symbols': 1,  # 查询系统支持的所有交易对
                        'common/currencys': 1,  # 查询系统支持的所有币种
                        'common/timestamp': 1,  # 查询系统当前时间
                        'common/exchange': 1,  # order limits
                        'settings/currencys': 1,  # ?language=en-US
                    },
                },
                'private': {
                    'get': {
                        'account/accounts': 0.2,  # 查询当前用户的所有账户(即account-id)
                        'account/accounts/{id}/balance': 0.2,  # 查询指定账户的余额
                        'account/accounts/{sub-uid}': 1,
                        'account/history': 4,
                        'cross-margin/loan-info': 1,
                        'margin/loan-info': 1,  # 查询借币币息率及额度
                        'fee/fee-rate/get': 1,
                        'order/openOrders': 0.4,
                        'order/orders': 0.4,
                        'order/orders/{id}': 0.4,  # 查询某个订单详情
                        'order/orders/{id}/matchresults': 0.4,  # 查询某个订单的成交明细
                        'order/orders/getClientOrder': 0.4,
                        'order/history': 1,  # 查询当前委托、历史委托
                        'order/matchresults': 1,  # 查询当前成交、历史成交
                        # 'dw/withdraw-virtual/addresses',  # 查询虚拟币提现地址（Deprecated）
                        'query/deposit-withdraw': 1,
                        # 'margin/loan-info',  # duplicate
                        'margin/loan-orders': 0.2,  # 借贷订单
                        'margin/accounts/balance': 0.2,  # 借贷账户详情
                        'cross-margin/loan-orders': 1,  # 查询借币订单
                        'cross-margin/accounts/balance': 1,  # 借币账户详情
                        'points/actions': 1,
                        'points/orders': 1,
                        'subuser/aggregate-balance': 10,
                        'stable-coin/exchange_rate': 1,
                        'stable-coin/quote': 1,
                    },
                    'post': {
                        'account/transfer': 1,  # 资产划转(该节点为母用户和子用户进行资产划转的通用接口。)
                        'futures/transfer': 1,
                        'order/batch-orders': 0.4,
                        'order/orders/place': 0.2,  # 创建并执行一个新订单(一步下单， 推荐使用)
                        'order/orders/submitCancelClientOrder': 0.2,
                        'order/orders/batchCancelOpenOrders': 0.4,
                        # 'order/orders',  # 创建一个新的订单请求 （仅创建订单，不执行下单）
                        # 'order/orders/{id}/place',  # 执行一个订单 （仅执行已创建的订单）
                        'order/orders/{id}/submitcancel': 0.2,  # 申请撤销一个订单请求
                        'order/orders/batchcancel': 0.4,  # 批量撤销订单
                        # 'dw/balance/transfer',  # 资产划转
                        'dw/withdraw/api/create': 1,  # 申请提现虚拟币
                        # 'dw/withdraw-virtual/create',  # 申请提现虚拟币
                        # 'dw/withdraw-virtual/{id}/place',  # 确认申请虚拟币提现（Deprecated）
                        'dw/withdraw-virtual/{id}/cancel': 1,  # 申请取消提现虚拟币
                        'dw/transfer-in/margin': 10,  # 现货账户划入至借贷账户
                        'dw/transfer-out/margin': 10,  # 借贷账户划出至现货账户
                        'margin/orders': 10,  # 申请借贷
                        'margin/orders/{id}/repay': 10,  # 归还借贷
                        'cross-margin/transfer-in': 1,  # 资产划转
                        'cross-margin/transfer-out': 1,  # 资产划转
                        'cross-margin/orders': 1,  # 申请借币
                        'cross-margin/orders/{id}/repay': 1,  # 归还借币
                        'stable-coin/exchange': 1,
                        'subuser/transfer': 10,
                    },
                },
                # ------------------------------------------------------------
                # new api definitions
                # 'https://status.huobigroup.com/api/v2/summary.json': 1,
                # 'https://status-dm.huobigroup.com/api/v2/summary.json': 1,
                # 'https://status-swap.huobigroup.com/api/v2/summary.json': 1,
                # 'https://status-linear-swap.huobigroup.com/api/v2/summary.json': 1,
                'status': {
                    'public': {
                        'spot': {
                            'get': {
                                'api/v2/summary.json': 1,
                            },
                        },
                        'future': {
                            'inverse': {
                                'get': {
                                    'api/v2/summary.json': 1,
                                },
                            },
                            'linear': {
                                'get': {
                                    'api/v2/summary.json': 1,
                                },
                            },
                        },
                        'swap': {
                            'inverse': {
                                'get': {
                                    'api/v2/summary.json': 1,
                                },
                            },
                            'linear': {
                                'get': {
                                    'api/v2/summary.json': 1,
                                },
                            },
                        },
                    },
                },
                'spot': {
                    'public': {
                        'get': {
                            'v2/market-status': 1,
                            'v1/common/symbols': 1,
                            'v1/common/currencys': 1,
                            'v2/settings/common/currencies': 1,
                            'v2/reference/currencies': 1,
                            'v1/common/timestamp': 1,
                            'v1/common/exchange': 1,  # order limits
                            'v1/settings/common/chains': 1,
                            'v1/settings/common/currencys': 1,
                            'v1/settings/common/symbols': 1,
                            'v2/settings/common/symbols': 1,
                            'v1/settings/common/market-symbols': 1,
                            # Market Data
                            'market/history/candles': 1,
                            'market/history/kline': 1,
                            'market/detail/merged': 1,
                            'market/tickers': 1,
                            'market/detail': 1,
                            'market/depth': 1,
                            'market/trade': 1,
                            'market/history/trade': 1,
                            'market/etp': 1,  # Get real-time equity of leveraged ETP
                            # ETP
                            'v2/etp/reference': 1,
                            'v2/etp/rebalance': 1,
                        },
                    },
                    'private': {
                        'get': {
                            # Account
                            'v1/account/accounts': 0.2,
                            'v1/account/accounts/{account-id}/balance': 0.2,
                            'v2/account/valuation': 1,
                            'v2/account/asset-valuation': 0.2,
                            'v1/account/history': 4,
                            'v2/account/ledger': 1,
                            'v2/point/account': 5,
                            # Wallet(Deposit and Withdraw)
                            'v2/account/deposit/address': 1,
                            'v2/account/withdraw/quota': 1,
                            'v2/account/withdraw/address': 1,
                            'v2/reference/currencies': 1,
                            'v1/query/deposit-withdraw': 1,
                            'v1/query/withdraw/client-order-id': 1,
                            # Sub user management
                            'v2/user/api-key': 1,
                            'v2/user/uid': 1,
                            'v2/sub-user/user-list': 1,
                            'v2/sub-user/user-state': 1,
                            'v2/sub-user/account-list': 1,
                            'v2/sub-user/deposit-address': 1,
                            'v2/sub-user/query-deposit': 1,
                            'v1/subuser/aggregate-balance': 10,
                            'v1/account/accounts/{sub-uid}': 1,
                            # Trading
                            'v1/order/openOrders': 0.4,
                            'v1/order/orders/{order-id}': 0.4,
                            'v1/order/orders/getClientOrder': 0.4,
                            'v1/order/orders/{order-id}/matchresult': 0.4,
                            'v1/order/orders/{order-id}/matchresults': 0.4,
                            'v1/order/orders': 0.4,
                            'v1/order/history': 1,
                            'v1/order/matchresults': 1,
                            'v2/reference/transact-fee-rate': 1,
                            # Conditional Order
                            'v2/algo-orders/opening': 1,
                            'v2/algo-orders/history': 1,
                            'v2/algo-orders/specific': 1,
                            # Margin Loan(Cross/Isolated)
                            'v1/margin/loan-info': 1,
                            'v1/margin/loan-orders': 0.2,
                            'v1/margin/accounts/balance': 0.2,
                            'v1/cross-margin/loan-info': 1,
                            'v1/cross-margin/loan-orders': 1,
                            'v1/cross-margin/accounts/balance': 1,
                            'v2/account/repayment': 5,
                            # Stable Coin Exchange
                            'v1/stable-coin/quote': 1,
                            'v1/stable_coin/exchange_rate': 1,
                            # ETP
                            'v2/etp/transactions': 5,
                            'v2/etp/transaction': 5,
                            'v2/etp/limit': 1,
                        },
                        'post': {
                            # Account
                            'v1/account/transfer': 1,
                            'v1/futures/transfer': 1,  # future transfers
                            'v2/point/transfer': 5,
                            'v2/account/transfer': 1,  # swap transfers
                            # Wallet(Deposit and Withdraw)
                            'v1/dw/withdraw/api/create': 1,
                            'v1/dw/withdraw-virtual/{withdraw-id}/cancel': 1,
                            # Sub user management
                            'v2/sub-user/deduct-mode': 1,
                            'v2/sub-user/creation': 1,
                            'v2/sub-user/management': 1,
                            'v2/sub-user/tradable-market': 1,
                            'v2/sub-user/transferability': 1,
                            'v2/sub-user/api-key-generation': 1,
                            'v2/sub-user/api-key-modification': 1,
                            'v2/sub-user/api-key-deletion': 1,
                            'v1/subuser/transfer': 10,
                            'v1/trust/user/active/credit': 10,
                            # Trading
                            'v1/order/orders/place': 0.2,
                            'v1/order/batch-orders': 0.4,
                            'v1/order/auto/place': 0.2,
                            'v1/order/orders/{order-id}/submitcancel': 0.2,
                            'v1/order/orders/submitCancelClientOrder': 0.2,
                            'v1/order/orders/batchCancelOpenOrders': 0.4,
                            'v1/order/orders/batchcancel': 0.4,
                            'v2/algo-orders/cancel-all-after': 1,
                            # Conditional Order
                            'v2/algo-orders': 1,
                            'v2/algo-orders/cancellation': 1,
                            # Margin Loan(Cross/Isolated)
                            'v2/account/repayment': 5,
                            'v1/dw/transfer-in/margin': 10,
                            'v1/dw/transfer-out/margin': 10,
                            'v1/margin/orders': 10,
                            'v1/margin/orders/{order-id}/repay': 10,
                            'v1/cross-margin/transfer-in': 1,
                            'v1/cross-margin/transfer-out': 1,
                            'v1/cross-margin/orders': 1,
                            'v1/cross-margin/orders/{order-id}/repay': 1,
                            # Stable Coin Exchange
                            'v1/stable-coin/exchange': 1,
                            # ETP
                            'v2/etp/creation': 5,
                            'v2/etp/redemption': 5,
                            'v2/etp/{transactId}/cancel': 10,
                            'v2/etp/batch-cancel': 50,
                        },
                    },
                },
                'contract': {
                    'public': {
                        'get': {
                            'api/v1/timestamp': 1,
                            'heartbeat/': 1,  # backslash is not a typo
                            # Future Market Data interface
                            'api/v1/contract_contract_info': 1,
                            'api/v1/contract_index': 1,
                            'api/v1/contract_query_elements': 1,
                            'api/v1/contract_price_limit': 1,
                            'api/v1/contract_open_interest': 1,
                            'api/v1/contract_delivery_price': 1,
                            'market/depth': 1,
                            'market/bbo': 1,
                            'market/history/kline': 1,
                            'index/market/history/mark_price_kline': 1,
                            'market/detail/merged': 1,
                            'market/detail/batch_merged': 1,
                            'v2/market/detail/batch_merged': 1,
                            'market/trade': 1,
                            'market/history/trade': 1,
                            'api/v1/contract_risk_info': 1,
                            'api/v1/contract_insurance_fund': 1,
                            'api/v1/contract_adjustfactor': 1,
                            'api/v1/contract_his_open_interest': 1,
                            'api/v1/contract_ladder_margin': 1,
                            'api/v1/contract_api_state': 1,
                            'api/v1/contract_elite_account_ratio': 1,
                            'api/v1/contract_elite_position_ratio': 1,
                            'api/v1/contract_liquidation_orders': 1,
                            'api/v1/contract_settlement_records': 1,
                            'index/market/history/index': 1,
                            'index/market/history/basis': 1,
                            'api/v1/contract_estimated_settlement_price': 1,
                            'api/v3/contract_liquidation_orders': 1,
                            # Swap Market Data interface
                            'swap-api/v1/swap_contract_info': 1,
                            'swap-api/v1/swap_index': 1,
                            'swap-api/v1/swap_query_elements': 1,
                            'swap-api/v1/swap_price_limit': 1,
                            'swap-api/v1/swap_open_interest': 1,
                            'swap-ex/market/depth': 1,
                            'swap-ex/market/bbo': 1,
                            'swap-ex/market/history/kline': 1,
                            'index/market/history/swap_mark_price_kline': 1,
                            'swap-ex/market/detail/merged': 1,
                            'v2/swap-ex/market/detail/batch_merged': 1,
                            'index/market/history/swap_premium_index_kline': 1,
                            'swap-ex/market/detail/batch_merged': 1,
                            'swap-ex/market/trade': 1,
                            'swap-ex/market/history/trade': 1,
                            'swap-api/v1/swap_risk_info': 1,
                            'swap-api/v1/swap_insurance_fund': 1,
                            'swap-api/v1/swap_adjustfactor': 1,
                            'swap-api/v1/swap_his_open_interest': 1,
                            'swap-api/v1/swap_ladder_margin': 1,
                            'swap-api/v1/swap_api_state': 1,
                            'swap-api/v1/swap_elite_account_ratio': 1,
                            'swap-api/v1/swap_elite_position_ratio': 1,
                            'swap-api/v1/swap_estimated_settlement_price': 1,
                            'swap-api/v1/swap_liquidation_orders': 1,
                            'swap-api/v1/swap_settlement_records': 1,
                            'swap-api/v1/swap_funding_rate': 1,
                            'swap-api/v1/swap_batch_funding_rate': 1,
                            'swap-api/v1/swap_historical_funding_rate': 1,
                            'swap-api/v3/swap_liquidation_orders': 1,
                            'index/market/history/swap_estimated_rate_kline': 1,
                            'index/market/history/swap_basis': 1,
                            # Swap Market Data interface
                            'linear-swap-api/v1/swap_contract_info': 1,
                            'linear-swap-api/v1/swap_index': 1,
                            'linear-swap-api/v1/swap_query_elements': 1,
                            'linear-swap-api/v1/swap_price_limit': 1,
                            'linear-swap-api/v1/swap_open_interest': 1,
                            'linear-swap-ex/market/depth': 1,
                            'linear-swap-ex/market/bbo': 1,
                            'linear-swap-ex/market/history/kline': 1,
                            'index/market/history/linear_swap_mark_price_kline': 1,
                            'linear-swap-ex/market/detail/merged': 1,
                            'linear-swap-ex/market/detail/batch_merged': 1,
                            'v2/linear-swap-ex/market/detail/batch_merged': 1,
                            'linear-swap-ex/market/trade': 1,
                            'linear-swap-ex/market/history/trade': 1,
                            'linear-swap-api/v1/swap_risk_info': 1,
                            'swap-api/v1/linear-swap-api/v1/swap_insurance_fund': 1,
                            'linear-swap-api/v1/swap_adjustfactor': 1,
                            'linear-swap-api/v1/swap_cross_adjustfactor': 1,
                            'linear-swap-api/v1/swap_his_open_interest': 1,
                            'linear-swap-api/v1/swap_ladder_margin': 1,
                            'linear-swap-api/v1/swap_cross_ladder_margin': 1,
                            'linear-swap-api/v1/swap_api_state': 1,
                            'linear-swap-api/v1/swap_cross_transfer_state': 1,
                            'linear-swap-api/v1/swap_cross_trade_state': 1,
                            'linear-swap-api/v1/swap_elite_account_ratio': 1,
                            'linear-swap-api/v1/swap_elite_position_ratio': 1,
                            'linear-swap-api/v1/swap_liquidation_orders': 1,
                            'linear-swap-api/v1/swap_settlement_records': 1,
                            'linear-swap-api/v1/swap_funding_rate': 1,
                            'linear-swap-api/v1/swap_batch_funding_rate': 1,
                            'linear-swap-api/v1/swap_historical_funding_rate': 1,
                            'linear-swap-api/v3/swap_liquidation_orders': 1,
                            'index/market/history/linear_swap_premium_index_kline': 1,
                            'index/market/history/linear_swap_estimated_rate_kline': 1,
                            'index/market/history/linear_swap_basis': 1,
                            'linear-swap-api/v1/swap_estimated_settlement_price': 1,
                        },
                    },
                    'private': {
                        'get': {
                            # Future Account Interface
                            'api/v1/contract_sub_auth_list': 1,
                            'api/v1/contract_api_trading_status': 1,
                            # Swap Account Interface
                            'swap-api/v1/swap_sub_auth_list': 1,
                            'swap-api/v1/swap_api_trading_status': 1,
                            # Swap Account Interface
                            'linear-swap-api/v1/swap_sub_auth_list': 1,
                            'linear-swap-api/v1/swap_api_trading_status': 1,
                            'linear-swap-api/v1/swap_cross_position_side': 1,
                            'linear-swap-api/v1/swap_position_side': 1,
                            'linear-swap-api/v3/unified_account_info': 1,
                            'linear-swap-api/v3/fix_position_margin_change_record': 1,
                            'linear-swap-api/v3/swap_unified_account_type': 1,
                            'linear-swap-api/v3/linear_swap_overview_account_info': 1,
                        },
                        'post': {
                            # Future Account Interface
                            'api/v1/contract_balance_valuation': 1,
                            'api/v1/contract_account_info': 1,
                            'api/v1/contract_position_info': 1,
                            'api/v1/contract_sub_auth': 1,
                            'api/v1/contract_sub_account_list': 1,
                            'api/v1/contract_sub_account_info_list': 1,
                            'api/v1/contract_sub_account_info': 1,
                            'api/v1/contract_sub_position_info': 1,
                            'api/v1/contract_financial_record': 1,
                            'api/v1/contract_financial_record_exact': 1,
                            'api/v1/contract_user_settlement_records': 1,
                            'api/v1/contract_order_limit': 1,
                            'api/v1/contract_fee': 1,
                            'api/v1/contract_transfer_limit': 1,
                            'api/v1/contract_position_limit': 1,
                            'api/v1/contract_account_position_info': 1,
                            'api/v1/contract_master_sub_transfer': 1,
                            'api/v1/contract_master_sub_transfer_record': 1,
                            'api/v1/contract_available_level_rate': 1,
                            'api/v3/contract_financial_record': 1,
                            'api/v3/contract_financial_record_exact': 1,
                            # Future Trade Interface
                            'api/v1/contract-cancel-after': 1,
                            'api/v1/contract_order': 1,
                            'api/v1/contract_batchorder': 1,
                            'api/v1/contract_cancel': 1,
                            'api/v1/contract_cancelall': 1,
                            'api/v1/contract_switch_lever_rate': 30,
                            'api/v1/lightning_close_position': 1,
                            'api/v1/contract_order_info': 1,
                            'api/v1/contract_order_detail': 1,
                            'api/v1/contract_openorders': 1,
                            'api/v1/contract_hisorders': 1,
                            'api/v1/contract_hisorders_exact': 1,
                            'api/v1/contract_matchresults': 1,
                            'api/v1/contract_matchresults_exact': 1,
                            'api/v3/contract_hisorders': 1,
                            'api/v3/contract_hisorders_exact': 1,
                            'api/v3/contract_matchresults': 1,
                            'api/v3/contract_matchresults_exact': 1,
                            # Contract Strategy Order Interface
                            'api/v1/contract_trigger_order': 1,
                            'api/v1/contract_trigger_cancel': 1,
                            'api/v1/contract_trigger_cancelall': 1,
                            'api/v1/contract_trigger_openorders': 1,
                            'api/v1/contract_trigger_hisorders': 1,
                            'api/v1/contract_tpsl_order': 1,
                            'api/v1/contract_tpsl_cancel': 1,
                            'api/v1/contract_tpsl_cancelall': 1,
                            'api/v1/contract_tpsl_openorders': 1,
                            'api/v1/contract_tpsl_hisorders': 1,
                            'api/v1/contract_relation_tpsl_order': 1,
                            'api/v1/contract_track_order': 1,
                            'api/v1/contract_track_cancel': 1,
                            'api/v1/contract_track_cancelall': 1,
                            'api/v1/contract_track_openorders': 1,
                            'api/v1/contract_track_hisorders': 1,
                            # Swap Account Interface
                            'swap-api/v1/swap_balance_valuation': 1,
                            'swap-api/v1/swap_account_info': 1,
                            'swap-api/v1/swap_position_info': 1,
                            'swap-api/v1/swap_account_position_info': 1,
                            'swap-api/v1/swap_sub_auth': 1,
                            'swap-api/v1/swap_sub_account_list': 1,
                            'swap-api/v1/swap_sub_account_info_list': 1,
                            'swap-api/v1/swap_sub_account_info': 1,
                            'swap-api/v1/swap_sub_position_info': 1,
                            'swap-api/v1/swap_financial_record': 1,
                            'swap-api/v1/swap_financial_record_exact': 1,
                            'swap-api/v1/swap_user_settlement_records': 1,
                            'swap-api/v1/swap_available_level_rate': 1,
                            'swap-api/v1/swap_order_limit': 1,
                            'swap-api/v1/swap_fee': 1,
                            'swap-api/v1/swap_transfer_limit': 1,
                            'swap-api/v1/swap_position_limit': 1,
                            'swap-api/v1/swap_master_sub_transfer': 1,
                            'swap-api/v1/swap_master_sub_transfer_record': 1,
                            'swap-api/v3/swap_financial_record': 1,
                            'swap-api/v3/swap_financial_record_exact': 1,
                            # Swap Trade Interface
                            'swap-api/v1/swap-cancel-after': 1,
                            'swap-api/v1/swap_order': 1,
                            'swap-api/v1/swap_batchorder': 1,
                            'swap-api/v1/swap_cancel': 1,
                            'swap-api/v1/swap_cancelall': 1,
                            'swap-api/v1/swap_lightning_close_position': 1,
                            'swap-api/v1/swap_switch_lever_rate': 30,
                            'swap-api/v1/swap_order_info': 1,
                            'swap-api/v1/swap_order_detail': 1,
                            'swap-api/v1/swap_openorders': 1,
                            'swap-api/v1/swap_hisorders': 1,
                            'swap-api/v1/swap_hisorders_exact': 1,
                            'swap-api/v1/swap_matchresults': 1,
                            'swap-api/v1/swap_matchresults_exact': 1,
                            'swap-api/v3/swap_matchresults': 1,
                            'swap-api/v3/swap_matchresults_exact': 1,
                            'swap-api/v3/swap_hisorders': 1,
                            'swap-api/v3/swap_hisorders_exact': 1,
                            # Swap Strategy Order Interface
                            'swap-api/v1/swap_trigger_order': 1,
                            'swap-api/v1/swap_trigger_cancel': 1,
                            'swap-api/v1/swap_trigger_cancelall': 1,
                            'swap-api/v1/swap_trigger_openorders': 1,
                            'swap-api/v1/swap_trigger_hisorders': 1,
                            'swap-api/v1/swap_tpsl_order': 1,
                            'swap-api/v1/swap_tpsl_cancel': 1,
                            'swap-api/v1/swap_tpsl_cancelall': 1,
                            'swap-api/v1/swap_tpsl_openorders': 1,
                            'swap-api/v1/swap_tpsl_hisorders': 1,
                            'swap-api/v1/swap_relation_tpsl_order': 1,
                            'swap-api/v1/swap_track_order': 1,
                            'swap-api/v1/swap_track_cancel': 1,
                            'swap-api/v1/swap_track_cancelall': 1,
                            'swap-api/v1/swap_track_openorders': 1,
                            'swap-api/v1/swap_track_hisorders': 1,
                            # Swap Account Interface
                            'linear-swap-api/v1/swap_lever_position_limit': 1,
                            'linear-swap-api/v1/swap_cross_lever_position_limit': 1,
                            'linear-swap-api/v1/swap_balance_valuation': 1,
                            'linear-swap-api/v1/swap_account_info': 1,
                            'linear-swap-api/v1/swap_cross_account_info': 1,
                            'linear-swap-api/v1/swap_position_info': 1,
                            'linear-swap-api/v1/swap_cross_position_info': 1,
                            'linear-swap-api/v1/swap_account_position_info': 1,
                            'linear-swap-api/v1/swap_cross_account_position_info': 1,
                            'linear-swap-api/v1/swap_sub_auth': 1,
                            'linear-swap-api/v1/swap_sub_account_list': 1,
                            'linear-swap-api/v1/swap_cross_sub_account_list': 1,
                            'linear-swap-api/v1/swap_sub_account_info_list': 1,
                            'linear-swap-api/v1/swap_cross_sub_account_info_list': 1,
                            'linear-swap-api/v1/swap_sub_account_info': 1,
                            'linear-swap-api/v1/swap_cross_sub_account_info': 1,
                            'linear-swap-api/v1/swap_sub_position_info': 1,
                            'linear-swap-api/v1/swap_cross_sub_position_info': 1,
                            'linear-swap-api/v1/swap_financial_record': 1,
                            'linear-swap-api/v1/swap_financial_record_exact': 1,
                            'linear-swap-api/v1/swap_user_settlement_records': 1,
                            'linear-swap-api/v1/swap_cross_user_settlement_records': 1,
                            'linear-swap-api/v1/swap_available_level_rate': 1,
                            'linear-swap-api/v1/swap_cross_available_level_rate': 1,
                            'linear-swap-api/v1/swap_order_limit': 1,
                            'linear-swap-api/v1/swap_fee': 1,
                            'linear-swap-api/v1/swap_transfer_limit': 1,
                            'linear-swap-api/v1/swap_cross_transfer_limit': 1,
                            'linear-swap-api/v1/swap_position_limit': 1,
                            'linear-swap-api/v1/swap_cross_position_limit': 1,
                            'linear-swap-api/v1/swap_master_sub_transfer': 1,
                            'linear-swap-api/v1/swap_master_sub_transfer_record': 1,
                            'linear-swap-api/v1/swap_transfer_inner': 1,
                            'linear-swap-api/v3/swap_financial_record': 1,
                            'linear-swap-api/v3/swap_financial_record_exact': 1,
                            # Swap Trade Interface
                            'linear-swap-api/v1/swap_order': 1,
                            'linear-swap-api/v1/swap_cross_order': 1,
                            'linear-swap-api/v1/swap_batchorder': 1,
                            'linear-swap-api/v1/swap_cross_batchorder': 1,
                            'linear-swap-api/v1/swap_cancel': 1,
                            'linear-swap-api/v1/swap_cross_cancel': 1,
                            'linear-swap-api/v1/swap_cancelall': 1,
                            'linear-swap-api/v1/swap_cross_cancelall': 1,
                            'linear-swap-api/v1/swap_switch_lever_rate': 30,
                            'linear-swap-api/v1/swap_cross_switch_lever_rate': 30,
                            'linear-swap-api/v1/swap_lightning_close_position': 1,
                            'linear-swap-api/v1/swap_cross_lightning_close_position': 1,
                            'linear-swap-api/v1/swap_order_info': 1,
                            'linear-swap-api/v1/swap_cross_order_info': 1,
                            'linear-swap-api/v1/swap_order_detail': 1,
                            'linear-swap-api/v1/swap_cross_order_detail': 1,
                            'linear-swap-api/v1/swap_openorders': 1,
                            'linear-swap-api/v1/swap_cross_openorders': 1,
                            'linear-swap-api/v1/swap_hisorders': 1,
                            'linear-swap-api/v1/swap_cross_hisorders': 1,
                            'linear-swap-api/v1/swap_hisorders_exact': 1,
                            'linear-swap-api/v1/swap_cross_hisorders_exact': 1,
                            'linear-swap-api/v1/swap_matchresults': 1,
                            'linear-swap-api/v1/swap_cross_matchresults': 1,
                            'linear-swap-api/v1/swap_matchresults_exact': 1,
                            'linear-swap-api/v1/swap_cross_matchresults_exact': 1,
                            'linear-swap-api/v1/linear-cancel-after': 1,
                            'linear-swap-api/v1/swap_switch_position_mode': 1,
                            'linear-swap-api/v1/swap_cross_switch_position_mode': 1,
                            'linear-swap-api/v3/swap_matchresults': 1,
                            'linear-swap-api/v3/swap_cross_matchresults': 1,
                            'linear-swap-api/v3/swap_matchresults_exact': 1,
                            'linear-swap-api/v3/swap_cross_matchresults_exact': 1,
                            'linear-swap-api/v3/swap_hisorders': 1,
                            'linear-swap-api/v3/swap_cross_hisorders': 1,
                            'linear-swap-api/v3/swap_hisorders_exact': 1,
                            'linear-swap-api/v3/swap_cross_hisorders_exact': 1,
                            'linear-swap-api/v3/fix_position_margin_change': 1,
                            'linear-swap-api/v3/swap_switch_account_type': 1,
                            'linear-swap-api/v3/linear_swap_fee_switch': 1,
                            # Swap Strategy Order Interface
                            'linear-swap-api/v1/swap_trigger_order': 1,
                            'linear-swap-api/v1/swap_cross_trigger_order': 1,
                            'linear-swap-api/v1/swap_trigger_cancel': 1,
                            'linear-swap-api/v1/swap_cross_trigger_cancel': 1,
                            'linear-swap-api/v1/swap_trigger_cancelall': 1,
                            'linear-swap-api/v1/swap_cross_trigger_cancelall': 1,
                            'linear-swap-api/v1/swap_trigger_openorders': 1,
                            'linear-swap-api/v1/swap_cross_trigger_openorders': 1,
                            'linear-swap-api/v1/swap_trigger_hisorders': 1,
                            'linear-swap-api/v1/swap_cross_trigger_hisorders': 1,
                            'linear-swap-api/v1/swap_tpsl_order': 1,
                            'linear-swap-api/v1/swap_cross_tpsl_order': 1,
                            'linear-swap-api/v1/swap_tpsl_cancel': 1,
                            'linear-swap-api/v1/swap_cross_tpsl_cancel': 1,
                            'linear-swap-api/v1/swap_tpsl_cancelall': 1,
                            'linear-swap-api/v1/swap_cross_tpsl_cancelall': 1,
                            'linear-swap-api/v1/swap_tpsl_openorders': 1,
                            'linear-swap-api/v1/swap_cross_tpsl_openorders': 1,
                            'linear-swap-api/v1/swap_tpsl_hisorders': 1,
                            'linear-swap-api/v1/swap_cross_tpsl_hisorders': 1,
                            'linear-swap-api/v1/swap_relation_tpsl_order': 1,
                            'linear-swap-api/v1/swap_cross_relation_tpsl_order': 1,
                            'linear-swap-api/v1/swap_track_order': 1,
                            'linear-swap-api/v1/swap_cross_track_order': 1,
                            'linear-swap-api/v1/swap_track_cancel': 1,
                            'linear-swap-api/v1/swap_cross_track_cancel': 1,
                            'linear-swap-api/v1/swap_track_cancelall': 1,
                            'linear-swap-api/v1/swap_cross_track_cancelall': 1,
                            'linear-swap-api/v1/swap_track_openorders': 1,
                            'linear-swap-api/v1/swap_cross_track_openorders': 1,
                            'linear-swap-api/v1/swap_track_hisorders': 1,
                            'linear-swap-api/v1/swap_cross_track_hisorders': 1,
                        },
                    },
                },
            },
            'fees': {
                'trading': {
                    'feeSide': 'get',
                    'tierBased': False,
                    'percentage': True,
                    'maker': self.parse_number('0.002'),
                    'taker': self.parse_number('0.002'),
                },
            },
            'exceptions': {
                'broad': {
                    'contract is restricted of closing positions on API.  Please contact customer service': OnMaintenance,
                    'maintain': OnMaintenance,
                    'API key has no permission': PermissionDenied,  # {"status":"error","err-code":"api-signature-not-valid","err-msg":"Signature not valid: API key has no permission [API Key没有权限]","data":null}
                },
                'exact': {
                    # err-code
                    '403': AuthenticationError,  # {"status":"error","err_code":403,"err_msg":"Incorrect Access key [Access key错误]","ts":1652774224344}
                    '1010': AccountNotEnabled,  # {"status":"error","err_code":1010,"err_msg":"Account doesnt exist.","ts":1648137970490}
                    '1003': AuthenticationError,  # {code: '1003', message: 'invalid signature'}
                    '1013': BadSymbol,  # {"status":"error","err_code":1013,"err_msg":"This contract symbol doesnt exist.","ts":1640550459583}
                    '1017': OrderNotFound,  # {"status":"error","err_code":1017,"err_msg":"Order doesnt exist.","ts":1640550859242}
                    '1034': InvalidOrder,  # {"status":"error","err_code":1034,"err_msg":"Incorrect field of order price type.","ts":1643802870182}
                    '1036': InvalidOrder,  # {"status":"error","err_code":1036,"err_msg":"Incorrect field of open long form.","ts":1643802518986}
                    '1039': InvalidOrder,  # {"status":"error","err_code":1039,"err_msg":"Buy price must be lower than 39270.9USDT. Sell price must exceed 37731USDT.","ts":1643802374403}
                    '1041': InvalidOrder,  # {"status":"error","err_code":1041,"err_msg":"The order amount exceeds the limit(170000Cont), please modify and order again.","ts":1643802784940}
                    '1047': InsufficientFunds,  # {"status":"error","err_code":1047,"err_msg":"Insufficient margin available.","ts":1643802672652}
                    '1048': InsufficientFunds,  # {"status":"error","err_code":1048,"err_msg":"Insufficient close amount available.","ts":1652772408864}
                    '1061': OrderNotFound,  # {"status":"ok","data":{"errors":[{"order_id":"1349442392365359104","err_code":1061,"err_msg":"The order does not exist."}],"successes":""},"ts":1741773744526}
                    '1051': InvalidOrder,  # {"status":"error","err_code":1051,"err_msg":"No orders to cancel.","ts":1652552125876}
                    '1066': BadSymbol,  # {"status":"error","err_code":1066,"err_msg":"The symbol field cannot be empty. Please re-enter.","ts":1640550819147}
                    '1067': InvalidOrder,  # {"status":"error","err_code":1067,"err_msg":"The client_order_id field is invalid. Please re-enter.","ts":1643802119413}
                    '1094': InvalidOrder,  # {"status":"error","err_code":1094,"err_msg":"The leverage cannot be empty, please switch the leverage or contact customer service","ts":1640496946243}
                    '1220': AccountNotEnabled,  # {"status":"error","err_code":1220,"err_msg":"You don’t have access permission have not opened contracts trading.","ts":1645096660718}
                    '1303': BadRequest,  # {"code":1303,"data":null,"message":"Each transfer-out cannot be less than 5USDT.","success":false,"print-log":true}
                    '1461': InvalidOrder,  # {"status":"error","err_code":1461,"err_msg":"Current positions have triggered position limits(5000USDT). Please modify.","ts":1652554651234}
                    '4007': BadRequest,  # {"code":"4007","msg":"Unified account special interface, non - one account is not available","data":null,"ts":"1698413427651"}'
                    'bad-request': BadRequest,
                    'validation-format-error': BadRequest,  # {"status":"error","err-code":"validation-format-error","err-msg":"Format Error: order-id.","data":null}
                    'validation-constraints-required': BadRequest,  # {"status":"error","err-code":"validation-constraints-required","err-msg":"Field is missing: client-order-id.","data":null}
                    'base-date-limit-error': BadRequest,  # {"status":"error","err-code":"base-date-limit-error","err-msg":"date less than system limit","data":null}
                    'api-not-support-temp-addr': PermissionDenied,  # {"status":"error","err-code":"api-not-support-temp-addr","err-msg":"API withdrawal does not support temporary addresses","data":null}
                    'timeout': RequestTimeout,  # {"ts":1571653730865,"status":"error","err-code":"timeout","err-msg":"Request Timeout"}
                    'gateway-internal-error': ExchangeNotAvailable,  # {"status":"error","err-code":"gateway-internal-error","err-msg":"Failed to load data. Try again later.","data":null}
                    'account-frozen-balance-insufficient-error': InsufficientFunds,  # {"status":"error","err-code":"account-frozen-balance-insufficient-error","err-msg":"trade account balance is not enough, left: `0.0027`","data":null}
                    'invalid-amount': InvalidOrder,  # eg "Paramemter `amount` is invalid."
                    'order-limitorder-amount-min-error': InvalidOrder,  # limit order amount error, min: `0.001`
                    'order-limitorder-amount-max-error': InvalidOrder,  # market order amount error, max: `1000000`
                    'order-marketorder-amount-min-error': InvalidOrder,  # market order amount error, min: `0.01`
                    'order-limitorder-price-min-error': InvalidOrder,  # limit order price error
                    'order-limitorder-price-max-error': InvalidOrder,  # limit order price error
                    'order-stop-order-hit-trigger': InvalidOrder,  # {"status":"error","err-code":"order-stop-order-hit-trigger","err-msg":"Orders that are triggered immediately are not supported.","data":null}
                    'order-value-min-error': InvalidOrder,  # {"status":"error","err-code":"order-value-min-error","err-msg":"Order total cannot be lower than: 1 USDT","data":null}
                    'order-invalid-price': InvalidOrder,  # {"status":"error","err-code":"order-invalid-price","err-msg":"invalid price","data":null}
                    'order-holding-limit-failed': InvalidOrder,  # {"status":"error","err-code":"order-holding-limit-failed","err-msg":"Order failed, exceeded the holding limit of self currency","data":null}
                    'order-orderprice-precision-error': InvalidOrder,  # {"status":"error","err-code":"order-orderprice-precision-error","err-msg":"order price precision error, scale: `4`","data":null}
                    'order-etp-nav-price-max-error': InvalidOrder,  # {"status":"error","err-code":"order-etp-nav-price-max-error","err-msg":"Order price cannot be higher than 5% of NAV","data":null}
                    'order-orderstate-error': OrderNotFound,  # canceling an already canceled order
                    'order-queryorder-invalid': OrderNotFound,  # querying a non-existent order
                    'order-update-error': ExchangeNotAvailable,  # undocumented error
                    'api-signature-check-failed': AuthenticationError,
                    'api-signature-not-valid': AuthenticationError,  # {"status":"error","err-code":"api-signature-not-valid","err-msg":"Signature not valid: Incorrect Access key [Access key错误]","data":null}
                    'base-record-invalid': OrderNotFound,  # https://github.com/ccxt/ccxt/issues/5750
                    'base-symbol-trade-disabled': BadSymbol,  # {"status":"error","err-code":"base-symbol-trade-disabled","err-msg":"Trading is disabled for self symbol","data":null}
                    'base-symbol-error': BadSymbol,  # {"status":"error","err-code":"base-symbol-error","err-msg":"The symbol is invalid","data":null}
                    'system-maintenance': OnMaintenance,  # {"status": "error", "err-code": "system-maintenance", "err-msg": "System is in maintenance!", "data": null}
                    'base-request-exceed-frequency-limit': RateLimitExceeded,  # {"status":"error","err-code":"base-request-exceed-frequency-limit","err-msg":"Frequency of requests has exceeded the limit, please try again later","data":null}
                    # err-msg
                    'invalid symbol': BadSymbol,  # {"ts":1568813334794,"status":"error","err-code":"invalid-parameter","err-msg":"invalid symbol"}
                    'symbol trade not open now': BadSymbol,  # {"ts":1576210479343,"status":"error","err-code":"invalid-parameter","err-msg":"symbol trade not open now"}
                    'require-symbol': BadSymbol,  # {"status":"error","err-code":"require-symbol","err-msg":"Parameter `symbol` is required.","data":null},
                    'invalid-address': BadRequest,  # {"status":"error","err-code":"invalid-address","err-msg":"Invalid address.","data":null},
                    'base-currency-chain-error': BadRequest,  # {"status":"error","err-code":"base-currency-chain-error","err-msg":"The current currency chain does not exist","data":null},
                    'dw-insufficient-balance': InsufficientFunds,  # {"status":"error","err-code":"dw-insufficient-balance","err-msg":"Insufficient balance. You can only transfer `12.3456` at most.","data":null}
                    'base-withdraw-fee-error': BadRequest,  # {"status":"error","err-code":"base-withdraw-fee-error","err-msg":"withdrawal fee is not within limits","data":null}
                    'dw-withdraw-min-limit': BadRequest,  # {"status":"error","err-code":"dw-withdraw-min-limit","err-msg":"The withdrawal amount is less than the minimum limit.","data":null}
                    'request limit': RateLimitExceeded,  # {"ts":1687004814731,"status":"error","err-code":"invalid-parameter","err-msg":"request limit"}
                },
            },
            'precisionMode': TICK_SIZE,
            'options': {
                'include_OS_certificates': False,  # temporarily leave self, remove in future
                'fetchMarkets': {
                    'types': {
                        'spot': True,
                        'linear': True,
                        'inverse': True,
                    },
                },
                'timeDifference': 0,  # the difference between system clock and exchange clock
                'adjustForTimeDifference': False,  # controls the adjustment logic upon instantiation
                'fetchOHLCV': {
                    'useHistoricalEndpointForSpot': True,
                },
                'withdraw': {
                    'includeFee': False,
                },
                'defaultType': 'spot',  # spot, future, swap
                'defaultSubType': 'linear',  # inverse, linear
                'defaultNetwork': 'ERC20',
                'defaultNetworks': {
                    'ETH': 'ERC20',
                    'BTC': 'BTC',
                    'USDT': 'TRC20',
                },
                'networks': {
                    # by displaynames
                    'TRC20': 'TRX',  # TRON for mainnet
                    'BTC': 'BTC',
                    'ERC20': 'ETH',  # ETH for mainnet
                    'SOL': 'SOLANA',
                    'HRC20': 'HECO',
                    'BEP20': 'BSC',
                    'XMR': 'XMR',
                    'LTC': 'LTC',
                    'XRP': 'XRP',
                    'XLM': 'XLM',
                    'CRONOS': 'CRO',
                    'CRO': 'CRO',
                    'GLMR': 'GLMR',
                    'POLYGON': 'MATIC',
                    'MATIC': 'MATIC',
                    'BTT': 'BTT',
                    'CUBE': 'CUBE',
                    'IOST': 'IOST',
                    'NEO': 'NEO',
                    'KLAY': 'KLAY',
                    'EOS': 'EOS',
                    'THETA': 'THETA',
                    'NAS': 'NAS',
                    'NULS': 'NULS',
                    'QTUM': 'QTUM',
                    'FTM': 'FTM',
                    'CELO': 'CELO',
                    'DOGE': 'DOGE',
                    'DOGECHAIN': 'DOGECHAIN',
                    'NEAR': 'NEAR',
                    'STEP': 'STEP',
                    'BITCI': 'BITCI',
                    'CARDANO': 'ADA',
                    'ADA': 'ADA',
                    'ETC': 'ETC',
                    'LUK': 'LUK',
                    'MINEPLEX': 'MINEPLEX',
                    'DASH': 'DASH',
                    'ZEC': 'ZEC',
                    'IOTA': 'IOTA',
                    'NEON3': 'NEON3',
                    'XEM': 'XEM',
                    'HC': 'HC',
                    'LSK': 'LSK',
                    'DCR': 'DCR',
                    'BTG': 'BTG',
                    'STEEM': 'STEEM',
                    'BTS': 'BTS',
                    'ICX': 'ICX',
                    'WAVES': 'WAVES',
                    'CMT': 'CMT',
                    'BTM': 'BTM',
                    'VET': 'VET',
                    'XZC': 'XZC',
                    'ACT': 'ACT',
                    'SMT': 'SMT',
                    'BCD': 'BCD',
                    'WAX': 'WAX1',
                    'WICC': 'WICC',
                    'ELF': 'ELF',
                    'ZIL': 'ZIL',
                    'ELA': 'ELA',
                    'BCX': 'BCX',
                    'SBTC': 'SBTC',
                    'BIFI': 'BIFI',
                    'CTXC': 'CTXC',
                    'WAN': 'WAN',
                    'POLYX': 'POLYX',
                    'PAI': 'PAI',
                    'WTC': 'WTC',
                    'DGB': 'DGB',
                    'XVG': 'XVG',
                    'AAC': 'AAC',
                    'AE': 'AE',
                    'SEELE': 'SEELE',
                    'BCV': 'BCV',
                    'GRS': 'GRS',
                    'ARDR': 'ARDR',
                    'NANO': 'NANO',
                    'ZEN': 'ZEN',
                    'RBTC': 'RBTC',
                    'BSV': 'BSV',
                    'GAS': 'GAS',
                    'XTZ': 'XTZ',
                    'LAMB': 'LAMB',
                    'CVNT1': 'CVNT1',
                    'DOCK': 'DOCK',
                    'SC': 'SC',
                    'KMD': 'KMD',
                    'ETN': 'ETN',
                    'TOP': 'TOP',
                    'IRIS': 'IRIS',
                    'UGAS': 'UGAS',
                    'TT': 'TT',
                    'NEWTON': 'NEWTON',
                    'VSYS': 'VSYS',
                    'FSN': 'FSN',
                    'BHD': 'BHD',
                    'ONE': 'ONE',
                    'EM': 'EM',
                    'CKB': 'CKB',
                    'EOSS': 'EOSS',
                    'HIVE': 'HIVE',
                    'RVN': 'RVN',
                    'DOT': 'DOT',
                    'KSM': 'KSM',
                    'BAND': 'BAND',
                    'OEP4': 'OEP4',
                    'NBS': 'NBS',
                    'FIS': 'FIS',
                    'AR': 'AR',
                    'HBAR': 'HBAR',
                    'FIL': 'FIL',
                    'MASS': 'MASS',
                    'KAVA': 'KAVA',
                    'XYM': 'XYM',
                    'ENJ': 'ENJ',
                    'CRUST': 'CRUST',
                    'ICP': 'ICP',
                    'CSPR': 'CSPR',
                    'FLOW': 'FLOW',
                    'IOTX': 'IOTX',
                    'LAT': 'LAT',
                    'APT': 'APT',
                    'XCH': 'XCH',
                    'MINA': 'MINA',
                    'XEC': 'ECASH',
                    'XPRT': 'XPRT',
                    'CCA': 'ACA',
                    'AOTI': 'COTI',
                    'AKT': 'AKT',
                    'ARS': 'ARS',
                    'ASTR': 'ASTR',
                    'AZERO': 'AZERO',
                    'BLD': 'BLD',
                    'BRISE': 'BRISE',
                    'CORE': 'CORE',
                    'DESO': 'DESO',
                    'DFI': 'DFI',
                    'EGLD': 'EGLD',
                    'ERG': 'ERG',
                    'ETHF': 'ETHFAIR',
                    'ETHW': 'ETHW',
                    'EVMOS': 'EVMOS',
                    'FIO': 'FIO',
                    'FLR': 'FLR',
                    'FINSCHIA': 'FINSCHIA',
                    'KMA': 'KMA',
                    'KYVE': 'KYVE',
                    'MEV': 'MEV',
                    'MOVR': 'MOVR',
                    'NODL': 'NODL',
                    'OAS': 'OAS',
                    'OSMO': 'OSMO',
                    'PAYCOIN': 'PAYCOIN',
                    'POKT': 'POKT',
                    'PYG': 'PYG',
                    'REI': 'REI',
                    'SCRT': 'SCRT',
                    'SDN': 'SDN',
                    'SEI': 'SEI',
                    'SGB': 'SGB',
                    'SUI': 'SUI',
                    'SXP': 'SOLAR',
                    'SYS': 'SYS',
                    'TENET': 'TENET',
                    'TON': 'TON',
                    'UNQ': 'UNQ',
                    'UYU': 'UYU',
                    'WEMIX': 'WEMIX',
                    'XDC': 'XDC',
                    'XPLA': 'XPLA',
                    # todo: below
                    # 'LUNC': 'LUNC',
                    # 'TERRA': 'TERRA',  # tbd
                    # 'LUNA': 'LUNA', tbd
                    # 'FCT2': 'FCT2',
                    # FIL-0X ?
                    # 'COSMOS': 'ATOM1',
                    # 'ATOM': 'ATOM1',
                    # 'CRO': 'CRO',
                    # 'OP': ['OPTIMISM', 'OPTIMISMETH']
                    # 'ARB': ['ARB', 'ARBITRUMETH']
                    # 'CHZ': ['CHZ', 'CZH'],
                    # todo: AVAXCCHAIN CCHAIN AVAX
                    # 'ALGO': ['ALGO', 'ALGOUSDT']
                    # 'ONT': ['ONT', 'ONTOLOGY'],
                    # 'BCC': 'BCC', BCH's somewhat chain
                    # 'DBC1': 'DBC1',
                },
                # https://github.com/ccxt/ccxt/issues/5376
                'fetchOrdersByStatesMethod': 'spot_private_get_v1_order_orders',  # 'spot_private_get_v1_order_history'  # https://github.com/ccxt/ccxt/pull/5392
                'createMarketBuyOrderRequiresPrice': True,
                'language': 'en-US',
                'broker': {
                    'id': 'AA03022abc',
                },
                'accountsByType': {
                    'spot': 'pro',
                    'funding': 'pro',
                    'future': 'futures',
                },
                'accountsById': {
                    'spot': 'spot',
                    'margin': 'margin',
                    'otc': 'otc',
                    'point': 'point',
                    'super-margin': 'super-margin',
                    'investment': 'investment',
                    'borrow': 'borrow',
                    'grid-trading': 'grid-trading',
                    'deposit-earning': 'deposit-earning',
                    'otc-options': 'otc-options',
                },
                'typesByAccount': {
                    'pro': 'spot',
                    'futures': 'future',
                },
                'spot': {
                    'stopOrderTypes': {
                        'stop-limit': True,
                        'buy-stop-limit': True,
                        'sell-stop-limit': True,
                        'stop-limit-fok': True,
                        'buy-stop-limit-fok': True,
                        'sell-stop-limit-fok': True,
                    },
                    'limitOrderTypes': {
                        'limit': True,
                        'buy-limit': True,
                        'sell-limit': True,
                        'ioc': True,
                        'buy-ioc': True,
                        'sell-ioc': True,
                        'limit-maker': True,
                        'buy-limit-maker': True,
                        'sell-limit-maker': True,
                        'stop-limit': True,
                        'buy-stop-limit': True,
                        'sell-stop-limit': True,
                        'limit-fok': True,
                        'buy-limit-fok': True,
                        'sell-limit-fok': True,
                        'stop-limit-fok': True,
                        'buy-stop-limit-fok': True,
                        'sell-stop-limit-fok': True,
                    },
                },
            },
            'commonCurrencies': {
                # https://github.com/ccxt/ccxt/issues/6081
                # https://github.com/ccxt/ccxt/issues/3365
                # https://github.com/ccxt/ccxt/issues/2873
                'NGL': 'GFNGL',
                'GET': 'THEMIS',  # conflict with GET(Guaranteed Entrance Token, GET Protocol)
                'GTC': 'GAMECOM',  # conflict with Gitcoin and Gastrocoin
                'HIT': 'HITCHAIN',
                # https://github.com/ccxt/ccxt/issues/7399
                # https://coinmarketcap.com/currencies/pnetwork/
                # https://coinmarketcap.com/currencies/penta/markets/
                # https://en.cryptonomist.ch/blog/eidoo/the-edo-to-pnt-upgrade-what-you-need-to-know-updated/
                'PNT': 'PENTA',
                'SBTC': 'SUPERBITCOIN',
                'SOUL': 'SOULSAVER',
                'BIFI': 'BITCOINFILE',  # conflict with Beefy.Finance https://github.com/ccxt/ccxt/issues/8706
                'FUD': 'FTX Users Debt',
            },
            'features': {
                'spot': {
                    'sandbox': True,
                    'createOrder': {
                        'marginMode': True,
                        'triggerPrice': True,
                        'triggerDirection': True,
                        'triggerPriceType': None,
                        'stopLossPrice': False,  # todo: add support by triggerprice
                        'takeProfitPrice': False,
                        'attachedStopLossTakeProfit': None,
                        'timeInForce': {
                            'IOC': True,
                            'FOK': True,
                            'PO': True,
                            'GTD': False,
                        },
                        'hedged': False,
                        'trailing': False,
                        'iceberg': False,
                        'selfTradePrevention': True,  # todo implement
                        'leverage': True,  # todo implement
                        'marketBuyByCost': True,
                        'marketBuyRequiresPrice': True,
                    },
                    'createOrders': {
                        'max': 10,
                    },
                    'fetchMyTrades': {
                        'marginMode': False,
                        'limit': 500,
                        'daysBack': 120,
                        'untilDays': 2,
                        'symbolRequired': False,
                    },
                    'fetchOrder': {
                        'marginMode': False,
                        'trigger': False,
                        'trailing': False,
                        'symbolRequired': False,
                    },
                    'fetchOpenOrders': {
                        'marginMode': False,
                        'trigger': True,
                        'trailing': False,
                        'limit': 500,
                        'symbolRequired': False,
                    },
                    'fetchOrders': {
                        'marginMode': False,
                        'trigger': True,
                        'trailing': False,
                        'limit': 500,
                        'untilDays': 2,
                        'daysBack': 180,
                        'symbolRequired': False,
                    },
                    'fetchClosedOrders': {
                        'marginMode': False,
                        'trigger': True,
                        'trailing': False,
                        'untilDays': 2,
                        'limit': 500,
                        'daysBack': 180,
                        'daysBackCanceled': 1 / 12,
                        'symbolRequired': False,
                    },
                    'fetchOHLCV': {
                        'limit': 1000,  # 2000 for non-historical
                    },
                },
                'forDerivatives': {
                    'extends': 'spot',
                    'createOrder': {
                        'stopLossPrice': True,
                        'takeProfitPrice': True,
                        'trailing': True,
                        'hedged': True,
                        # 'leverage': True,  # todo
                    },
                    'createOrders': {
                        'max': 25,
                    },
                    'fetchOrder': {
                        'marginMode': True,
                    },
                    'fetchOpenOrders': {
                        'marginMode': True,
                        'trigger': False,
                        'trailing': False,
                        'limit': 50,
                    },
                    'fetchOrders': {
                        'marginMode': True,
                        'trigger': False,
                        'trailing': False,
                        'limit': 50,
                        'daysBack': 90,
                    },
                    'fetchClosedOrders': {
                        'marginMode': True,
                        'trigger': False,
                        'trailing': False,
                        'untilDays': 2,
                        'limit': 50,
                        'daysBack': 90,
                        'daysBackCanceled': 1 / 12,
                    },
                    'fetchOHLCV': {
                        'limit': 2000,
                    },
                },
                'swap': {
                    'linear': {
                        'extends': 'forDerivatives',
                    },
                    'inverse': {
                        'extends': 'forDerivatives',
                    },
                },
                'future': {
                    'linear': {
                        'extends': 'forDerivatives',
                    },
                    'inverse': {
                        'extends': 'forDerivatives',
                    },
                },
            },
        })

    def fetch_status(self, params={}):
        """
        the latest known information on the availability of the exchange API

        https://huobiapi.github.io/docs/spot/v1/en/#get-system-status
        https://huobiapi.github.io/docs/dm/v1/en/#get-system-status
        https://huobiapi.github.io/docs/coin_margined_swap/v1/en/#get-system-status
        https://huobiapi.github.io/docs/usdt_swap/v1/en/#get-system-status
        https://huobiapi.github.io/docs/usdt_swap/v1/en/#query-whether-the-system-is-available  # contractPublicGetHeartbeat

        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: a `status structure <https://docs.ccxt.com/#/?id=exchange-status-structure>`
        """
        self.load_markets()
        marketType = None
        marketType, params = self.handle_market_type_and_params('fetchStatus', None, params)
        enabledForContracts = self.handle_option('fetchStatus', 'enableForContracts', False)  # temp fix for: https://status-linear-swap.huobigroup.com/api/v2/summary.json
        response = None
        if marketType != 'spot' and enabledForContracts:
            subType = self.safe_string(params, 'subType', self.options['defaultSubType'])
            if marketType == 'swap':
                if subType == 'linear':
                    response = self.statusPublicSwapLinearGetApiV2SummaryJson()
                elif subType == 'inverse':
                    response = self.statusPublicSwapInverseGetApiV2SummaryJson()
            elif marketType == 'future':
                if subType == 'linear':
                    response = self.statusPublicFutureLinearGetApiV2SummaryJson()
                elif subType == 'inverse':
                    response = self.statusPublicFutureInverseGetApiV2SummaryJson()
            elif marketType == 'contract':
                response = self.contractPublicGetHeartbeat()
        elif marketType == 'spot':
            response = self.statusPublicSpotGetApiV2SummaryJson()
        #
        # statusPublicSpotGetApiV2SummaryJson, statusPublicSwapInverseGetApiV2SummaryJson, statusPublicFutureLinearGetApiV2SummaryJson, statusPublicFutureInverseGetApiV2SummaryJson
        #
        #      {
        #          "page": {
        #              "id":"mn7l2lw8pz4p",
        #              "name":"Huobi Futures-USDT-margined Swaps",
        #              "url":"https://status-linear-swap.huobigroup.com",
        #              "time_zone":"Asia/Singapore",
        #              "updated_at":"2022-04-29T12:47:21.319+08:00"},
        #              "components": [
        #                  {
        #                      "id":"lrv093qk3yp5",
        #                      "name":"market data",
        #                      "status":"operational",
        #                      "created_at":"2020-10-29T14:08:59.427+08:00",
        #                      "updated_at":"2020-10-29T14:08:59.427+08:00",
        #                      "position":1,"description":null,
        #                      "showcase":false,
        #                      "start_date":null,
        #                      "group_id":null,
        #                      "page_id":"mn7l2lw8pz4p",
        #                      "group":true,
        #                      "only_show_if_degraded":false,
        #                      "components": [
        #                          "82k5jxg7ltxd"  # list of related components
        #                      ]
        #                  },
        #              ],
        #              "incidents": [ # empty array if there are no issues
        #                  {
        #                      "id": "rclfxz2g21ly",  # incident id
        #                      "name": "Market data is delayed",  # incident name
        #                      "status": "investigating",  # incident status
        #                      "created_at": "2020-02-11T03:15:01.913Z",  # incident create time
        #                      "updated_at": "2020-02-11T03:15:02.003Z",   # incident update time
        #                      "monitoring_at": null,
        #                      "resolved_at": null,
        #                      "impact": "minor",  # incident impact
        #                      "shortlink": "http://stspg.io/pkvbwp8jppf9",
        #                      "started_at": "2020-02-11T03:15:01.906Z",
        #                      "page_id": "p0qjfl24znv5",
        #                      "incident_updates": [
        #                          {
        #                              "id": "dwfsk5ttyvtb",
        #                              "status": "investigating",
        #                              "body": "Market data is delayed",
        #                              "incident_id": "rclfxz2g21ly",
        #                              "created_at": "2020-02-11T03:15:02.000Z",
        #                              "updated_at": "2020-02-11T03:15:02.000Z",
        #                              "display_at": "2020-02-11T03:15:02.000Z",
        #                              "affected_components": [
        #                                  {
        #                                      "code": "nctwm9tghxh6",
        #                                      "name": "Market data",
        #                                      "old_status": "operational",
        #                                      "new_status": "degraded_performance"
        #                                  }
        #                              ],
        #                              "deliver_notifications": True,
        #                              "custom_tweet": null,
        #                              "tweet_id": null
        #                          }
        #                      ],
        #                      "components": [
        #                          {
        #                              "id": "nctwm9tghxh6",
        #                              "name": "Market data",
        #                              "status": "degraded_performance",
        #                              "created_at": "2020-01-13T09:34:48.284Z",
        #                              "updated_at": "2020-02-11T03:15:01.951Z",
        #                              "position": 8,
        #                              "description": null,
        #                              "showcase": False,
        #                              "group_id": null,
        #                              "page_id": "p0qjfl24znv5",
        #                              "group": False,
        #                              "only_show_if_degraded": False
        #                          }
        #                      ]
        #                  }, ...
        #              ],
        #              "scheduled_maintenances":[ # empty array if there are no scheduled maintenances
        #                  {
        #                      "id": "k7g299zl765l",  # incident id
        #                      "name": "Schedule maintenance",  # incident name
        #                      "status": "scheduled",  # incident status
        #                      "created_at": "2020-02-11T03:16:31.481Z",  # incident create time
        #                      "updated_at": "2020-02-11T03:16:31.530Z",  # incident update time
        #                      "monitoring_at": null,
        #                      "resolved_at": null,
        #                      "impact": "maintenance",  # incident impact
        #                      "shortlink": "http://stspg.io/md4t4ym7nytd",
        #                      "started_at": "2020-02-11T03:16:31.474Z",
        #                      "page_id": "p0qjfl24znv5",
        #                      "incident_updates": [
        #                          {
        #                              "id": "8whgr3rlbld8",
        #                              "status": "scheduled",
        #                              "body": "We will be undergoing scheduled maintenance during self time.",
        #                              "incident_id": "k7g299zl765l",
        #                              "created_at": "2020-02-11T03:16:31.527Z",
        #                              "updated_at": "2020-02-11T03:16:31.527Z",
        #                              "display_at": "2020-02-11T03:16:31.527Z",
        #                              "affected_components": [
        #                                  {
        #                                      "code": "h028tnzw1n5l",
        #                                      "name": "Deposit And Withdraw - Deposit",
        #                                      "old_status": "operational",
        #                                      "new_status": "operational"
        #                                  }
        #                              ],
        #                              "deliver_notifications": True,
        #                              "custom_tweet": null,
        #                              "tweet_id": null
        #                          }
        #                      ],
        #                      "components": [
        #                          {
        #                              "id": "h028tnzw1n5l",
        #                              "name": "Deposit",
        #                              "status": "operational",
        #                              "created_at": "2019-12-05T02:07:12.372Z",
        #                              "updated_at": "2020-02-10T12:34:52.970Z",
        #                              "position": 1,
        #                              "description": null,
        #                              "showcase": False,
        #                              "group_id": "gtd0nyr3pf0k",
        #                              "page_id": "p0qjfl24znv5",
        #                              "group": False,
        #                              "only_show_if_degraded": False
        #                          }
        #                      ],
        #                      "scheduled_for": "2020-02-15T00:00:00.000Z",  # scheduled maintenance start time
        #                      "scheduled_until": "2020-02-15T01:00:00.000Z"  # scheduled maintenance end time
        #                  }
        #              ],
        #              "status": {
        #                  "indicator":"none",  # none, minor, major, critical, maintenance
        #                  "description":"all systems operational"  # All Systems Operational, Minor Service Outage, Partial System Outage, Partially Degraded Service, Service Under Maintenance
        #              }
        #          }
        #
        #
        # contractPublicGetHeartbeat
        #
        #      {
        #          "status": "ok",  # 'ok', 'error'
        #          "data": {
        #              "heartbeat": 1,  # future 1: available, 0: maintenance with service suspended
        #              "estimated_recovery_time": null,  # estimated recovery time in milliseconds
        #              "swap_heartbeat": 1,
        #              "swap_estimated_recovery_time": null,
        #              "option_heartbeat": 1,
        #              "option_estimated_recovery_time": null,
        #              "linear_swap_heartbeat": 1,
        #              "linear_swap_estimated_recovery_time": null
        #          },
        #          "ts": 1557714418033
        #      }
        #
        status = None
        updated = None
        url = None
        if marketType == 'contract':
            statusRaw = self.safe_string(response, 'status')
            if statusRaw is None:
                status = None
            else:
                status = 'ok' if (statusRaw == 'ok') else 'maintenance'  # 'ok', 'error'
            updated = self.safe_string(response, 'ts')
        else:
            statusData = self.safe_value(response, 'status', {})
            statusRaw = self.safe_string(statusData, 'indicator')
            status = 'ok' if (statusRaw == 'none') else 'maintenance'  # none, minor, major, critical, maintenance
            pageData = self.safe_value(response, 'page', {})
            datetime = self.safe_string(pageData, 'updated_at')
            updated = self.parse8601(datetime)
            url = self.safe_string(pageData, 'url')
        return {
            'status': status,
            'updated': updated,
            'eta': None,
            'url': url,
            'info': response,
        }

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

        https://huobiapi.github.io/docs/spot/v1/en/#get-current-timestamp
        https://huobiapi.github.io/docs/coin_margined_swap/v1/en/#get-current-system-timestamp

        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns int: the current integer timestamp in milliseconds from the exchange server
        """
        options = self.safe_value(self.options, 'fetchTime', {})
        defaultType = self.safe_string(self.options, 'defaultType', 'spot')
        type = self.safe_string(options, 'type', defaultType)
        type = self.safe_string(params, 'type', type)
        response = None
        if (type == 'future') or (type == 'swap'):
            response = self.contractPublicGetApiV1Timestamp(params)
        else:
            response = self.spotPublicGetV1CommonTimestamp(params)
        #
        # spot
        #
        #     {"status":"ok","data":1637504261099}
        #
        # future, swap
        #
        #     {"status":"ok","ts":1637504164707}
        #
        return self.safe_integer_2(response, 'data', 'ts')

    def parse_trading_fee(self, fee: dict, market: Market = None) -> TradingFeeInterface:
        #
        #     {
        #         "symbol":"btcusdt",
        #         "actualMakerRate":"0.002",
        #         "actualTakerRate":"0.002",
        #         "takerFeeRate":"0.002",
        #         "makerFeeRate":"0.002"
        #     }
        #
        marketId = self.safe_string(fee, 'symbol')
        return {
            'info': fee,
            'symbol': self.safe_symbol(marketId, market),
            'maker': self.safe_number(fee, 'actualMakerRate'),
            'taker': self.safe_number(fee, 'actualTakerRate'),
            'percentage': None,
            'tierBased': None,
        }

    def fetch_trading_fee(self, symbol: str, params={}) -> TradingFeeInterface:
        """
        fetch the trading fees for a market

        https://huobiapi.github.io/docs/spot/v1/en/#get-current-fee-rate-applied-to-the-user

        :param str symbol: unified market symbol
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: a `fee structure <https://docs.ccxt.com/#/?id=fee-structure>`
        """
        self.load_markets()
        market = self.market(symbol)
        request: dict = {
            'symbols': market['id'],  # trading symbols comma-separated
        }
        response = self.spotPrivateGetV2ReferenceTransactFeeRate(self.extend(request, params))
        #
        #     {
        #         "code":200,
        #         "data":[
        #             {
        #                 "symbol":"btcusdt",
        #                 "actualMakerRate":"0.002",
        #                 "actualTakerRate":"0.002",
        #                 "takerFeeRate":"0.002",
        #                 "makerFeeRate":"0.002"
        #             }
        #         ],
        #         "success":true
        #     }
        #
        data = self.safe_value(response, 'data', [])
        first = self.safe_value(data, 0, {})
        return self.parse_trading_fee(first, market)

    def fetch_trading_limits(self, symbols: Strings = None, params={}):
        # self method should not be called directly, use loadTradingLimits() instead
        #  by default it will try load withdrawal fees of all currencies(with separate requests)
        #  however if you define symbols = ['ETH/BTC', 'LTC/BTC'] in args it will only load those
        self.load_markets()
        if symbols is None:
            symbols = self.symbols
        result: dict = {}
        for i in range(0, len(symbols)):
            symbol = symbols[i]
            result[symbol] = self.fetch_trading_limits_by_id(self.market_id(symbol), params)
        return result

    def fetch_trading_limits_by_id(self, id: str, params={}):
        """
 @ignore

        https://huobiapi.github.io/docs/spot/v1/en/#get-current-fee-rate-applied-to-the-user

        :param str id: market id
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: the limits object of a market structure
        """
        request: dict = {
            'symbol': id,
        }
        response = self.spotPublicGetV1CommonExchange(self.extend(request, params))
        #
        #     {status:   "ok",
        #         "data": {                                 symbol: "aidocbtc",
        #                              "buy-limit-must-less-than":  1.1,
        #                          "sell-limit-must-greater-than":  0.9,
        #                         "limit-order-must-greater-than":  1,
        #                            "limit-order-must-less-than":  5000000,
        #                    "market-buy-order-must-greater-than":  0.0001,
        #                       "market-buy-order-must-less-than":  100,
        #                   "market-sell-order-must-greater-than":  1,
        #                      "market-sell-order-must-less-than":  500000,
        #                       "circuit-break-when-greater-than":  10000,
        #                          "circuit-break-when-less-than":  10,
        #                 "market-sell-order-rate-must-less-than":  0.1,
        #                  "market-buy-order-rate-must-less-than":  0.1        }}
        #
        return self.parse_trading_limits(self.safe_value(response, 'data', {}))

    def parse_trading_limits(self, limits, symbol: Str = None, params={}):
        #
        #   {                               "symbol": "aidocbtc",
        #                  "buy-limit-must-less-than":  1.1,
        #              "sell-limit-must-greater-than":  0.9,
        #             "limit-order-must-greater-than":  1,
        #                "limit-order-must-less-than":  5000000,
        #        "market-buy-order-must-greater-than":  0.0001,
        #           "market-buy-order-must-less-than":  100,
        #       "market-sell-order-must-greater-than":  1,
        #          "market-sell-order-must-less-than":  500000,
        #           "circuit-break-when-greater-than":  10000,
        #              "circuit-break-when-less-than":  10,
        #     "market-sell-order-rate-must-less-than":  0.1,
        #      "market-buy-order-rate-must-less-than":  0.1        }
        #
        return {
            'info': limits,
            'limits': {
                'amount': {
                    'min': self.safe_number(limits, 'limit-order-must-greater-than'),
                    'max': self.safe_number(limits, 'limit-order-must-less-than'),
                },
            },
        }

    def cost_to_precision(self, symbol, cost):
        return self.decimal_to_precision(cost, TRUNCATE, self.markets[symbol]['precision']['cost'], self.precisionMode)

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

        https://huobiapi.github.io/docs/spot/v1/en/#get-all-supported-trading-symbol-v1-deprecated
        https://huobiapi.github.io/docs/dm/v1/en/#get-contract-info
        https://huobiapi.github.io/docs/coin_margined_swap/v1/en/#query-swap-info
        https://huobiapi.github.io/docs/usdt_swap/v1/en/#general-query-swap-info

        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict[]: an array of objects representing market data
        """
        if self.options['adjustForTimeDifference']:
            self.load_time_difference()
        types = None
        types, params = self.handle_option_and_params(params, 'fetchMarkets', 'types', {})
        allMarkets = []
        promises = []
        keys = list(types.keys())
        for i in range(0, len(keys)):
            key = keys[i]
            if self.safe_bool(types, key):
                if key == 'spot':
                    promises.append(self.fetch_markets_by_type_and_sub_type('spot', None, params))
                elif key == 'linear':
                    promises.append(self.fetch_markets_by_type_and_sub_type(None, 'linear', params))
                elif key == 'inverse':
                    promises.append(self.fetch_markets_by_type_and_sub_type('swap', 'inverse', params))
                    promises.append(self.fetch_markets_by_type_and_sub_type('future', 'inverse', params))
        promises = promises
        for i in range(0, len(promises)):
            allMarkets = self.array_concat(allMarkets, promises[i])
        return allMarkets

    def fetch_markets_by_type_and_sub_type(self, type: Str, subType: Str, params={}):
        """
 @ignore
        retrieves data on all markets of a certain type and/or subtype

        https://huobiapi.github.io/docs/spot/v1/en/#get-all-supported-trading-symbol-v1-deprecated
        https://huobiapi.github.io/docs/dm/v1/en/#get-contract-info
        https://huobiapi.github.io/docs/coin_margined_swap/v1/en/#query-swap-info
        https://huobiapi.github.io/docs/usdt_swap/v1/en/#general-query-swap-info

        :param str [type]: 'spot', 'swap' or 'future'
        :param str [subType]: 'linear' or 'inverse'
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict[]: an array of objects representing market data
        """
        isSpot = (type == 'spot')
        request: dict = {}
        response = None
        if not isSpot:
            if subType == 'linear':
                request['business_type'] = 'all'  # override default to fetch all linear markets
                response = self.contractPublicGetLinearSwapApiV1SwapContractInfo(self.extend(request, params))
            elif subType == 'inverse':
                if type == 'future':
                    response = self.contractPublicGetApiV1ContractContractInfo(self.extend(request, params))
                elif type == 'swap':
                    response = self.contractPublicGetSwapApiV1SwapContractInfo(self.extend(request, params))
        else:
            response = self.spotPublicGetV1CommonSymbols(self.extend(request, params))
        #
        # spot
        #
        #     {
        #         "status":"ok",
        #         "data":[
        #             {
        #                 "base-currency":"xrp3s",
        #                 "quote-currency":"usdt",
        #                 "price-precision":4,
        #                 "amount-precision":4,
        #                 "symbol-partition":"innovation",
        #                 "symbol":"xrp3susdt",
        #                 "state":"online",
        #                 "value-precision":8,
        #                 "min-order-amt":0.01,
        #                 "max-order-amt":1616.4353,
        #                 "min-order-value":5,
        #                 "limit-order-min-order-amt":0.01,
        #                 "limit-order-max-order-amt":1616.4353,
        #                 "limit-order-max-buy-amt":1616.4353,
        #                 "limit-order-max-sell-amt":1616.4353,
        #                 "sell-market-min-order-amt":0.01,
        #                 "sell-market-max-order-amt":1616.4353,
        #                 "buy-market-max-order-value":2500,
        #                 "max-order-value":2500,
        #                 "underlying":"xrpusdt",
        #                 "mgmt-fee-rate":0.035000000000000000,
        #                 "charge-time":"23:55:00",
        #                 "rebal-time":"00:00:00",
        #                 "rebal-threshold":-5,
        #                 "init-nav":10.000000000000000000,
        #                 "api-trading":"enabled",
        #                 "tags":"etp,nav,holdinglimit"
        #             },
        #         ]
        #     }
        #
        # inverse(swap & future)
        #
        #     {
        #         "status":"ok",
        #         "data":[
        #             {
        #                 "symbol":"BTC",
        #                 "contract_code":"BTC211126",  #/ BTC-USD in swap
        #                 "contract_type":"self_week",  # only in future
        #                 "contract_size":100,
        #                 "price_tick":0.1,
        #                 "delivery_date":"20211126",  # only in future
        #                 "delivery_time":"1637913600000",  # empty in swap
        #                 "create_date":"20211112",
        #                 "contract_status":1,
        #                 "settlement_time":"1637481600000"  # only in future
        #                 "settlement_date":"16xxxxxxxxxxx"  # only in swap
        #             },
        #           ...
        #         ],
        #         "ts":1637474595140
        #     }
        #
        # linear(swap & future)
        #
        #     {
        #         "status":"ok",
        #         "data":[
        #             {
        #                 "symbol":"BTC",
        #                 "contract_code":"BTC-USDT-211231",  # or "BTC-USDT" in swap
        #                 "contract_size":0.001,
        #                 "price_tick":0.1,
        #                 "delivery_date":"20211231",  # empty in swap
        #                 "delivery_time":"1640937600000",  # empty in swap
        #                 "create_date":"20211228",
        #                 "contract_status":1,
        #                 "settlement_date":"1640764800000",
        #                 "support_margin_mode":"cross",  # "all" or "cross"
        #                 "business_type":"futures",  # "swap" or "futures"
        #                 "pair":"BTC-USDT",
        #                 "contract_type":"self_week",  # "swap", "self_week", "next_week", "quarter"
        #                 "trade_partition":"USDT",
        #             }
        #         ],
        #         "ts":1640736207263
        #     }
        #
        markets = self.safe_list(response, 'data', [])
        numMarkets = len(markets)
        if numMarkets < 1:
            raise OperationFailed(self.id + ' fetchMarkets() returned an empty response: ' + self.json(response))
        result = []
        for i in range(0, len(markets)):
            market = markets[i]
            baseId = None
            quoteId = None
            settleId = None
            id = None
            lowercaseId = None
            contract = ('contract_code' in market)
            spot = not contract
            swap = False
            future = False
            linear = None
            inverse = None
            # check if parsed market is contract
            if contract:
                id = self.safe_string(market, 'contract_code')
                lowercaseId = id.lower()
                delivery_date = self.safe_string(market, 'delivery_date')
                business_type = self.safe_string(market, 'business_type')
                future = delivery_date is not None
                swap = not future
                linear = business_type is not None
                inverse = not linear
                if swap:
                    type = 'swap'
                    parts = id.split('-')
                    baseId = self.safe_string_lower(market, 'symbol')
                    quoteId = self.safe_string_lower(parts, 1)
                    settleId = baseId if inverse else quoteId
                elif future:
                    type = 'future'
                    baseId = self.safe_string_lower(market, 'symbol')
                    if inverse:
                        quoteId = 'USD'
                        settleId = baseId
                    else:
                        pair = self.safe_string(market, 'pair')
                        parts = pair.split('-')
                        quoteId = self.safe_string_lower(parts, 1)
                        settleId = quoteId
            else:
                type = 'spot'
                baseId = self.safe_string(market, 'base-currency')
                quoteId = self.safe_string(market, 'quote-currency')
                id = baseId + quoteId
                lowercaseId = id.lower()
            base = self.safe_currency_code(baseId)
            quote = self.safe_currency_code(quoteId)
            settle = self.safe_currency_code(settleId)
            symbol = base + '/' + quote
            expiry = None
            if contract:
                if inverse:
                    symbol += ':' + base
                elif linear:
                    symbol += ':' + quote
                if future:
                    expiry = self.safe_integer(market, 'delivery_time')
                    symbol += '-' + self.yymmdd(expiry)
            contractSize = self.safe_number(market, 'contract_size')
            minCost = self.safe_number(market, 'min-order-value')
            maxAmount = self.safe_number(market, 'max-order-amt')
            minAmount = self.safe_number(market, 'min-order-amt')
            if contract:
                if linear:
                    minAmount = contractSize
                elif inverse:
                    minCost = contractSize
            pricePrecision = None
            amountPrecision = None
            costPrecision = None
            maker = None
            taker = None
            active = None
            if spot:
                pricePrecision = self.parse_number(self.parse_precision(self.safe_string(market, 'price-precision')))
                amountPrecision = self.parse_number(self.parse_precision(self.safe_string(market, 'amount-precision')))
                costPrecision = self.parse_number(self.parse_precision(self.safe_string(market, 'value-precision')))
                maker = self.parse_number('0.002')
                taker = self.parse_number('0.002')
                state = self.safe_string(market, 'state')
                active = (state == 'online')
            else:
                pricePrecision = self.safe_number(market, 'price_tick')
                amountPrecision = self.parse_number('1')  # other markets have step size of 1 contract
                maker = self.parse_number('0.0002')
                taker = self.parse_number('0.0005')
                contractStatus = self.safe_integer(market, 'contract_status')
                active = (contractStatus == 1)
            leverageRatio = self.safe_string(market, 'leverage-ratio', '1')
            superLeverageRatio = self.safe_string(market, 'super-margin-leverage-ratio', '1')
            hasLeverage = Precise.string_gt(leverageRatio, '1') or Precise.string_gt(superLeverageRatio, '1')
            # 0 Delisting
            # 1 Listing
            # 2 Pending Listing
            # 3 Suspension
            # 4 Suspending of Listing
            # 5 In Settlement
            # 6 Delivering
            # 7 Settlement Completed
            # 8 Delivered
            # 9 Suspending of Trade
            created = None
            createdDate = self.safe_string(market, 'create_date')  # i.e 20230101
            if createdDate is not None:
                createdArray = self.string_to_chars_array(createdDate)
                createdDate = createdArray[0] + createdArray[1] + createdArray[2] + createdArray[3] + '-' + createdArray[4] + createdArray[5] + '-' + createdArray[6] + createdArray[7] + ' 00:00:00'
                created = self.parse8601(createdDate)
            result.append({
                'id': id,
                'lowercaseId': lowercaseId,
                'symbol': symbol,
                'base': base,
                'quote': quote,
                'settle': settle,
                'baseId': baseId,
                'quoteId': quoteId,
                'settleId': settleId,
                'type': type,
                'spot': spot,
                'margin': (spot and hasLeverage),
                'swap': swap,
                'future': future,
                'option': False,
                'active': active,
                'contract': contract,
                'linear': linear,
                'inverse': inverse,
                'taker': taker,
                'maker': maker,
                'contractSize': contractSize,
                'expiry': expiry,
                'expiryDatetime': self.iso8601(expiry),
                'strike': None,
                'optionType': None,
                'precision': {
                    'amount': amountPrecision,
                    'price': pricePrecision,
                    'cost': costPrecision,
                },
                'limits': {
                    'leverage': {
                        'min': self.parse_number('1'),
                        'max': self.parse_number(leverageRatio),
                        'superMax': self.parse_number(superLeverageRatio),
                    },
                    'amount': {
                        'min': minAmount,
                        'max': maxAmount,
                    },
                    'price': {
                        'min': None,
                        'max': None,
                    },
                    'cost': {
                        'min': minCost,
                        'max': None,
                    },
                },
                'created': created,
                'info': market,
            })
        return result

    def try_get_symbol_from_future_markets(self, symbolOrMarketId: str):
        if symbolOrMarketId in self.markets:
            return symbolOrMarketId
        # only on "future" market type(inverse & linear), market-id differs between "fetchMarkets" and "fetchTicker"
        # so we have to create a mapping
        # - market-id from fetchMarkts:    `BTC-USDT-240419`(linear future) or `BTC240412`(inverse future)
        # - market-id from fetchTciker[s]: `BTC-USDT-CW`     (linear future) or `BTC_CW`    (inverse future)
        if not ('futureMarketIdsForSymbols' in self.options):
            self.options['futureMarketIdsForSymbols'] = {}
        futureMarketIdsForSymbols = self.safe_dict(self.options, 'futureMarketIdsForSymbols', {})
        if symbolOrMarketId in futureMarketIdsForSymbols:
            return futureMarketIdsForSymbols[symbolOrMarketId]
        futureMarkets = self.filter_by(self.markets, 'future', True)
        futuresCharsMaps: dict = {
            'this_week': 'CW',
            'next_week': 'NW',
            'quarter': 'CQ',
            'next_quarter': 'NQ',
        }
        for i in range(0, len(futureMarkets)):
            market = futureMarkets[i]
            info = self.safe_value(market, 'info', {})
            contractType = self.safe_string(info, 'contract_type')
            contractSuffix = futuresCharsMaps[contractType]
            # see comment on formats a bit above
            constructedId = market['base'] + '-' + market['quote'] + '-' + contractSuffix if market['linear'] else market['base'] + '_' + contractSuffix
            if constructedId == symbolOrMarketId:
                symbol = market['symbol']
                self.options['futureMarketIdsForSymbols'][symbolOrMarketId] = symbol
                return symbol
        # if not found, just save it to avoid unnecessary future iterations
        self.options['futureMarketIdsForSymbols'][symbolOrMarketId] = symbolOrMarketId
        return symbolOrMarketId

    def parse_ticker(self, ticker: dict, market: Market = None) -> Ticker:
        #
        # fetchTicker
        #
        #     {
        #         "amount": 26228.672978342216,
        #         "open": 9078.95,
        #         "close": 9146.86,
        #         "high": 9155.41,
        #         "id": 209988544334,
        #         "count": 265846,
        #         "low": 8988.0,
        #         "version": 209988544334,
        #         "ask": [9146.87, 0.156134],
        #         "vol": 2.3822168242201668E8,
        #         "bid": [9146.86, 0.080758],
        #     }
        #
        # fetchTickers
        #
        #     {
        #         "symbol": "bhdht",
        #         "open":  2.3938,
        #         "high":  2.4151,
        #         "low":  2.3323,
        #         "close":  2.3909,
        #         "amount":  628.992,
        #         "vol":  1493.71841095,
        #         "count":  2088,
        #         "bid":  2.3643,
        #         "bidSize":  0.7136,
        #         "ask":  2.4061,
        #         "askSize":  0.4156
        #     }
        #
        # watchTikcer - bbo
        #     {
        #         "seqId": 161499562790,
        #         "ask": 16829.51,
        #         "askSize": 0.707776,
        #         "bid": 16829.5,
        #         "bidSize": 1.685945,
        #         "quoteTime": 1671941599612,
        #         "symbol": "btcusdt"
        #     }
        #
        marketId = self.safe_string_2(ticker, 'symbol', 'contract_code')
        symbol = self.safe_symbol(marketId, market)
        symbol = self.try_get_symbol_from_future_markets(symbol)
        timestamp = self.safe_integer_2(ticker, 'ts', 'quoteTime')
        bid = None
        bidVolume = None
        ask = None
        askVolume = None
        if 'bid' in ticker:
            if ticker['bid'] is not None and isinstance(ticker['bid'], list):
                bid = self.safe_string(ticker['bid'], 0)
                bidVolume = self.safe_string(ticker['bid'], 1)
            else:
                bid = self.safe_string(ticker, 'bid')
                bidVolume = self.safe_string(ticker, 'bidSize')
        if 'ask' in ticker:
            if ticker['ask'] is not None and isinstance(ticker['ask'], list):
                ask = self.safe_string(ticker['ask'], 0)
                askVolume = self.safe_string(ticker['ask'], 1)
            else:
                ask = self.safe_string(ticker, 'ask')
                askVolume = self.safe_string(ticker, 'askSize')
        open = self.safe_string(ticker, 'open')
        close = self.safe_string(ticker, 'close')
        baseVolume = self.safe_string(ticker, 'amount')
        quoteVolume = self.safe_string(ticker, 'vol')
        return self.safe_ticker({
            'symbol': symbol,
            'timestamp': timestamp,
            'datetime': self.iso8601(timestamp),
            'high': self.safe_string(ticker, 'high'),
            'low': self.safe_string(ticker, 'low'),
            'bid': bid,
            'bidVolume': bidVolume,
            'ask': ask,
            'askVolume': askVolume,
            'vwap': None,
            'open': open,
            'close': close,
            'last': close,
            'previousClose': None,
            'change': None,
            'percentage': None,
            'average': None,
            'baseVolume': baseVolume,
            'quoteVolume': quoteVolume,
            'info': ticker,
        }, market)

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

        https://huobiapi.github.io/docs/spot/v1/en/#get-latest-aggregated-ticker
        https://huobiapi.github.io/docs/dm/v1/en/#get-market-data-overview
        https://huobiapi.github.io/docs/coin_margined_swap/v1/en/#get-market-data-overview
        https://huobiapi.github.io/docs/usdt_swap/v1/en/#general-get-market-data-overview

        :param str symbol: unified symbol of the market to fetch the ticker for
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
        """
        self.load_markets()
        market = self.market(symbol)
        request: dict = {}
        response = None
        if market['linear']:
            request['contract_code'] = market['id']
            response = self.contractPublicGetLinearSwapExMarketDetailMerged(self.extend(request, params))
        elif market['inverse']:
            if market['future']:
                request['symbol'] = market['id']
                response = self.contractPublicGetMarketDetailMerged(self.extend(request, params))
            elif market['swap']:
                request['contract_code'] = market['id']
                response = self.contractPublicGetSwapExMarketDetailMerged(self.extend(request, params))
        else:
            request['symbol'] = market['id']
            response = self.spotPublicGetMarketDetailMerged(self.extend(request, params))
        #
        # spot
        #
        #     {
        #         "status": "ok",
        #         "ch": "market.btcusdt.detail.merged",
        #         "ts": 1583494336669,
        #         "tick": {
        #             "amount": 26228.672978342216,
        #             "open": 9078.95,
        #             "close": 9146.86,
        #             "high": 9155.41,
        #             "id": 209988544334,
        #             "count": 265846,
        #             "low": 8988.0,
        #             "version": 209988544334,
        #             "ask": [9146.87, 0.156134],
        #             "vol": 2.3822168242201668E8,
        #             "bid": [9146.86, 0.080758],
        #         }
        #     }
        #
        # future, swap
        #
        #     {
        #         "ch":"market.BTC211126.detail.merged",
        #         "status":"ok",
        #         "tick":{
        #             "amount":"669.3385682049668320322569544150680718474",
        #             "ask":[59117.44,48],
        #             "bid":[59082,48],
        #             "close":"59087.97",
        #             "count":5947,
        #             "high":"59892.62",
        #             "id":1637502670,
        #             "low":"57402.87",
        #             "open":"57638",
        #             "ts":1637502670059,
        #             "vol":"394598"
        #         },
        #         "ts":1637502670059
        #     }
        #
        tick = self.safe_value(response, 'tick', {})
        ticker = self.parse_ticker(tick, market)
        timestamp = self.safe_integer(response, 'ts')
        ticker['timestamp'] = timestamp
        ticker['datetime'] = self.iso8601(timestamp)
        return ticker

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

        https://huobiapi.github.io/docs/spot/v1/en/#get-latest-tickers-for-all-pairs
        https://huobiapi.github.io/docs/usdt_swap/v1/en/#general-get-a-batch-of-market-data-overview
        https://huobiapi.github.io/docs/dm/v1/en/#get-a-batch-of-market-data-overview
        https://huobiapi.github.io/docs/coin_margined_swap/v1/en/#get-a-batch-of-market-data-overview-v2

        :param str[] [symbols]: unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: a dictionary of `ticker structures <https://docs.ccxt.com/#/?id=ticker-structure>`
        """
        self.load_markets()
        symbols = self.market_symbols(symbols)
        first = self.safe_string(symbols, 0)
        market = None
        if first is not None:
            market = self.market(first)
        isSubTypeRequested = ('subType' in params) or ('business_type' in params)
        type = None
        subType = None
        type, params = self.handle_market_type_and_params('fetchTickers', market, params)
        subType, params = self.handle_sub_type_and_params('fetchTickers', market, params)
        request: dict = {}
        isSpot = (type == 'spot')
        future = (type == 'future')
        swap = (type == 'swap')
        linear = (subType == 'linear')
        inverse = (subType == 'inverse')
        response = None
        if not isSpot or isSubTypeRequested:
            if linear:
                # independently of type, supports calling all linear symbols i.e. fetchTickers(None, {subType:'linear'})
                if future:
                    request['business_type'] = 'futures'
                elif swap:
                    request['business_type'] = 'swap'
                else:
                    request['business_type'] = 'all'
                response = self.contractPublicGetLinearSwapExMarketDetailBatchMerged(self.extend(request, params))
            elif inverse:
                if future:
                    response = self.contractPublicGetMarketDetailBatchMerged(self.extend(request, params))
                elif swap:
                    response = self.contractPublicGetSwapExMarketDetailBatchMerged(self.extend(request, params))
                else:
                    raise NotSupported(self.id + ' fetchTickers() you have to set params["type"] to either "swap" or "future" for inverse contracts')
            else:
                raise NotSupported(self.id + ' fetchTickers() you have to set params["subType"] to either "linear" or "inverse" for contracts')
        else:
            response = self.spotPublicGetMarketTickers(self.extend(request, params))
        #
        # spot
        #
        #     {
        #         "data":[
        #             {
        #                 "symbol":"hbcbtc",
        #                 "open":5.313E-5,
        #                 "high":5.34E-5,
        #                 "low":5.112E-5,
        #                 "close":5.175E-5,
        #                 "amount":1183.87,
        #                 "vol":0.0618599229,
        #                 "count":205,
        #                 "bid":5.126E-5,
        #                 "bidSize":5.25,
        #                 "ask":5.214E-5,
        #                 "askSize":150.0
        #             },
        #         ],
        #         "status":"ok",
        #         "ts":1639547261293
        #     }
        #
        # linear swap, linear future, inverse swap, inverse future
        #
        #     {
        #         "status":"ok",
        #         "ticks":[
        #             {
        #                 "id":1637504679,
        #                 "ts":1637504679372,
        #                 "ask":[0.10644,100],
        #                 "bid":[0.10624,26],
        #                 "symbol":"TRX_CW",
        #                 "open":"0.10233",
        #                 "close":"0.10644",
        #                 "low":"0.1017",
        #                 "high":"0.10725",
        #                 "amount":"2340267.415144052378486261756692535687481566",
        #                 "count":882,
        #                 "vol":"24706",
        #                 "trade_turnover":"840726.5048",  # only in linear futures
        #                 "business_type":"futures",  # only in linear futures
        #                 "contract_code":"BTC-USDT-CW",  # only in linear futures, instead of 'symbol'
        #             }
        #         ],
        #         "ts":1637504679376
        #     }
        #
        rawTickers = self.safe_list_2(response, 'data', 'ticks', [])
        tickers = self.parse_tickers(rawTickers, symbols, params)
        return self.filter_by_array_tickers(tickers, 'symbol', symbols)

    def fetch_last_prices(self, symbols: Strings = None, params={}):
        """
        fetches the last price for multiple markets

        https://www.htx.com/en-us/opend/newApiPages/?id=8cb81024-77b5-11ed-9966-0242ac110003 linear swap & linear future
        https://www.htx.com/en-us/opend/newApiPages/?id=28c2e8fc-77ae-11ed-9966-0242ac110003 inverse future
        https://www.htx.com/en-us/opend/newApiPages/?id=5d517ef5-77b6-11ed-9966-0242ac110003 inverse swap

        :param str[] [symbols]: unified symbols of the markets to fetch the last prices
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: a dictionary of lastprices structures
        """
        self.load_markets()
        symbols = self.market_symbols(symbols)
        market = self.get_market_from_symbols(symbols)
        type = None
        subType = None
        subType, params = self.handle_sub_type_and_params('fetchLastPrices', market, params)
        type, params = self.handle_market_type_and_params('fetchLastPrices', market, params)
        response = None
        if ((type == 'swap') or (type == 'future')) and (subType == 'linear'):
            response = self.contractPublicGetLinearSwapExMarketTrade(params)
            #
            #     {
            #         "ch": "market.*.trade.detail",
            #         "status": "ok",
            #         "tick": {
            #           "data": [
            #             {
            #               "amount": "4",
            #               "quantity": "40",
            #               "trade_turnover": "22.176",
            #               "ts": 1703697705028,
            #               "id": 1000003558478170000,
            #               "price": "0.5544",
            #               "direction": "buy",
            #               "contract_code": "MANA-USDT",
            #               "business_type": "swap",
            #               "trade_partition": "USDT"
            #             },
            #           ],
            #           "id": 1703697740147,
            #           "ts": 1703697740147
            #         },
            #         "ts": 1703697740147
            #     }
            #
        elif (type == 'swap') and (subType == 'inverse'):
            response = self.contractPublicGetSwapExMarketTrade(params)
            #
            #     {
            #         "ch": "market.*.trade.detail",
            #         "status": "ok",
            #         "tick": {
            #           "data": [
            #             {
            #               "amount": "6",
            #               "quantity": "94.5000945000945000945000945000945000945",
            #               "ts": 1703698704594,
            #               "id": 1000001187811060000,
            #               "price": "0.63492",
            #               "direction": "buy",
            #               "contract_code": "XRP-USD"
            #             },
            #           ],
            #           "id": 1703698706589,
            #           "ts": 1703698706589
            #         },
            #         "ts": 1703698706589
            #     }
            #
        elif (type == 'future') and (subType == 'inverse'):
            response = self.contractPublicGetMarketTrade(params)
            #
            #     {
            #         "ch": "market.*.trade.detail",
            #         "status": "ok",
            #         "tick": {
            #           "data": [
            #             {
            #               "amount": "20",
            #               "quantity": "44.4444444444444444444444444444444444444",
            #               "ts": 1686134498885,
            #               "id": 2323000000174820000,
            #               "price": "4.5",
            #               "direction": "sell",
            #               "symbol": "DORA_CW"
            #             },
            #           ],
            #           "id": 1703698855142,
            #           "ts": 1703698855142
            #         },
            #         "ts": 1703698855142
            #     }
            #
        else:
            raise NotSupported(self.id + ' fetchLastPrices() does not support ' + type + ' markets yet')
        tick = self.safe_value(response, 'tick', {})
        data = self.safe_list(tick, 'data', [])
        return self.parse_last_prices(data, symbols)

    def parse_last_price(self, entry, market: Market = None):
        # example responses are documented in fetchLastPrices
        marketId = self.safe_string_2(entry, 'symbol', 'contract_code')
        market = self.safe_market(marketId, market)
        price = self.safe_number(entry, 'price')
        direction = self.safe_string(entry, 'direction')  # "buy" or "sell"
        # group timestamp should not be assigned to the individual trades' times
        return {
            'symbol': market['symbol'],
            'timestamp': None,
            'datetime': None,
            'price': price,
            'side': direction,
            'info': entry,
        }

    def fetch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook:
        """
        fetches information on open orders with bid(buy) and ask(sell) prices, volumes and other data

        https://huobiapi.github.io/docs/spot/v1/en/#get-market-depth
        https://huobiapi.github.io/docs/dm/v1/en/#get-market-depth
        https://huobiapi.github.io/docs/coin_margined_swap/v1/en/#get-market-depth
        https://huobiapi.github.io/docs/usdt_swap/v1/en/#general-get-market-depth

        :param str symbol: unified symbol of the market to fetch the order book for
        :param int [limit]: the maximum amount of order book entries to return
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: A dictionary of `order book structures <https://docs.ccxt.com/#/?id=order-book-structure>` indexed by market symbols
        """
        self.load_markets()
        market = self.market(symbol)
        request: dict = {
            #
            # from the API docs
            #
            #     to get depth data within step 150, use step0, step1, step2, step3, step4, step5, step14, step15（merged depth data 0-5,14-15, when step is 0，depth data will not be merged
            #     to get depth data within step 20, use step6, step7, step8, step9, step10, step11, step12, step13(merged depth data 7-13), when step is 6, depth data will not be merged
            #
            'type': 'step0',
            # 'symbol': market['id'],  # spot, future
            # 'contract_code': market['id'],  # swap
        }
        response = None
        if market['linear']:
            request['contract_code'] = market['id']
            response = self.contractPublicGetLinearSwapExMarketDepth(self.extend(request, params))
        elif market['inverse']:
            if market['future']:
                request['symbol'] = market['id']
                response = self.contractPublicGetMarketDepth(self.extend(request, params))
            elif market['swap']:
                request['contract_code'] = market['id']
                response = self.contractPublicGetSwapExMarketDepth(self.extend(request, params))
        else:
            if limit is not None:
                # Valid depths are 5, 10, 20 or empty https://huobiapi.github.io/docs/spot/v1/en/#get-market-depth
                if (limit != 5) and (limit != 10) and (limit != 20) and (limit != 150):
                    raise BadRequest(self.id + ' fetchOrderBook() limit argument must be None, 5, 10, 20, or 150, default is 150')
                # only set the depth if it is not 150
                # 150 is the implicit default on the exchange side for step0 and no orderbook aggregation
                # it is not accepted by the exchange if you set it explicitly
                if limit != 150:
                    request['depth'] = limit
            request['symbol'] = market['id']
            response = self.spotPublicGetMarketDepth(self.extend(request, params))
        #
        # spot, future, swap
        #
        #     {
        #         "status": "ok",
        #         "ch": "market.btcusdt.depth.step0",
        #         "ts": 1583474832790,
        #         "tick": {
        #             "bids": [
        #                 [9100.290000000000000000, 0.200000000000000000],
        #                 [9099.820000000000000000, 0.200000000000000000],
        #                 [9099.610000000000000000, 0.205000000000000000],
        #             ],
        #             "asks": [
        #                 [9100.640000000000000000, 0.005904000000000000],
        #                 [9101.010000000000000000, 0.287311000000000000],
        #                 [9101.030000000000000000, 0.012121000000000000],
        #             ],
        #             "ch":"market.BTC-USD.depth.step0",
        #             "ts":1583474832008,
        #             "id":1637554816,
        #             "mrid":121654491624,
        #             "version":104999698781
        #         }
        #     }
        #
        if 'tick' in response:
            if not response['tick']:
                raise BadSymbol(self.id + ' fetchOrderBook() returned empty response: ' + self.json(response))
            tick = self.safe_value(response, 'tick')
            timestamp = self.safe_integer(tick, 'ts', self.safe_integer(response, 'ts'))
            result = self.parse_order_book(tick, symbol, timestamp)
            result['nonce'] = self.safe_integer(tick, 'version')
            return result
        raise ExchangeError(self.id + ' fetchOrderBook() returned unrecognized response: ' + self.json(response))

    def parse_trade(self, trade: dict, market: Market = None) -> Trade:
        #
        # spot fetchTrades(public)
        #
        #     {
        #         "amount": 0.010411000000000000,
        #         "trade-id": 102090736910,
        #         "ts": 1583497692182,
        #         "id": 10500517034273194594947,
        #         "price": 9096.050000000000000000,
        #         "direction": "sell"
        #     }
        #
        # spot fetchMyTrades(private)
        #
        #     {
        #          "symbol": "swftcbtc",
        #          "fee-currency": "swftc",
        #          "filled-fees": "0",
        #          "source": "spot-api",
        #          "id": 83789509854000,
        #          "type": "buy-limit",
        #          "order-id": 83711103204909,
        #          'filled-points': "0.005826843283532154",
        #          "fee-deduct-currency": "ht",
        #          'filled-amount': "45941.53",
        #          "price": "0.0000001401",
        #          "created-at": 1597933260729,
        #          "match-id": 100087455560,
        #          "role": "maker",
        #          "trade-id": 100050305348
        #     }
        #
        # linear swap isolated margin fetchOrder details
        #
        #     {
        #         "trade_id": 131560927,
        #         "trade_price": 13059.800000000000000000,
        #         "trade_volume": 1.000000000000000000,
        #         "trade_turnover": 13.059800000000000000,
        #         "trade_fee": -0.005223920000000000,
        #         "created_at": 1603703614715,
        #         "role": "taker",
        #         "fee_asset": "USDT",
        #         "profit": 0,
        #         "real_profit": 0,
        #         "id": "131560927-770334322963152896-1"
        #     }
        #
        # inverse swap cross margin fetchMyTrades
        #
        #     {
        #         "contract_type":"swap",
        #         "pair":"O3-USDT",
        #         "business_type":"swap",
        #         "query_id":652123190,
        #         "match_id":28306009409,
        #         "order_id":941137865226903553,
        #         "symbol":"O3",
        #         "contract_code":"O3-USDT",
        #         "direction":"sell",
        #         "offset":"open",
        #         "trade_volume":100.000000000000000000,
        #         "trade_price":0.398500000000000000,
        #         "trade_turnover":39.850000000000000000,
        #         "trade_fee":-0.007970000000000000,
        #         "offset_profitloss":0E-18,
        #         "create_date":1644426352999,
        #         "role":"Maker",
        #         "order_source":"api",
        #         "order_id_str":"941137865226903553",
        #         "id":"28306009409-941137865226903553-1",
        #         "fee_asset":"USDT",
        #         "margin_mode":"cross",
        #         "margin_account":"USDT",
        #         "real_profit":0E-18,
        #         "trade_partition":"USDT"
        #     }
        #
        marketId = self.safe_string_2(trade, 'contract_code', 'symbol')
        market = self.safe_market(marketId, market)
        symbol = market['symbol']
        timestamp = self.safe_integer_2(trade, 'ts', 'created-at')
        timestamp = self.safe_integer_2(trade, 'created_at', 'create_date', timestamp)
        order = self.safe_string_2(trade, 'order-id', 'order_id')
        side = self.safe_string(trade, 'direction')
        type = self.safe_string(trade, 'type')
        if type is not None:
            typeParts = type.split('-')
            side = typeParts[0]
            type = typeParts[1]
        takerOrMaker = self.safe_string_lower(trade, 'role')
        priceString = self.safe_string_2(trade, 'price', 'trade_price')
        amountString = self.safe_string_2(trade, 'filled-amount', 'amount')
        amountString = self.safe_string(trade, 'trade_volume', amountString)
        costString = self.safe_string(trade, 'trade_turnover')
        fee = None
        feeCost = self.safe_string(trade, 'filled-fees')
        if feeCost is None:
            feeCost = Precise.string_neg(self.safe_string(trade, 'trade_fee'))
        feeCurrencyId = self.safe_string_2(trade, 'fee-currency', 'fee_asset')
        feeCurrency = self.safe_currency_code(feeCurrencyId)
        filledPoints = self.safe_string(trade, 'filled-points')
        if filledPoints is not None:
            if (feeCost is None) or Precise.string_equals(feeCost, '0'):
                feeDeductCurrency = self.safe_string(trade, 'fee-deduct-currency')
                if feeDeductCurrency is not None:
                    feeCost = filledPoints
                    feeCurrency = self.safe_currency_code(feeDeductCurrency)
        if feeCost is not None:
            fee = {
                'cost': feeCost,
                'currency': feeCurrency,
            }
        # htx's multi-market trade-id is a bit complex to parse accordingly.
        # - for `id` which contains hyphen, it would be the unique id, eg. xxxxxx-1, xxxxxx-2(self happens mostly for contract markets)
        # - otherwise the least priority is given to the `id` key
        id: Str = None
        safeId = self.safe_string(trade, 'id')
        if safeId is not None and safeId.find('-') >= 0:
            id = safeId
        else:
            id = self.safe_string_n(trade, ['trade_id', 'trade-id', 'id'])
        return self.safe_trade({
            'id': id,
            'info': trade,
            'order': order,
            'timestamp': timestamp,
            'datetime': self.iso8601(timestamp),
            'symbol': symbol,
            'type': type,
            'side': side,
            'takerOrMaker': takerOrMaker,
            'price': priceString,
            'amount': amountString,
            'cost': costString,
            'fee': fee,
        }, market)

    def fetch_order_trades(self, id: str, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
        """
        fetch all the trades made from a single order

        https://huobiapi.github.io/docs/spot/v1/en/#get-the-match-result-of-an-order

        :param str id: order id
        :param str symbol: unified market symbol
        :param int [since]: the earliest time in ms to fetch trades for
        :param int [limit]: the maximum number of trades to retrieve
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict[]: a list of `trade structures <https://docs.ccxt.com/#/?id=trade-structure>`
        """
        market = None
        if symbol is not None:
            market = self.market(symbol)
        marketType = None
        marketType, params = self.handle_market_type_and_params('fetchOrderTrades', market, params)
        if marketType != 'spot':
            raise NotSupported(self.id + ' fetchOrderTrades() is only supported for spot markets')
        return self.fetch_spot_order_trades(id, symbol, since, limit, params)

    def fetch_spot_order_trades(self, id: str, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
        """
 @ignore
        fetch all the trades made from a single order

        https://huobiapi.github.io/docs/spot/v1/en/#get-the-match-result-of-an-order

        :param str id: order id
        :param str symbol: unified market symbol
        :param int [since]: the earliest time in ms to fetch trades for
        :param int [limit]: the maximum number of trades to retrieve
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict[]: a list of `trade structures <https://docs.ccxt.com/#/?id=trade-structure>`
        """
        self.load_markets()
        request: dict = {
            'order-id': id,
        }
        response = self.spotPrivateGetV1OrderOrdersOrderIdMatchresults(self.extend(request, params))
        return self.parse_trades(response['data'], None, since, limit)

    def fetch_my_trades(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
        """

        https://huobiapi.github.io/docs/usdt_swap/v1/en/#isolated-get-history-match-results-via-multiple-fields-new
        https://huobiapi.github.io/docs/usdt_swap/v1/en/#cross-get-history-match-results-via-multiple-fields-new
        https://huobiapi.github.io/docs/spot/v1/en/#search-match-results

        fetch all trades made by the user
        :param str symbol: unified market symbol
        :param int [since]: the earliest time in ms to fetch trades for
        :param int [limit]: the maximum number of trades structures to retrieve
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :param int [params.until]: the latest time in ms to fetch trades for
        :param boolean [params.paginate]: default False, when True will automatically paginate by calling self endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
        :returns Trade[]: a list of `trade structures <https://docs.ccxt.com/#/?id=trade-structure>`
        """
        self.load_markets()
        paginate = False
        paginate, params = self.handle_option_and_params(params, 'fetchMyTrades', 'paginate')
        if paginate:
            return self.fetch_paginated_call_dynamic('fetchMyTrades', symbol, since, limit, params)
        market = None
        if symbol is not None:
            market = self.market(symbol)
        marketType = None
        marketType, params = self.handle_market_type_and_params('fetchMyTrades', market, params)
        request: dict = {
            # spot -----------------------------------------------------------
            # 'symbol': market['id'],
            # 'types': 'buy-market,sell-market,buy-limit,sell-limit,buy-ioc,sell-ioc,buy-limit-maker,sell-limit-maker,buy-stop-limit,sell-stop-limit',
            # 'start-time': since,  # max 48 hours within 120 days
            # 'end-time': self.milliseconds(),  # max 48 hours within 120 days
            # 'from': 'id',  # tring False N/A Search internal id to begin with if search next page, then self should be the last id(not trade-id) of last page; if search previous page, then self should be the first id(not trade-id) of last page
            # 'direct': 'next',  # next, prev
            # 'size': limit,  # default 100, max 500 The number of orders to return [1-500]
            # contracts ------------------------------------------------------
            # 'symbol': market['settleId'],  # required
            # 'trade_type': 0,  # required, 0 all, 1 open long, 2 open short, 3 close short, 4 close long, 5 liquidate long positions, 6 liquidate short positions
            # 'contract_code': market['id'],
            # 'start_time': since,  # max 48 hours within 120 days
            # 'end_time': self.milliseconds(),  # max 48 hours within 120 days
            # 'from_id': 'id',  # tring False N/A Search internal id to begin with if search next page, then self should be the last id(not trade-id) of last page; if search previous page, then self should be the first id(not trade-id) of last page
            # 'direct': 'prev',  # next, prev
            # 'size': limit,  # default 20, max 50
        }
        response = None
        if marketType == 'spot':
            if symbol is not None:
                market = self.market(symbol)
                request['symbol'] = market['id']
            if limit is not None:
                request['size'] = limit  # default 100, max 500
            if since is not None:
                request['start-time'] = since  # a date within 120 days from today
                # request['end-time'] = self.sum(since, 172800000)  # 48 hours window
            request, params = self.handle_until_option('end-time', request, params)
            response = self.spotPrivateGetV1OrderMatchresults(self.extend(request, params))
        else:
            if symbol is None:
                raise ArgumentsRequired(self.id + ' fetchMyTrades() requires a symbol argument')
            request['contract'] = market['id']
            request['trade_type'] = 0  # 0 all, 1 open long, 2 open short, 3 close short, 4 close long, 5 liquidate long positions, 6 liquidate short positions
            if since is not None:
                request['start_time'] = since  # a date within 120 days from today
                # request['end_time'] = self.sum(request['start_time'], 172800000)  # 48 hours window
            request, params = self.handle_until_option('end_time', request, params)
            if limit is not None:
                request['page_size'] = limit  # default 100, max 500
            if market['linear']:
                marginMode = None
                marginMode, params = self.handle_margin_mode_and_params('fetchMyTrades', params)
                marginMode = 'cross' if (marginMode is None) else marginMode
                if marginMode == 'isolated':
                    response = self.contractPrivatePostLinearSwapApiV3SwapMatchresultsExact(self.extend(request, params))
                elif marginMode == 'cross':
                    response = self.contractPrivatePostLinearSwapApiV3SwapCrossMatchresultsExact(self.extend(request, params))
            elif market['inverse']:
                if marketType == 'future':
                    request['symbol'] = market['settleId']
                    response = self.contractPrivatePostApiV3ContractMatchresultsExact(self.extend(request, params))
                elif marketType == 'swap':
                    response = self.contractPrivatePostSwapApiV3SwapMatchresultsExact(self.extend(request, params))
                else:
                    raise NotSupported(self.id + ' fetchMyTrades() does not support ' + marketType + ' markets')
        #
        # spot
        #
        #     {
        #         "status": "ok",
        #         "data": [
        #             {
        #                 "symbol": "polyusdt",
        #                 "fee-currency": "poly",
        #                 "source": "spot-web",
        #                 "price": "0.338",
        #                 "created-at": 1629443051839,
        #                 "role": "taker",
        #                 "order-id": 345487249132375,
        #                 "match-id": 5014,
        #                 "trade-id": 1085,
        #                 "filled-amount": "147.928994082840236",
        #                 "filled-fees": "0",
        #                 "filled-points": "0.1",
        #                 "fee-deduct-currency": "hbpoint",
        #                 "fee-deduct-state": "done",
        #                 "id": 313288753120940,
        #                 "type": "buy-market"
        #             }
        #         ]
        #     }
        #
        # contracts
        #
        #     {
        #         "status": "ok",
        #         "data": {
        #             "trades": [
        #                 {
        #                     "query_id": 2424420723,
        #                     "match_id": 113891764710,
        #                     "order_id": 773135295142658048,
        #                     "symbol": "ADA",
        #                     "contract_type": "quarter",  # swap
        #                     "business_type": "futures",  # swap
        #                     "contract_code": "ADA201225",
        #                     "direction": "buy",
        #                     "offset": "open",
        #                     "trade_volume": 1,
        #                     "trade_price": 0.092,
        #                     "trade_turnover": 10,
        #                     "trade_fee": -0.021739130434782608,
        #                     "offset_profitloss": 0,
        #                     "create_date": 1604371703183,
        #                     "role": "Maker",
        #                     "order_source": "web",
        #                     "order_id_str": "773135295142658048",
        #                     "fee_asset": "ADA",
        #                     "margin_mode": "isolated",  # cross
        #                     "margin_account": "BTC-USDT",
        #                     "real_profit": 0,
        #                     "id": "113891764710-773135295142658048-1",
        #                     "trade_partition":"USDT",
        #                 }
        #             ],
        #             "remain_size": 15,
        #             "next_id": 2424413094
        #         },
        #         "ts": 1604372202243
        #     }
        #
        trades = self.safe_value(response, 'data')
        if not isinstance(trades, list):
            trades = self.safe_value(trades, 'trades')
        return self.parse_trades(trades, market, since, limit)

    def fetch_trades(self, symbol: str, since: Int = None, limit: Int = 1000, params={}) -> List[Trade]:
        """

        https://huobiapi.github.io/docs/spot/v1/en/#get-the-most-recent-trades
        https://huobiapi.github.io/docs/dm/v1/en/#query-a-batch-of-trade-records-of-a-contract
        https://huobiapi.github.io/docs/coin_margined_swap/v1/en/#query-a-batch-of-trade-records-of-a-contract
        https://huobiapi.github.io/docs/usdt_swap/v1/en/#general-query-a-batch-of-trade-records-of-a-contract

        get the list of most recent trades for a particular symbol
        :param str symbol: unified symbol of the market to fetch trades for
        :param int [since]: timestamp in ms of the earliest trade to fetch
        :param int [limit]: the maximum amount of trades to fetch
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns Trade[]: a list of `trade structures <https://docs.ccxt.com/#/?id=public-trades>`
        """
        self.load_markets()
        market = self.market(symbol)
        request: dict = {
            # 'symbol': market['id'],  # spot, future
            # 'contract_code': market['id'],  # swap
        }
        if limit is not None:
            request['size'] = min(limit, 2000)  # max 2000
        response = None
        if market['future']:
            if market['inverse']:
                request['symbol'] = market['id']
                response = self.contractPublicGetMarketHistoryTrade(self.extend(request, params))
            elif market['linear']:
                request['contract_code'] = market['id']
                response = self.contractPublicGetLinearSwapExMarketHistoryTrade(self.extend(request, params))
        elif market['swap']:
            request['contract_code'] = market['id']
            if market['inverse']:
                response = self.contractPublicGetSwapExMarketHistoryTrade(self.extend(request, params))
            elif market['linear']:
                response = self.contractPublicGetLinearSwapExMarketHistoryTrade(self.extend(request, params))
        else:
            request['symbol'] = market['id']
            response = self.spotPublicGetMarketHistoryTrade(self.extend(request, params))
        #
        #     {
        #         "status": "ok",
        #         "ch": "market.btcusdt.trade.detail",
        #         "ts": 1583497692365,
        #         "data": [
        #             {
        #                 "id": 105005170342,
        #                 "ts": 1583497692182,
        #                 "data": [
        #                     {
        #                         "amount": 0.010411000000000000,
        #                         "trade-id": 102090736910,
        #                         "ts": 1583497692182,
        #                         "id": 10500517034273194594947,
        #                         "price": 9096.050000000000000000,
        #                         "direction": "sell"
        #                     }
        #                 ]
        #             },
        #             # ...
        #         ]
        #     }
        #
        data = self.safe_value(response, 'data', [])
        result = []
        for i in range(0, len(data)):
            trades = self.safe_value(data[i], 'data', [])
            for j in range(0, len(trades)):
                trade = self.parse_trade(trades[j], market)
                result.append(trade)
        result = self.sort_by(result, 'timestamp')
        return self.filter_by_symbol_since_limit(result, market['symbol'], since, limit)

    def parse_ohlcv(self, ohlcv, market: Market = None) -> list:
        #
        #     {
        #         "amount":1.2082,
        #         "open":0.025096,
        #         "close":0.025095,
        #         "high":0.025096,
        #         "id":1591515300,
        #         "count":6,
        #         "low":0.025095,
        #         "vol":0.0303205097
        #     }
        #
        return [
            self.safe_timestamp(ohlcv, 'id'),
            self.safe_number(ohlcv, 'open'),
            self.safe_number(ohlcv, 'high'),
            self.safe_number(ohlcv, 'low'),
            self.safe_number(ohlcv, 'close'),
            self.safe_number(ohlcv, 'amount'),
        ]

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

        https://huobiapi.github.io/docs/spot/v1/en/#get-klines-candles
        https://huobiapi.github.io/docs/dm/v1/en/#get-kline-data
        https://huobiapi.github.io/docs/coin_margined_swap/v1/en/#get-kline-data
        https://huobiapi.github.io/docs/usdt_swap/v1/en/#general-get-kline-data

        :param str symbol: unified symbol of the market to fetch OHLCV data for
        :param str timeframe: the length of time each candle represents
        :param int [since]: timestamp in ms of the earliest candle to fetch
        :param int [limit]: the maximum amount of candles to fetch
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :param boolean [params.paginate]: default False, when True will automatically paginate by calling self endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
        :param str [params.useHistoricalEndpointForSpot]: True/false - whether use the historical candles endpoint for spot markets or default klines endpoint
        :returns int[][]: A list of candles ordered, open, high, low, close, volume
        """
        self.load_markets()
        paginate = False
        paginate, params = self.handle_option_and_params(params, 'fetchOHLCV', 'paginate')
        if paginate:
            return self.fetch_paginated_call_deterministic('fetchOHLCV', symbol, since, limit, timeframe, params, 1000)
        market = self.market(symbol)
        request: dict = {
            'period': self.safe_string(self.timeframes, timeframe, timeframe),
            # 'symbol': market['id'],  # spot, future
            # 'contract_code': market['id'],  # swap
            # 'size': 1000,  # max 1000 for spot, 2000 for contracts
            # 'from': int((since / str(1000))), spot only
            # 'to': self.seconds(), spot only
        }
        priceType = self.safe_string_n(params, ['priceType', 'price'])
        params = self.omit(params, ['priceType', 'price'])
        until = None
        until, params = self.handle_param_integer(params, 'until')
        untilSeconds = self.parse_to_int(until / 1000) if (until is not None) else None
        if market['contract']:
            if limit is not None:
                request['size'] = min(limit, 2000)  # when using limit: from & to are ignored
                # https://huobiapi.github.io/docs/usdt_swap/v1/en/#general-get-kline-data
            else:
                limit = 2000  # only used for from/to calculation
            if priceType is None:
                duration = self.parse_timeframe(timeframe)
                calcualtedEnd = None
                if since is None:
                    now = self.seconds()
                    request['from'] = now - duration * (limit - 1)
                    calcualtedEnd = now
                else:
                    start = self.parse_to_int(since / 1000)
                    request['from'] = start
                    calcualtedEnd = self.sum(start, duration * (limit - 1))
                request['to'] = untilSeconds if (untilSeconds is not None) else calcualtedEnd
        response = None
        if market['future']:
            if market['inverse']:
                request['symbol'] = market['id']
                if priceType == 'mark':
                    response = self.contractPublicGetIndexMarketHistoryMarkPriceKline(self.extend(request, params))
                elif priceType == 'index':
                    response = self.contractPublicGetIndexMarketHistoryIndex(self.extend(request, params))
                elif priceType == 'premiumIndex':
                    raise BadRequest(self.id + ' ' + market['type'] + ' has no api endpoint for ' + priceType + ' kline data')
                else:
                    response = self.contractPublicGetMarketHistoryKline(self.extend(request, params))
            elif market['linear']:
                request['contract_code'] = market['id']
                if priceType == 'mark':
                    response = self.contractPublicGetIndexMarketHistoryLinearSwapMarkPriceKline(self.extend(request, params))
                elif priceType == 'index':
                    raise BadRequest(self.id + ' ' + market['type'] + ' has no api endpoint for ' + priceType + ' kline data')
                elif priceType == 'premiumIndex':
                    response = self.contractPublicGetIndexMarketHistoryLinearSwapPremiumIndexKline(self.extend(request, params))
                else:
                    response = self.contractPublicGetLinearSwapExMarketHistoryKline(self.extend(request, params))
        elif market['swap']:
            request['contract_code'] = market['id']
            if market['inverse']:
                if priceType == 'mark':
                    response = self.contractPublicGetIndexMarketHistorySwapMarkPriceKline(self.extend(request, params))
                elif priceType == 'index':
                    raise BadRequest(self.id + ' ' + market['type'] + ' has no api endpoint for ' + priceType + ' kline data')
                elif priceType == 'premiumIndex':
                    response = self.contractPublicGetIndexMarketHistorySwapPremiumIndexKline(self.extend(request, params))
                else:
                    response = self.contractPublicGetSwapExMarketHistoryKline(self.extend(request, params))
            elif market['linear']:
                if priceType == 'mark':
                    response = self.contractPublicGetIndexMarketHistoryLinearSwapMarkPriceKline(self.extend(request, params))
                elif priceType == 'index':
                    raise BadRequest(self.id + ' ' + market['type'] + ' has no api endpoint for ' + priceType + ' kline data')
                elif priceType == 'premiumIndex':
                    response = self.contractPublicGetIndexMarketHistoryLinearSwapPremiumIndexKline(self.extend(request, params))
                else:
                    response = self.contractPublicGetLinearSwapExMarketHistoryKline(self.extend(request, params))
        else:
            request['symbol'] = market['id']
            useHistorical = None
            useHistorical, params = self.handle_option_and_params(params, 'fetchOHLCV', 'useHistoricalEndpointForSpot', True)
            if not useHistorical:
                if limit is not None:
                    request['size'] = min(limit, 2000)  # max 2000
                response = self.spotPublicGetMarketHistoryKline(self.extend(request, params))
            else:
                # "from & to" only available for the self endpoint
                if since is not None:
                    request['from'] = self.parse_to_int(since / 1000)
                if untilSeconds is not None:
                    request['to'] = untilSeconds
                if limit is not None:
                    request['size'] = min(1000, limit)  # max 1000, otherwise default returns 150
                response = self.spotPublicGetMarketHistoryCandles(self.extend(request, params))
        #
        #     {
        #         "status":"ok",
        #         "ch":"market.ethbtc.kline.1min",
        #         "ts":1591515374371,
        #         "data":[
        #             {"amount":0.0,"open":0.025095,"close":0.025095,"high":0.025095,"id":1591515360,"count":0,"low":0.025095,"vol":0.0},
        #             {"amount":1.2082,"open":0.025096,"close":0.025095,"high":0.025096,"id":1591515300,"count":6,"low":0.025095,"vol":0.0303205097},
        #             {"amount":0.0648,"open":0.025096,"close":0.025096,"high":0.025096,"id":1591515240,"count":2,"low":0.025096,"vol":0.0016262208},
        #         ]
        #     }
        #
        data = self.safe_list(response, 'data', [])
        return self.parse_ohlcvs(data, market, timeframe, since, limit)

    def fetch_accounts(self, params={}) -> List[Account]:
        """
        fetch all the accounts associated with a profile

        https://huobiapi.github.io/docs/spot/v1/en/#get-all-accounts-of-the-current-user

        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: a dictionary of `account structures <https://docs.ccxt.com/#/?id=account-structure>` indexed by the account type
        """
        self.load_markets()
        response = self.spotPrivateGetV1AccountAccounts(params)
        #
        #     {
        #         "status":"ok",
        #         "data":[
        #             {"id":5202591,"type":"point","subtype":"","state":"working"},
        #             {"id":1528640,"type":"spot","subtype":"","state":"working"},
        #         ]
        #     }
        #
        data = self.safe_value(response, 'data')
        return self.parse_accounts(data)

    def parse_account(self, account):
        #
        #     {
        #         "id": 5202591,
        #         "type": "point",   # spot, margin, otc, point, super-margin, investment, borrow, grid-trading, deposit-earning, otc-options
        #         "subtype": "",     # The corresponding trading symbol(currency pair) the isolated margin is based on, e.g. btcusdt
        #         "state": "working"  # working, lock
        #     }
        #
        typeId = self.safe_string(account, 'type')
        accountsById = self.safe_value(self.options, 'accountsById', {})
        type = self.safe_value(accountsById, typeId, typeId)
        return {
            'info': account,
            'id': self.safe_string(account, 'id'),
            'type': type,
            'code': None,
        }

    def fetch_account_id_by_type(self, type: str, marginMode: Str = None, symbol: Str = None, params={}):
        """
        fetch all the accounts by a type and marginModeassociated with a profile

        https://huobiapi.github.io/docs/spot/v1/en/#get-all-accounts-of-the-current-user

        :param str type: 'spot', 'swap' or 'future
        :param str [marginMode]: 'cross' or 'isolated'
        :param str [symbol]: unified ccxt market symbol
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: a dictionary of `account structures <https://docs.ccxt.com/#/?id=account-structure>` indexed by the account type
        """
        accounts = self.load_accounts()
        accountId = self.safe_value_2(params, 'accountId', 'account-id')
        if accountId is not None:
            return accountId
        if type == 'spot':
            if marginMode == 'cross':
                type = 'super-margin'
            elif marginMode == 'isolated':
                type = 'margin'
        marketId = None
        if symbol is not None:
            marketId = self.market_id(symbol)
        for i in range(0, len(accounts)):
            account = accounts[i]
            info = self.safe_value(account, 'info')
            subtype = self.safe_string(info, 'subtype', None)
            typeFromAccount = self.safe_string(account, 'type')
            if type == 'margin':
                if subtype == marketId:
                    return self.safe_string(account, 'id')
            elif type == typeFromAccount:
                return self.safe_string(account, 'id')
        defaultAccount = self.safe_value(accounts, 0, {})
        return self.safe_string(defaultAccount, 'id')

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

        https://huobiapi.github.io/docs/spot/v1/en/#apiv2-currency-amp-chains

        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: an associative dictionary of currencies
        """
        response = self.spotPublicGetV2ReferenceCurrencies(params)
        #
        #    {
        #        "code": 200,
        #        "data": [
        #            {
        #                "currency": "sxp",
        #                "assetType": "1",
        #                "chains": [
        #                    {
        #                        "chain": "sxp",
        #                        "displayName": "ERC20",
        #                        "baseChain": "ETH",
        #                        "baseChainProtocol": "ERC20",
        #                        "isDynamic": True,
        #                        "numOfConfirmations": "12",
        #                        "numOfFastConfirmations": "12",
        #                        "depositStatus": "allowed",
        #                        "minDepositAmt": "0.23",
        #                        "withdrawStatus": "allowed",
        #                        "minWithdrawAmt": "0.23",
        #                        "withdrawPrecision": "8",
        #                        "maxWithdrawAmt": "227000.000000000000000000",
        #                        "withdrawQuotaPerDay": "227000.000000000000000000",
        #                        "withdrawQuotaPerYear": null,
        #                        "withdrawQuotaTotal": null,
        #                        "withdrawFeeType": "fixed",
        #                        "transactFeeWithdraw": "11.1654",
        #                        "addrWithTag": False,
        #                        "addrDepositTag": False
        #                    }
        #                ],
        #                "instStatus": "normal"
        #            }
        #        ]
        #    }
        #
        data = self.safe_list(response, 'data', [])
        result: dict = {}
        self.options['networkChainIdsByNames'] = {}
        self.options['networkNamesByChainIds'] = {}
        for i in range(0, len(data)):
            entry = data[i]
            currencyId = self.safe_string(entry, 'currency')
            code = self.safe_currency_code(currencyId)
            assetType = self.safe_string(entry, 'assetType')
            type = assetType == 'crypto' if '1' else 'fiat'
            self.options['networkChainIdsByNames'][code] = {}
            chains = self.safe_list(entry, 'chains', [])
            networks: dict = {}
            for j in range(0, len(chains)):
                chainEntry = chains[j]
                uniqueChainId = self.safe_string(chainEntry, 'chain')  # i.e. usdterc20, trc20usdt ...
                title = self.safe_string_2(chainEntry, 'baseChain', 'displayName')  # baseChain and baseChainProtocol are together existent or inexistent in entries, but baseChain is preferred. when they are both inexistent, then we use generic displayName
                self.options['networkChainIdsByNames'][code][title] = uniqueChainId
                self.options['networkNamesByChainIds'][uniqueChainId] = title
                networkCode = self.network_id_to_code(uniqueChainId)
                networks[networkCode] = {
                    'info': chainEntry,
                    'id': uniqueChainId,
                    'network': networkCode,
                    'limits': {
                        'deposit': {
                            'min': self.safe_number(chainEntry, 'minDepositAmt'),
                            'max': None,
                        },
                        'withdraw': {
                            'min': self.safe_number(chainEntry, 'minWithdrawAmt'),
                            'max': self.safe_number(chainEntry, 'maxWithdrawAmt'),
                        },
                    },
                    'active': None,
                    'deposit': self.safe_string(chainEntry, 'depositStatus') == 'allowed',
                    'withdraw': self.safe_string(chainEntry, 'withdrawStatus') == 'allowed',
                    'fee': self.safe_number(chainEntry, 'transactFeeWithdraw'),
                    'precision': self.parse_number(self.parse_precision(self.safe_string(chainEntry, 'withdrawPrecision'))),
                }
            result[code] = self.safe_currency_structure({
                'info': entry,
                'code': code,
                'id': currencyId,
                'active': self.safe_string(entry, 'instStatus') == 'normal',
                'deposit': None,
                'withdraw': None,
                'fee': None,
                'name': None,
                'type': type,
                'limits': {
                    'amount': {
                        'min': None,
                        'max': None,
                    },
                    'withdraw': {
                        'min': None,
                        'max': None,
                    },
                    'deposit': {
                        'min': None,
                        'max': None,
                    },
                },
                'precision': None,
                'networks': networks,
            })
        return result

    def network_id_to_code(self, networkId: Str = None, currencyCode: Str = None):
        # here network-id is provided pair of currency & chain(i.e. trc20usdt)
        keys = list(self.options['networkNamesByChainIds'].keys())
        keysLength = len(keys)
        if keysLength == 0:
            raise ExchangeError(self.id + ' networkIdToCode() - markets need to be loaded at first')
        networkTitle = self.safe_value(self.options['networkNamesByChainIds'], networkId, networkId)
        return super(htx, self).network_id_to_code(networkTitle)

    def network_code_to_id(self, networkCode: str, currencyCode: Str = None):
        if currencyCode is None:
            raise ArgumentsRequired(self.id + ' networkCodeToId() requires a currencyCode argument')
        keys = list(self.options['networkChainIdsByNames'].keys())
        keysLength = len(keys)
        if keysLength == 0:
            raise ExchangeError(self.id + ' networkCodeToId() - markets need to be loaded at first')
        uniqueNetworkIds = self.safe_value(self.options['networkChainIdsByNames'], currencyCode, {})
        if networkCode in uniqueNetworkIds:
            return uniqueNetworkIds[networkCode]
        else:
            networkTitle = super(htx, self).network_code_to_id(networkCode)
            return self.safe_value(uniqueNetworkIds, networkTitle, networkTitle)

    def fetch_balance(self, params={}) -> Balances:
        """

        https://huobiapi.github.io/docs/spot/v1/en/#get-account-balance-of-a-specific-account
        https://www.htx.com/en-us/opend/newApiPages/?id=7ec4b429-7773-11ed-9966-0242ac110003
        https://www.htx.com/en-us/opend/newApiPages/?id=10000074-77b7-11ed-9966-0242ac110003
        https://huobiapi.github.io/docs/dm/v1/en/#query-asset-valuation
        https://huobiapi.github.io/docs/coin_margined_swap/v1/en/#query-user-s-account-information
        https://huobiapi.github.io/docs/usdt_swap/v1/en/#isolated-query-user-s-account-information
        https://huobiapi.github.io/docs/usdt_swap/v1/en/#cross-query-user-39-s-account-information

        query for balance and get the amount of funds available for trading or funds locked in orders
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :param bool [params.unified]: provide self parameter if you have a recent account with unified cross+isolated margin account
        :returns dict: a `balance structure <https://docs.ccxt.com/#/?id=balance-structure>`
        """
        self.load_markets()
        type = None
        type, params = self.handle_market_type_and_params('fetchBalance', None, params)
        options = self.safe_value(self.options, 'fetchBalance', {})
        isUnifiedAccount = self.safe_value_2(params, 'isUnifiedAccount', 'unified', False)
        params = self.omit(params, ['isUnifiedAccount', 'unified'])
        request: dict = {}
        spot = (type == 'spot')
        future = (type == 'future')
        defaultSubType = self.safe_string_2(self.options, 'defaultSubType', 'subType', 'linear')
        subType = self.safe_string_2(options, 'defaultSubType', 'subType', defaultSubType)
        subType = self.safe_string_2(params, 'defaultSubType', 'subType', subType)
        inverse = (subType == 'inverse')
        linear = (subType == 'linear')
        marginMode = None
        marginMode, params = self.handle_margin_mode_and_params('fetchBalance', params)
        params = self.omit(params, ['defaultSubType', 'subType'])
        isolated = (marginMode == 'isolated')
        cross = (marginMode == 'cross')
        margin = (type == 'margin') or (spot and (cross or isolated))
        response = None
        if spot or margin:
            if margin:
                if isolated:
                    response = self.spotPrivateGetV1MarginAccountsBalance(self.extend(request, params))
                else:
                    response = self.spotPrivateGetV1CrossMarginAccountsBalance(self.extend(request, params))
            else:
                self.load_accounts()
                accountId = self.fetch_account_id_by_type(type, None, None, params)
                request['account-id'] = accountId
                response = self.spotPrivateGetV1AccountAccountsAccountIdBalance(self.extend(request, params))
        elif isUnifiedAccount:
            response = self.contractPrivateGetLinearSwapApiV3UnifiedAccountInfo(self.extend(request, params))
        elif linear:
            if isolated:
                response = self.contractPrivatePostLinearSwapApiV1SwapAccountInfo(self.extend(request, params))
            else:
                response = self.contractPrivatePostLinearSwapApiV1SwapCrossAccountInfo(self.extend(request, params))
        elif inverse:
            if future:
                response = self.contractPrivatePostApiV1ContractAccountInfo(self.extend(request, params))
            else:
                response = self.contractPrivatePostSwapApiV1SwapAccountInfo(self.extend(request, params))
        #
        # spot
        #
        #     {
        #         "status": "ok",
        #         "data": {
        #             "id": 1528640,
        #             "type": "spot",
        #             "state": "working",
        #             "list": [
        #                 {"currency": "lun", "type": "trade", "balance": "0", "seq-num": "0"},
        #                 {"currency": "lun", "type": "frozen", "balance": "0", "seq-num": "0"},
        #                 {"currency": "ht", "type": "frozen", "balance": "0", "seq-num": "145"},
        #             ]
        #         },
        #         "ts":1637644827566
        #     }
        #
        # cross margin
        #
        #     {
        #         "status": "ok",
        #         "data": {
        #             "id": 51015302,
        #             "type": "cross-margin",
        #             "state": "working",
        #             "risk-rate": "2",
        #             "acct-balance-sum": "100",
        #             "debt-balance-sum": "0",
        #             "list": [
        #                 {"currency": "usdt", "type": "trade", "balance": "100"},
        #                 {"currency": "usdt", "type": "frozen", "balance": "0"},
        #                 {"currency": "usdt", "type": "loan-available", "balance": "200"},
        #                 {"currency": "usdt", "type": "transfer-out-available", "balance": "-1"},
        #                 {"currency": "ht", "type": "loan-available", "balance": "36.60724091"},
        #                 {"currency": "ht", "type": "transfer-out-available", "balance": "-1"},
        #                 {"currency": "btc", "type": "trade", "balance": "1168.533000000000000000"},
        #                 {"currency": "btc", "type": "frozen", "balance": "0.000000000000000000"},
        #                 {"currency": "btc", "type": "loan", "balance": "-2.433000000000000000"},
        #                 {"currency": "btc", "type": "interest", "balance": "-0.000533000000000000"},
        #                 {"currency": "btc", "type": "transfer-out-available", "balance": "1163.872174670000000000"},
        #                 {"currency": "btc", "type": "loan-available", "balance": "8161.876538350676000000"}
        #             ]
        #         },
        #         "code": 200
        #     }
        #
        # isolated margin
        #
        #     {
        #         "data": [
        #             {
        #                 "id": 18264,
        #                 "type": "margin",
        #                 "state": "working",
        #                 "symbol": "btcusdt",
        #                 "fl-price": "0",
        #                 "fl-type": "safe",
        #                 "risk-rate": "475.952571086994250554",
        #                 "list": [
        #                     {"currency": "btc","type": "trade","balance": "1168.533000000000000000"},
        #                     {"currency": "btc","type": "frozen","balance": "0.000000000000000000"},
        #                     {"currency": "btc","type": "loan","balance": "-2.433000000000000000"},
        #                     {"currency": "btc","type": "interest","balance": "-0.000533000000000000"},
        #                     {"currency": "btc","type": "transfer-out-available", "balance": "1163.872174670000000000"},
        #                     {"currency": "btc","type": "loan-available", "balance": "8161.876538350676000000"}
        #                 ]
        #             }
        #         ]
        #     }
        #
        # future, swap isolated
        #
        #     {
        #         "status": "ok",
        #         "data": [
        #             {
        #                 "symbol": "BTC",
        #                 "margin_balance": 0,
        #                 "margin_position": 0E-18,
        #                 "margin_frozen": 0,
        #                 "margin_available": 0E-18,
        #                 "profit_real": 0,
        #                 "profit_unreal": 0,
        #                 "risk_rate": null,
        #                 "withdraw_available": 0,
        #                 "liquidation_price": null,
        #                 "lever_rate": 5,
        #                 "adjust_factor": 0.025000000000000000,
        #                 "margin_static": 0,
        #                 "is_debit": 0,  # future only
        #                 "contract_code": "BTC-USD",  # swap only
        #                 "margin_asset": "USDT",  # linear only
        #                 "margin_mode": "isolated",  # linear only
        #                 "margin_account": "BTC-USDT"  # linear only
        #                 "transfer_profit_ratio": null  # inverse only
        #             },
        #         ],
        #         "ts": 1637644827566
        #     }
        #
        # linear cross futures and linear cross swap
        #
        #     {
        #         "status": "ok",
        #         "data": [
        #             {
        #                 "futures_contract_detail": [
        #                     {
        #                         "symbol": "ETH",
        #                         "contract_code": "ETH-USDT-220325",
        #                         "margin_position": 0,
        #                         "margin_frozen": 0,
        #                         "margin_available": 200.000000000000000000,
        #                         "profit_unreal": 0E-18,
        #                         "liquidation_price": null,
        #                         "lever_rate": 5,
        #                         "adjust_factor": 0.060000000000000000,
        #                         "contract_type": "quarter",
        #                         "pair": "ETH-USDT",
        #                         "business_type": "futures"
        #                     },
        #                 ],
        #                 "margin_mode": "cross",
        #                 "margin_account": "USDT",
        #                 "margin_asset": "USDT",
        #                 "margin_balance": 49.874186030200000000,
        #                 "money_in": 50,
        #                 "money_out": 0,
        #                 "margin_static": 49.872786030200000000,
        #                 "margin_position": 6.180000000000000000,
        #                 "margin_frozen": 6.000000000000000000,
        #                 "profit_unreal": 0.001400000000000000,
        #                 "withdraw_available": 37.6927860302,
        #                 "risk_rate": 271.984050521072796934,
        #                 "new_risk_rate": 0.001858676950514399,
        #                 "contract_detail": [
        #                     {
        #                         "symbol": "MANA",
        #                         "contract_code": "MANA-USDT",
        #                         "margin_position": 0,
        #                         "margin_frozen": 0,
        #                         "margin_available": 200.000000000000000000,
        #                         "profit_unreal": 0E-18,
        #                         "liquidation_price": null,
        #                         "lever_rate": 5,
        #                         "adjust_factor": 0.100000000000000000,
        #                         "contract_type": "swap",
        #                         "pair": "MANA-USDT",
        #                         "business_type": "swap"
        #                     },
        #                 ]
        #             }
        #         ],
        #         "ts": 1640915104870
        #     }
        #
        # TODO add balance parsing for linear swap
        #
        result: dict = {'info': response}
        data = self.safe_value(response, 'data')
        if spot or margin:
            if isolated:
                for i in range(0, len(data)):
                    entry = data[i]
                    symbol = self.safe_symbol(self.safe_string(entry, 'symbol'))
                    balances = self.safe_value(entry, 'list')
                    subResult: dict = {}
                    for j in range(0, len(balances)):
                        balance = balances[j]
                        currencyId = self.safe_string(balance, 'currency')
                        code = self.safe_currency_code(currencyId)
                        subResult[code] = self.parse_margin_balance_helper(balance, code, subResult)
                    result[symbol] = self.safe_balance(subResult)
            else:
                balances = self.safe_value(data, 'list', [])
                for i in range(0, len(balances)):
                    balance = balances[i]
                    currencyId = self.safe_string(balance, 'currency')
                    code = self.safe_currency_code(currencyId)
                    result[code] = self.parse_margin_balance_helper(balance, code, result)
                result = self.safe_balance(result)
        elif isUnifiedAccount:
            for i in range(0, len(data)):
                entry = data[i]
                marginAsset = self.safe_string(entry, 'margin_asset')
                currencyCode = self.safe_currency_code(marginAsset)
                if isolated:
                    isolated_swap = self.safe_value(entry, 'isolated_swap', {})
                    for j in range(0, len(isolated_swap)):
                        balance = isolated_swap[j]
                        marketId = self.safe_string(balance, 'contract_code')
                        subBalance: dict = {
                            'code': currencyCode,
                            'free': self.safe_number(balance, 'margin_available'),
                        }
                        symbol = self.safe_symbol(marketId)
                        result[symbol] = subBalance
                        result = self.safe_balance(result)
                else:
                    account = self.account()
                    account['free'] = self.safe_string(entry, 'margin_static')
                    account['used'] = self.safe_string(entry, 'margin_frozen')
                    result[currencyCode] = account
                    result = self.safe_balance(result)
        elif linear:
            first = self.safe_value(data, 0, {})
            if isolated:
                for i in range(0, len(data)):
                    balance = data[i]
                    marketId = self.safe_string_2(balance, 'contract_code', 'margin_account')
                    market = self.safe_market(marketId)
                    currencyId = self.safe_string(balance, 'margin_asset')
                    currency = self.safe_currency(currencyId)
                    code = self.safe_string(market, 'settle', currency['code'])
                    # the exchange outputs positions for delisted markets
                    # https://www.huobi.com/support/en-us/detail/74882968522337
                    # we skip it if the market was delisted
                    if code is not None:
                        account = self.account()
                        account['free'] = self.safe_string(balance, 'margin_balance')
                        account['used'] = self.safe_string(balance, 'margin_frozen')
                        accountsByCode: dict = {}
                        accountsByCode[code] = account
                        symbol = market['symbol']
                        result[symbol] = self.safe_balance(accountsByCode)
            else:
                account = self.account()
                account['free'] = self.safe_string(first, 'withdraw_available')
                account['total'] = self.safe_string(first, 'margin_balance')
                currencyId = self.safe_string_2(first, 'margin_asset', 'symbol')
                code = self.safe_currency_code(currencyId)
                result[code] = account
                result = self.safe_balance(result)
        elif inverse:
            for i in range(0, len(data)):
                balance = data[i]
                currencyId = self.safe_string(balance, 'symbol')
                code = self.safe_currency_code(currencyId)
                account = self.account()
                account['free'] = self.safe_string(balance, 'margin_available')
                account['used'] = self.safe_string(balance, 'margin_frozen')
                result[code] = account
            result = self.safe_balance(result)
        return result

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

        https://huobiapi.github.io/docs/spot/v1/en/#get-the-order-detail-of-an-order-based-on-client-order-id
        https://huobiapi.github.io/docs/spot/v1/en/#get-the-order-detail-of-an-order
        https://huobiapi.github.io/docs/usdt_swap/v1/en/#isolated-get-information-of-an-order
        https://huobiapi.github.io/docs/usdt_swap/v1/en/#cross-get-information-of-order
        https://huobiapi.github.io/docs/dm/v1/en/#get-information-of-an-order
        https://huobiapi.github.io/docs/coin_margined_swap/v1/en/#get-information-of-an-order

        :param str id: order id
        :param str symbol: unified symbol of the market the order was made in
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
        """
        self.load_markets()
        market = None
        if symbol is not None:
            market = self.market(symbol)
        marketType = None
        marketType, params = self.handle_market_type_and_params('fetchOrder', market, params)
        request: dict = {
            # spot -----------------------------------------------------------
            # 'order-id': 'id',
            # 'symbol': market['id'],
            # 'client-order-id': clientOrderId,
            # 'clientOrderId': clientOrderId,
            # contracts ------------------------------------------------------
            # 'order_id': id,
            # 'client_order_id': clientOrderId,
            # 'contract_code': market['id'],
            # 'pair': 'BTC-USDT',
            # 'contract_type': 'this_week',  # swap, self_week, next_week, quarter, next_ quarter
        }
        response = None
        if marketType == 'spot':
            clientOrderId = self.safe_string(params, 'clientOrderId')
            if clientOrderId is not None:
                # will be filled below in self.extend()
                # they expect clientOrderId instead of client-order-id
                # request['clientOrderId'] = clientOrderId
                response = self.spotPrivateGetV1OrderOrdersGetClientOrder(self.extend(request, params))
            else:
                request['order-id'] = id
                response = self.spotPrivateGetV1OrderOrdersOrderId(self.extend(request, params))
        else:
            if symbol is None:
                raise ArgumentsRequired(self.id + ' fetchOrder() requires a symbol argument')
            clientOrderId = self.safe_string_2(params, 'client_order_id', 'clientOrderId')
            if clientOrderId is None:
                request['order_id'] = id
            else:
                request['client_order_id'] = clientOrderId
                params = self.omit(params, ['client_order_id', 'clientOrderId'])
            request['contract_code'] = market['id']
            if market['linear']:
                marginMode = None
                marginMode, params = self.handle_margin_mode_and_params('fetchOrder', params)
                marginMode = 'cross' if (marginMode is None) else marginMode
                if marginMode == 'isolated':
                    response = self.contractPrivatePostLinearSwapApiV1SwapOrderInfo(self.extend(request, params))
                elif marginMode == 'cross':
                    response = self.contractPrivatePostLinearSwapApiV1SwapCrossOrderInfo(self.extend(request, params))
            elif market['inverse']:
                if marketType == 'future':
                    request['symbol'] = market['settleId']
                    response = self.contractPrivatePostApiV1ContractOrderInfo(self.extend(request, params))
                elif marketType == 'swap':
                    response = self.contractPrivatePostSwapApiV1SwapOrderInfo(self.extend(request, params))
                else:
                    raise NotSupported(self.id + ' fetchOrder() does not support ' + marketType + ' markets')
        #
        # spot
        #
        #     {
        #         "status":"ok",
        #         "data":{
        #             "id":438398393065481,
        #             "symbol":"ethusdt",
        #             "account-id":1528640,
        #             "client-order-id":"AA03022abc2163433e-006b-480e-9ad1-d4781478c5e7",
        #             "amount":"0.100000000000000000",
        #             "price":"3000.000000000000000000",
        #             "created-at":1640549994642,
        #             "type":"buy-limit",
        #             "field-amount":"0.0",
        #             "field-cash-amount":"0.0",
        #             "field-fees":"0.0",
        #             "finished-at":0,
        #             "source":"spot-api",
        #             "state":"submitted",
        #             "canceled-at":0
        #         }
        #     }
        #
        # linear swap cross margin
        #
        #     {
        #         "status":"ok",
        #         "data":[
        #             {
        #                 "business_type":"swap",
        #                 "contract_type":"swap",
        #                 "pair":"BTC-USDT",
        #                 "symbol":"BTC",
        #                 "contract_code":"BTC-USDT",
        #                 "volume":1,
        #                 "price":3000,
        #                 "order_price_type":"limit",
        #                 "order_type":1,
        #                 "direction":"buy",
        #                 "offset":"open",
        #                 "lever_rate":1,
        #                 "order_id":924912513206878210,
        #                 "client_order_id":null,
        #                 "created_at":1640557927189,
        #                 "trade_volume":0,
        #                 "trade_turnover":0,
        #                 "fee":0,
        #                 "trade_avg_price":null,
        #                 "margin_frozen":3.000000000000000000,
        #                 "profit":0,
        #                 "status":3,
        #                 "order_source":"api",
        #                 "order_id_str":"924912513206878210",
        #                 "fee_asset":"USDT",
        #                 "liquidation_type":"0",
        #                 "canceled_at":0,
        #                 "margin_asset":"USDT",
        #                 "margin_account":"USDT",
        #                 "margin_mode":"cross",
        #                 "is_tpsl":0,
        #                 "real_profit":0
        #             }
        #         ],
        #         "ts":1640557982556
        #     }
        #
        # linear swap isolated margin detail
        #
        #     {
        #         "status": "ok",
        #         "data": {
        #             "symbol": "BTC",
        #             "contract_code": "BTC-USDT",
        #             "instrument_price": 0,
        #             "final_interest": 0,
        #             "adjust_value": 0,
        #             "lever_rate": 10,
        #             "direction": "sell",
        #             "offset": "open",
        #             "volume": 1.000000000000000000,
        #             "price": 13059.800000000000000000,
        #             "created_at": 1603703614712,
        #             "canceled_at": 0,
        #             "order_source": "api",
        #             "order_price_type": "opponent",
        #             "margin_frozen": 0,
        #             "profit": 0,
        #             "trades": [
        #                 {
        #                     "trade_id": 131560927,
        #                     "trade_price": 13059.800000000000000000,
        #                     "trade_volume": 1.000000000000000000,
        #                     "trade_turnover": 13.059800000000000000,
        #                     "trade_fee": -0.005223920000000000,
        #                     "created_at": 1603703614715,
        #                     "role": "taker",
        #                     "fee_asset": "USDT",
        #                     "profit": 0,
        #                     "real_profit": 0,
        #                     "id": "131560927-770334322963152896-1"
        #                 }
        #             ],
        #             "total_page": 1,
        #             "current_page": 1,
        #             "total_size": 1,
        #             "liquidation_type": "0",
        #             "fee_asset": "USDT",
        #             "fee": -0.005223920000000000,
        #             "order_id": 770334322963152896,
        #             "order_id_str": "770334322963152896",
        #             "client_order_id": 57012021045,
        #             "order_type": "1",
        #             "status": 6,
        #             "trade_avg_price": 13059.800000000000000000,
        #             "trade_turnover": 13.059800000000000000,
        #             "trade_volume": 1.000000000000000000,
        #             "margin_asset": "USDT",
        #             "margin_mode": "isolated",
        #             "margin_account": "BTC-USDT",
        #             "real_profit": 0,
        #             "is_tpsl": 0
        #         },
        #         "ts": 1603703678477
        #     }
        order = self.safe_value(response, 'data')
        if isinstance(order, list):
            order = self.safe_value(order, 0)
        return self.parse_order(order)

    def parse_margin_balance_helper(self, balance, code, result):
        account = None
        if code in result:
            account = result[code]
        else:
            account = self.account()
        if balance['type'] == 'trade':
            account['free'] = self.safe_string(balance, 'balance')
        if balance['type'] == 'frozen':
            account['used'] = self.safe_string(balance, 'balance')
        return account

    def fetch_spot_orders_by_states(self, states, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
        method = self.safe_string(self.options, 'fetchOrdersByStatesMethod', 'spot_private_get_v1_order_orders')  # spot_private_get_v1_order_history
        if method == 'spot_private_get_v1_order_orders':
            if symbol is None:
                raise ArgumentsRequired(self.id + ' fetchOrders() requires a symbol argument')
        self.load_markets()
        market = None
        request: dict = {
            # spot_private_get_v1_order_orders GET /v1/order/orders ----------
            # 'symbol': market['id'],  # required
            # 'types': 'buy-market,sell-market,buy-limit,sell-limit,buy-ioc,sell-ioc,buy-stop-limit,sell-stop-limit,buy-limit-fok,sell-limit-fok,buy-stop-limit-fok,sell-stop-limit-fok',
            # 'start-time': since,  # max window of 48h within a range of 180 days, within past 2 hours for cancelled orders
            # 'end-time': self.milliseconds(),
            'states': states,  # filled, partial-canceled, canceled
            # 'from': order['id'],
            # 'direct': 'next',  # next, prev, used with from
            # 'size': 100,  # max 100
            # spot_private_get_v1_order_history GET /v1/order/history --------
            # 'symbol': market['id'],  # optional
            # 'start-time': since,  # max window of 48h within a range of 180 days, within past 2 hours for cancelled orders
            # 'end-time': self.milliseconds(),
            # 'direct': 'next',  # next, prev, used with from
            # 'size': 100,  # max 100
        }
        if symbol is not None:
            market = self.market(symbol)
            request['symbol'] = market['id']
        if since is not None:
            request['start-time'] = since  # a window of 48 hours within 180 days
            request['end-time'] = self.sum(since, 48 * 60 * 60 * 1000)
        request, params = self.handle_until_option('end-time', request, params)
        if limit is not None:
            request['size'] = limit
        response = None
        if method == 'spot_private_get_v1_order_orders':
            response = self.spotPrivateGetV1OrderOrders(self.extend(request, params))
        else:
            response = self.spotPrivateGetV1OrderHistory(self.extend(request, params))
        #
        # spot_private_get_v1_order_orders GET /v1/order/orders
        #
        #     {
        #         "status": "ok",
        #         "data": [
        #             {
        #                 "id": 13997833014,
        #                 "symbol": "ethbtc",
        #                 "account-id": 3398321,
        #                 "client-order-id": "23456",
        #                 "amount": "0.045000000000000000",
        #                 "price": "0.034014000000000000",
        #                 "created-at": 1545836976871,
        #                 "type": "sell-limit",
        #                 "field-amount": "0.045000000000000000",
        #                 "field-cash-amount": "0.001530630000000000",
        #                 "field-fees": "0.000003061260000000",
        #                 "finished-at": 1545837948214,
        #                 "source": "spot-api",
        #                 "state": "filled",
        #                 "canceled-at": 0
        #             }
        #         ]
        #     }
        #
        data = self.safe_list(response, 'data', [])
        return self.parse_orders(data, market, since, limit)

    def fetch_spot_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
        return self.fetch_spot_orders_by_states('pre-submitted,submitted,partial-filled,filled,partial-canceled,canceled', symbol, since, limit, params)

    def fetch_closed_spot_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
        return self.fetch_spot_orders_by_states('filled,partial-canceled,canceled', symbol, since, limit, params)

    def fetch_contract_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
        if symbol is None:
            raise ArgumentsRequired(self.id + ' fetchContractOrders() requires a symbol argument')
        self.load_markets()
        market = self.market(symbol)
        request: dict = {
            # POST /api/v1/contract_hisorders inverse futures ----------------
            # 'symbol': market['settleId'],  # BTC, ETH, ...
            # 'order_type': '1',  # 1 limit，3 opponent，4 lightning, 5 trigger order, 6 pst_only, 7 optimal_5, 8 optimal_10, 9 optimal_20, 10 fok, 11 ioc
            # POST /swap-api/v3/swap_hisorders inverse swap ------------------
            # POST /linear-swap-api/v3/swap_hisorders linear isolated --------
            # POST /linear-swap-api/v3/swap_cross_hisorders linear cross -----
            'trade_type': 0,  # 0:All; 1: Open long; 2: Open short; 3: Close short; 4: Close long; 5: Liquidate long positions; 6: Liquidate short positions, 17:buy(one-way mode), 18:sell(one-way mode)
            'status': '0',  # support multiple query seperated by ',',such as '3,4,5', 0: all. 3. Have sumbmitted the orders; 4. Orders partially matched; 5. Orders cancelled with partially matched; 6. Orders fully matched; 7. Orders cancelled
        }
        response = None
        trigger = self.safe_bool_2(params, 'stop', 'trigger')
        stopLossTakeProfit = self.safe_value(params, 'stopLossTakeProfit')
        trailing = self.safe_bool(params, 'trailing', False)
        params = self.omit(params, ['stop', 'stopLossTakeProfit', 'trailing', 'trigger'])
        if trigger or stopLossTakeProfit or trailing:
            if limit is not None:
                request['page_size'] = limit
            request['contract_code'] = market['id']
            request['create_date'] = 90
        else:
            if since is not None:
                request['start_time'] = since  # max 90 days back
                # request['end_time'] = since + 172800000  # 48 hours window
            request['contract'] = market['id']
            request['type'] = 1  # 1:All Orders,2:Order in Finished Status
        request, params = self.handle_until_option('end_time', request, params)
        if market['linear']:
            marginMode = None
            marginMode, params = self.handle_margin_mode_and_params('fetchContractOrders', params)
            marginMode = 'cross' if (marginMode is None) else marginMode
            if marginMode == 'isolated':
                if trigger:
                    response = self.contractPrivatePostLinearSwapApiV1SwapTriggerHisorders(self.extend(request, params))
                elif stopLossTakeProfit:
                    response = self.contractPrivatePostLinearSwapApiV1SwapTpslHisorders(self.extend(request, params))
                elif trailing:
                    response = self.contractPrivatePostLinearSwapApiV1SwapTrackHisorders(self.extend(request, params))
                else:
                    response = self.contractPrivatePostLinearSwapApiV3SwapHisorders(self.extend(request, params))
            elif marginMode == 'cross':
                if trigger:
                    response = self.contractPrivatePostLinearSwapApiV1SwapCrossTriggerHisorders(self.extend(request, params))
                elif stopLossTakeProfit:
                    response = self.contractPrivatePostLinearSwapApiV1SwapCrossTpslHisorders(self.extend(request, params))
                elif trailing:
                    response = self.contractPrivatePostLinearSwapApiV1SwapCrossTrackHisorders(self.extend(request, params))
                else:
                    response = self.contractPrivatePostLinearSwapApiV3SwapCrossHisorders(self.extend(request, params))
        elif market['inverse']:
            if market['swap']:
                if trigger:
                    response = self.contractPrivatePostSwapApiV1SwapTriggerHisorders(self.extend(request, params))
                elif stopLossTakeProfit:
                    response = self.contractPrivatePostSwapApiV1SwapTpslHisorders(self.extend(request, params))
                elif trailing:
                    response = self.contractPrivatePostSwapApiV1SwapTrackHisorders(self.extend(request, params))
                else:
                    response = self.contractPrivatePostSwapApiV3SwapHisorders(self.extend(request, params))
            elif market['future']:
                request['symbol'] = market['settleId']
                if trigger:
                    response = self.contractPrivatePostApiV1ContractTriggerHisorders(self.extend(request, params))
                elif stopLossTakeProfit:
                    response = self.contractPrivatePostApiV1ContractTpslHisorders(self.extend(request, params))
                elif trailing:
                    response = self.contractPrivatePostApiV1ContractTrackHisorders(self.extend(request, params))
                else:
                    response = self.contractPrivatePostApiV3ContractHisorders(self.extend(request, params))
        #
        # future and swap
        #
        #     {
        #         "code": 200,
        #         "msg": "ok",
        #         "data": [
        #             {
        #                 "direction": "buy",
        #                 "offset": "open",
        #                 "volume": 1.000000000000000000,
        #                 "price": 25000.000000000000000000,
        #                 "profit": 0E-18,
        #                 "pair": "BTC-USDT",
        #                 "query_id": 47403349100,
        #                 "order_id": 1103683465337593856,
        #                 "contract_code": "BTC-USDT-230505",
        #                 "symbol": "BTC",
        #                 "lever_rate": 5,
        #                 "create_date": 1683180243577,
        #                 "order_source": "web",
        #                 "canceled_source": "web",
        #                 "order_price_type": 1,
        #                 "order_type": 1,
        #                 "margin_frozen": 0E-18,
        #                 "trade_volume": 0E-18,
        #                 "trade_turnover": 0E-18,
        #                 "fee": 0E-18,
        #                 "trade_avg_price": 0,
        #                 "status": 7,
        #                 "order_id_str": "1103683465337593856",
        #                 "fee_asset": "USDT",
        #                 "fee_amount": 0,
        #                 "fee_quote_amount": 0,
        #                 "liquidation_type": "0",
        #                 "margin_asset": "USDT",
        #                 "margin_mode": "cross",
        #                 "margin_account": "USDT",
        #                 "update_time": 1683180352034,
        #                 "is_tpsl": 0,
        #                 "real_profit": 0,
        #                 "trade_partition": "USDT",
        #                 "reduce_only": 0,
        #                 "contract_type": "self_week",
        #                 "business_type": "futures"
        #             }
        #         ],
        #         "ts": 1683239909141
        #     }
        #
        # trigger
        #
        #     {
        #         "status": "ok",
        #         "data": {
        #             "orders": [
        #                 {
        #                     "contract_type": "swap",
        #                     "business_type": "swap",
        #                     "pair": "BTC-USDT",
        #                     "symbol": "BTC",
        #                     "contract_code": "BTC-USDT",
        #                     "trigger_type": "le",
        #                     "volume": 1.000000000000000000,
        #                     "order_type": 1,
        #                     "direction": "buy",
        #                     "offset": "open",
        #                     "lever_rate": 1,
        #                     "order_id": 1103670703588327424,
        #                     "order_id_str": "1103670703588327424",
        #                     "relation_order_id": "-1",
        #                     "order_price_type": "limit",
        #                     "status": 6,
        #                     "order_source": "web",
        #                     "trigger_price": 25000.000000000000000000,
        #                     "triggered_price": null,
        #                     "order_price": 24000.000000000000000000,
        #                     "created_at": 1683177200945,
        #                     "triggered_at": null,
        #                     "order_insert_at": 0,
        #                     "canceled_at": 1683179075234,
        #                     "fail_code": null,
        #                     "fail_reason": null,
        #                     "margin_mode": "cross",
        #                     "margin_account": "USDT",
        #                     "update_time": 1683179075958,
        #                     "trade_partition": "USDT",
        #                     "reduce_only": 0
        #                 },
        #             ],
        #             "total_page": 1,
        #             "current_page": 1,
        #             "total_size": 2
        #         },
        #         "ts": 1683239702792
        #     }
        #
        # stop-loss and take-profit
        #
        #     {
        #         "status": "ok",
        #         "data": {
        #             "orders": [
        #                 {
        #                     "contract_type": "swap",
        #                     "business_type": "swap",
        #                     "pair": "BTC-USDT",
        #                     "symbol": "BTC",
        #                     "contract_code": "BTC-USDT",
        #                     "margin_mode": "cross",
        #                     "margin_account": "USDT",
        #                     "volume": 1.000000000000000000,
        #                     "order_type": 1,
        #                     "tpsl_order_type": "sl",
        #                     "direction": "sell",
        #                     "order_id": 1103680386844839936,
        #                     "order_id_str": "1103680386844839936",
        #                     "order_source": "web",
        #                     "trigger_type": "le",
        #                     "trigger_price": 25000.000000000000000000,
        #                     "created_at": 1683179509613,
        #                     "order_price_type": "market",
        #                     "status": 11,
        #                     "source_order_id": null,
        #                     "relation_tpsl_order_id": "-1",
        #                     "canceled_at": 0,
        #                     "fail_code": null,
        #                     "fail_reason": null,
        #                     "triggered_price": null,
        #                     "relation_order_id": "-1",
        #                     "update_time": 1683179968231,
        #                     "order_price": 0E-18,
        #                     "trade_partition": "USDT"
        #                 },
        #             ],
        #             "total_page": 1,
        #             "current_page": 1,
        #             "total_size": 2
        #         },
        #         "ts": 1683229230233
        #     }
        #
        orders = self.safe_value(response, 'data')
        if not isinstance(orders, list):
            orders = self.safe_value(orders, 'orders', [])
        return self.parse_orders(orders, market, since, limit)

    def fetch_closed_contract_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
        request: dict = {
            'status': '5,6,7',  # comma separated, 0 all, 3 submitted orders, 4 partially matched, 5 partially cancelled, 6 fully matched and closed, 7 canceled
        }
        return self.fetch_contract_orders(symbol, since, limit, self.extend(request, params))

    def fetch_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
        """

        https://huobiapi.github.io/docs/spot/v1/en/#search-past-orders
        https://huobiapi.github.io/docs/spot/v1/en/#search-historical-orders-within-48-hours
        https://huobiapi.github.io/docs/usdt_swap/v1/en/#isolated-get-history-orders-new
        https://huobiapi.github.io/docs/usdt_swap/v1/en/#cross-get-history-orders-new
        https://huobiapi.github.io/docs/coin_margined_swap/v1/en/#get-history-orders-new
        https://huobiapi.github.io/docs/coin_margined_swap/v1/en/#query-history-orders-via-multiple-fields-new

        fetches information on multiple orders made by the user
        :param str symbol: unified market symbol of the market orders were made in
        :param int [since]: the earliest time in ms to fetch orders for
        :param int [limit]: the maximum number of order structures to retrieve
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :param bool [params.trigger]: *contract only* if the orders are trigger trigger orders or not
        :param bool [params.stopLossTakeProfit]: *contract only* if the orders are stop-loss or take-profit orders
        :param int [params.until]: the latest time in ms to fetch entries for
        :param boolean [params.trailing]: *contract only* set to True if you want to fetch trailing stop orders
        :returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
        """
        self.load_markets()
        market = None
        if symbol is not None:
            market = self.market(symbol)
        marketType = None
        marketType, params = self.handle_market_type_and_params('fetchOrders', market, params)
        contract = (marketType == 'swap') or (marketType == 'future')
        if contract and (symbol is None):
            raise ArgumentsRequired(self.id + ' fetchOrders() requires a symbol argument for ' + marketType + ' orders')
        if contract:
            return self.fetch_contract_orders(symbol, since, limit, params)
        else:
            return self.fetch_spot_orders(symbol, since, limit, params)

    def fetch_closed_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
        """

        https://huobiapi.github.io/docs/spot/v1/en/#search-past-orders
        https://huobiapi.github.io/docs/spot/v1/en/#search-historical-orders-within-48-hours
        https://huobiapi.github.io/docs/usdt_swap/v1/en/#isolated-get-history-orders-new
        https://huobiapi.github.io/docs/usdt_swap/v1/en/#cross-get-history-orders-new
        https://huobiapi.github.io/docs/coin_margined_swap/v1/en/#get-history-orders-new
        https://huobiapi.github.io/docs/coin_margined_swap/v1/en/#query-history-orders-via-multiple-fields-new

        fetches information on multiple closed orders made by the user
        :param str symbol: unified market symbol of the market orders were made in
        :param int [since]: the earliest time in ms to fetch orders for
        :param int [limit]: the maximum number of order structures to retrieve
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :param int [params.until]: the latest time in ms to fetch entries for
        :param boolean [params.paginate]: default False, when True will automatically paginate by calling self endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
        :returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
        """
        self.load_markets()
        paginate = False
        paginate, params = self.handle_option_and_params(params, 'fetchClosedOrders', 'paginate')
        if paginate:
            return self.fetch_paginated_call_dynamic('fetchClosedOrders', symbol, since, limit, params, 100)
        market = None
        if symbol is not None:
            market = self.market(symbol)
        marketType = None
        marketType, params = self.handle_market_type_and_params('fetchClosedOrders', market, params)
        if marketType == 'spot':
            return self.fetch_closed_spot_orders(symbol, since, limit, params)
        else:
            return self.fetch_closed_contract_orders(symbol, since, limit, params)

    def fetch_open_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
        """

        https://huobiapi.github.io/docs/spot/v1/en/#get-all-open-orders
        https://huobiapi.github.io/docs/usdt_swap/v1/en/#isolated-current-unfilled-order-acquisition
        https://huobiapi.github.io/docs/usdt_swap/v1/en/#cross-current-unfilled-order-acquisition

        fetch all unfilled currently open orders
        :param str symbol: unified market symbol
        :param int [since]: the earliest time in ms to fetch open orders for
        :param int [limit]: the maximum number of open order structures to retrieve
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :param bool [params.trigger]: *contract only* if the orders are trigger trigger orders or not
        :param bool [params.stopLossTakeProfit]: *contract only* if the orders are stop-loss or take-profit orders
        :param boolean [params.trailing]: *contract only* set to True if you want to fetch trailing stop orders
        :returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
        """
        self.load_markets()
        market = None
        if symbol is not None:
            market = self.market(symbol)
        request: dict = {}
        marketType = None
        marketType, params = self.handle_market_type_and_params('fetchOpenOrders', market, params)
        subType = None
        subType, params = self.handle_sub_type_and_params('fetchOpenOrders', market, params, 'linear')
        response = None
        if marketType == 'spot':
            if symbol is not None:
                request['symbol'] = market['id']
            # todo replace with fetchAccountIdByType
            accountId = self.safe_string(params, 'account-id')
            if accountId is None:
                # pick the first account
                self.load_accounts()
                for i in range(0, len(self.accounts)):
                    account = self.accounts[i]
                    if self.safe_string(account, 'type') == 'spot':
                        accountId = self.safe_string(account, 'id')
                        if accountId is not None:
                            break
            request['account-id'] = accountId
            if limit is not None:
                request['size'] = limit
            params = self.omit(params, 'account-id')
            response = self.spotPrivateGetV1OrderOpenOrders(self.extend(request, params))
        else:
            if symbol is not None:
                # raise ArgumentsRequired(self.id + ' fetchOpenOrders() requires a symbol argument')
                request['contract_code'] = market['id']
            if limit is not None:
                request['page_size'] = limit
            trigger = self.safe_bool_2(params, 'stop', 'trigger')
            stopLossTakeProfit = self.safe_value(params, 'stopLossTakeProfit')
            trailing = self.safe_bool(params, 'trailing', False)
            params = self.omit(params, ['stop', 'stopLossTakeProfit', 'trailing', 'trigger'])
            if subType == 'linear':
                marginMode = None
                marginMode, params = self.handle_margin_mode_and_params('fetchOpenOrders', params)
                marginMode = 'cross' if (marginMode is None) else marginMode
                if marginMode == 'isolated':
                    if trigger:
                        response = self.contractPrivatePostLinearSwapApiV1SwapTriggerOpenorders(self.extend(request, params))
                    elif stopLossTakeProfit:
                        response = self.contractPrivatePostLinearSwapApiV1SwapTpslOpenorders(self.extend(request, params))
                    elif trailing:
                        response = self.contractPrivatePostLinearSwapApiV1SwapTrackOpenorders(self.extend(request, params))
                    else:
                        response = self.contractPrivatePostLinearSwapApiV1SwapOpenorders(self.extend(request, params))
                elif marginMode == 'cross':
                    if trigger:
                        response = self.contractPrivatePostLinearSwapApiV1SwapCrossTriggerOpenorders(self.extend(request, params))
                    elif stopLossTakeProfit:
                        response = self.contractPrivatePostLinearSwapApiV1SwapCrossTpslOpenorders(self.extend(request, params))
                    elif trailing:
                        response = self.contractPrivatePostLinearSwapApiV1SwapCrossTrackOpenorders(self.extend(request, params))
                    else:
                        response = self.contractPrivatePostLinearSwapApiV1SwapCrossOpenorders(self.extend(request, params))
            elif subType == 'inverse':
                if marketType == 'swap':
                    if trigger:
                        response = self.contractPrivatePostSwapApiV1SwapTriggerOpenorders(self.extend(request, params))
                    elif stopLossTakeProfit:
                        response = self.contractPrivatePostSwapApiV1SwapTpslOpenorders(self.extend(request, params))
                    elif trailing:
                        response = self.contractPrivatePostSwapApiV1SwapTrackOpenorders(self.extend(request, params))
                    else:
                        response = self.contractPrivatePostSwapApiV1SwapOpenorders(self.extend(request, params))
                elif marketType == 'future':
                    request['symbol'] = self.safe_string(market, 'settleId', 'usdt')
                    if trigger:
                        response = self.contractPrivatePostApiV1ContractTriggerOpenorders(self.extend(request, params))
                    elif stopLossTakeProfit:
                        response = self.contractPrivatePostApiV1ContractTpslOpenorders(self.extend(request, params))
                    elif trailing:
                        response = self.contractPrivatePostApiV1ContractTrackOpenorders(self.extend(request, params))
                    else:
                        response = self.contractPrivatePostApiV1ContractOpenorders(self.extend(request, params))
        #
        # spot
        #
        #     {
        #         "status":"ok",
        #         "data":[
        #             {
        #                 "symbol":"ethusdt",
        #                 "source":"api",
        #                 "amount":"0.010000000000000000",
        #                 "account-id":1528640,
        #                 "created-at":1561597491963,
        #                 "price":"400.000000000000000000",
        #                 "filled-amount":"0.0",
        #                 "filled-cash-amount":"0.0",
        #                 "filled-fees":"0.0",
        #                 "id":38477101630,
        #                 "state":"submitted",
        #                 "type":"sell-limit"
        #             }
        #         ]
        #     }
        #
        # futures
        #
        #     {
        #         "status": "ok",
        #         "data": {
        #             "orders": [
        #                 {
        #                     "symbol": "ADA",
        #                     "contract_code": "ADA201225",
        #                     "contract_type": "quarter",
        #                     "volume": 1,
        #                     "price": 0.0925,
        #                     "order_price_type": "post_only",
        #                     "order_type": 1,
        #                     "direction": "buy",
        #                     "offset": "close",
        #                     "lever_rate": 20,
        #                     "order_id": 773131315209248768,
        #                     "client_order_id": null,
        #                     "created_at": 1604370469629,
        #                     "trade_volume": 0,
        #                     "trade_turnover": 0,
        #                     "fee": 0,
        #                     "trade_avg_price": null,
        #                     "margin_frozen": 0,
        #                     "profit": 0,
        #                     "status": 3,
        #                     "order_source": "web",
        #                     "order_id_str": "773131315209248768",
        #                     "fee_asset": "ADA",
        #                     "liquidation_type": null,
        #                     "canceled_at": null,
        #                     "is_tpsl": 0,
        #                     "update_time": 1606975980467,
        #                     "real_profit": 0
        #                 }
        #             ],
        #             "total_page": 1,
        #             "current_page": 1,
        #             "total_size": 1
        #         },
        #         "ts": 1604370488518
        #     }
        #
        # trigger
        #
        #     {
        #         "status": "ok",
        #         "data": {
        #             "orders": [
        #                 {
        #                     "contract_type": "swap",
        #                     "business_type": "swap",
        #                     "pair": "BTC-USDT",
        #                     "symbol": "BTC",
        #                     "contract_code": "BTC-USDT",
        #                     "trigger_type": "le",
        #                     "volume": 1.000000000000000000,
        #                     "order_type": 1,
        #                     "direction": "buy",
        #                     "offset": "open",
        #                     "lever_rate": 1,
        #                     "order_id": 1103670703588327424,
        #                     "order_id_str": "1103670703588327424",
        #                     "order_source": "web",
        #                     "trigger_price": 25000.000000000000000000,
        #                     "order_price": 24000.000000000000000000,
        #                     "created_at": 1683177200945,
        #                     "order_price_type": "limit",
        #                     "status": 2,
        #                     "margin_mode": "cross",
        #                     "margin_account": "USDT",
        #                     "trade_partition": "USDT",
        #                     "reduce_only": 0
        #                 }
        #             ],
        #             "total_page": 1,
        #             "current_page": 1,
        #             "total_size": 1
        #         },
        #         "ts": 1683177805320
        #     }
        #
        # stop-loss and take-profit
        #
        #     {
        #         "status": "ok",
        #         "data": {
        #             "orders": [
        #                 {
        #                     "contract_type": "swap",
        #                     "business_type": "swap",
        #                     "pair": "BTC-USDT",
        #                     "symbol": "BTC",
        #                     "contract_code": "BTC-USDT",
        #                     "margin_mode": "cross",
        #                     "margin_account": "USDT",
        #                     "volume": 1.000000000000000000,
        #                     "order_type": 1,
        #                     "direction": "sell",
        #                     "order_id": 1103680386844839936,
        #                     "order_id_str": "1103680386844839936",
        #                     "order_source": "web",
        #                     "trigger_type": "le",
        #                     "trigger_price": 25000.000000000000000000,
        #                     "order_price": 0E-18,
        #                     "created_at": 1683179509613,
        #                     "order_price_type": "market",
        #                     "status": 2,
        #                     "tpsl_order_type": "sl",
        #                     "source_order_id": null,
        #                     "relation_tpsl_order_id": "-1",
        #                     "trade_partition": "USDT"
        #                 }
        #             ],
        #             "total_page": 1,
        #             "current_page": 1,
        #             "total_size": 1
        #         },
        #         "ts": 1683179527011
        #     }
        #
        # trailing
        #
        #     {
        #         "status": "ok",
        #         "data": {
        #             "orders": [
        #                 {
        #                     "contract_type": "swap",
        #                     "business_type": "swap",
        #                     "pair": "BTC-USDT",
        #                     "symbol": "BTC",
        #                     "contract_code": "BTC-USDT",
        #                     "volume": 1.000000000000000000,
        #                     "order_type": 1,
        #                     "direction": "sell",
        #                     "offset": "close",
        #                     "lever_rate": 1,
        #                     "order_id": 1192021437253877761,
        #                     "order_id_str": "1192021437253877761",
        #                     "order_source": "api",
        #                     "created_at": 1704241657328,
        #                     "order_price_type": "formula_price",
        #                     "status": 2,
        #                     "callback_rate": 0.050000000000000000,
        #                     "active_price": 50000.000000000000000000,
        #                     "is_active": 0,
        #                     "margin_mode": "cross",
        #                     "margin_account": "USDT",
        #                     "trade_partition": "USDT",
        #                     "reduce_only": 1
        #                 },
        #             ],
        #             "total_page": 1,
        #             "current_page": 1,
        #             "total_size": 2
        #         },
        #         "ts": 1704242440106
        #     }
        #
        orders = self.safe_value(response, 'data')
        if not isinstance(orders, list):
            orders = self.safe_value(orders, 'orders', [])
        return self.parse_orders(orders, market, since, limit)

    def parse_order_status(self, status: Str):
        statuses: dict = {
            # spot
            'partial-filled': 'open',
            'partial-canceled': 'canceled',
            'filled': 'closed',
            'canceled': 'canceled',
            'submitted': 'open',
            'created': 'open',  # For stop orders
            # contract
            '1': 'open',
            '2': 'open',
            '3': 'open',
            '4': 'open',
            '5': 'canceled',  # partially matched
            '6': 'closed',
            '7': 'canceled',
            '11': 'canceling',
        }
        return self.safe_string(statuses, status, status)

    def parse_order(self, order: dict, market: Market = None) -> Order:
        #
        # spot
        #
        #     {
        #         "id":  13997833014,
        #         "symbol": "ethbtc",
        #         "account-id":  3398321,
        #         "amount": "0.045000000000000000",
        #         "price": "0.034014000000000000",
        #         "created-at":  1545836976871,
        #         "type": "sell-limit",
        #         "field-amount": "0.045000000000000000",  # they have fixed it for filled-amount
        #         "field-cash-amount": "0.001530630000000000",  # they have fixed it for filled-cash-amount
        #         "field-fees": "0.000003061260000000",  # they have fixed it for filled-fees
        #         "finished-at":  1545837948214,
        #         "source": "spot-api",
        #         "state": "filled",
        #         "canceled-at":  0
        #     }
        #
        #     {
        #         "id":  20395337822,
        #         "symbol": "ethbtc",
        #         "account-id":  5685075,
        #         "amount": "0.001000000000000000",
        #         "price": "0.0",
        #         "created-at":  1545831584023,
        #         "type": "buy-market",
        #         "field-amount": "0.029100000000000000",  # they have fixed it for filled-amount
        #         "field-cash-amount": "0.000999788700000000",  # they have fixed it for filled-cash-amount
        #         "field-fees": "0.000058200000000000",  # they have fixed it for filled-fees
        #         "finished-at":  1545831584181,
        #         "source": "spot-api",
        #         "state": "filled",
        #         "canceled-at":  0
        #     }
        #
        # linear swap cross margin createOrder
        #
        #     {
        #         "order_id":924660854912552960,
        #         "order_id_str":"924660854912552960"
        #     }
        #
        # contracts fetchOrder
        #
        #     {
        #         "business_type":"swap",
        #         "contract_type":"swap",
        #         "pair":"BTC-USDT",
        #         "symbol":"BTC",
        #         "contract_code":"BTC-USDT",
        #         "volume":1,
        #         "price":3000,
        #         "order_price_type":"limit",
        #         "order_type":1,
        #         "direction":"buy",
        #         "offset":"open",
        #         "lever_rate":1,
        #         "order_id":924912513206878210,
        #         "client_order_id":null,
        #         "created_at":1640557927189,
        #         "trade_volume":0,
        #         "trade_turnover":0,
        #         "fee":0,
        #         "trade_avg_price":null,
        #         "margin_frozen":3.000000000000000000,
        #         "profit":0,
        #         "status":3,
        #         "order_source":"api",
        #         "order_id_str":"924912513206878210",
        #         "fee_asset":"USDT",
        #         "liquidation_type":"0",
        #         "canceled_at":0,
        #         "margin_asset":"USDT",
        #         "margin_account":"USDT",
        #         "margin_mode":"cross",
        #         "is_tpsl":0,
        #         "real_profit":0
        #     }
        #
        # contracts fetchOrder detailed
        #
        #     {
        #         "symbol": "BTC",
        #         "contract_code": "BTC-USDT",
        #         "instrument_price": 0,
        #         "final_interest": 0,
        #         "adjust_value": 0,
        #         "lever_rate": 10,
        #         "direction": "sell",
        #         "offset": "open",
        #         "volume": 1.000000000000000000,
        #         "price": 13059.800000000000000000,
        #         "created_at": 1603703614712,
        #         "canceled_at": 0,
        #         "order_source": "api",
        #         "order_price_type": "opponent",
        #         "margin_frozen": 0,
        #         "profit": 0,
        #         "trades": [
        #             {
        #                 "trade_id": 131560927,
        #                 "trade_price": 13059.800000000000000000,
        #                 "trade_volume": 1.000000000000000000,
        #                 "trade_turnover": 13.059800000000000000,
        #                 "trade_fee": -0.005223920000000000,
        #                 "created_at": 1603703614715,
        #                 "role": "taker",
        #                 "fee_asset": "USDT",
        #                 "profit": 0,
        #                 "real_profit": 0,
        #                 "id": "131560927-770334322963152896-1"
        #             }
        #         ],
        #         "total_page": 1,
        #         "current_page": 1,
        #         "total_size": 1,
        #         "liquidation_type": "0",
        #         "fee_asset": "USDT",
        #         "fee": -0.005223920000000000,
        #         "order_id": 770334322963152896,
        #         "order_id_str": "770334322963152896",
        #         "client_order_id": 57012021045,
        #         "order_type": "1",
        #         "status": 6,
        #         "trade_avg_price": 13059.800000000000000000,
        #         "trade_turnover": 13.059800000000000000,
        #         "trade_volume": 1.000000000000000000,
        #         "margin_asset": "USDT",
        #         "margin_mode": "isolated",
        #         "margin_account": "BTC-USDT",
        #         "real_profit": 0,
        #         "is_tpsl": 0
        #     }
        #
        # future and swap: fetchOrders
        #
        #     {
        #         "order_id": 773131315209248768,
        #         "contract_code": "ADA201225",
        #         "symbol": "ADA",
        #         "lever_rate": 20,
        #         "direction": "buy",
        #         "offset": "close",
        #         "volume": 1,
        #         "price": 0.0925,
        #         "create_date": 1604370469629,
        #         "update_time": 1603704221118,
        #         "order_source": "web",
        #         "order_price_type": 6,
        #         "order_type": 1,
        #         "margin_frozen": 0,
        #         "profit": 0,
        #         "contract_type": "quarter",
        #         "trade_volume": 0,
        #         "trade_turnover": 0,
        #         "fee": 0,
        #         "trade_avg_price": 0,
        #         "status": 3,
        #         "order_id_str": "773131315209248768",
        #         "fee_asset": "ADA",
        #         "liquidation_type": "0",
        #         "is_tpsl": 0,
        #         "real_profit": 0
        #         "margin_asset": "USDT",
        #         "margin_mode": "cross",
        #         "margin_account": "USDT",
        #         "trade_partition": "USDT",  # only in isolated & cross of linear
        #         "reduce_only": "1",  # only in isolated & cross of linear
        #         "contract_type": "quarter",  # only in cross-margin(inverse & linear)
        #         "pair": "BTC-USDT",  # only in cross-margin(inverse & linear)
        #         "business_type": "futures"  # only in cross-margin(inverse & linear)
        #     }
        #
        # trigger: fetchOpenOrders
        #
        #     {
        #         "contract_type": "swap",
        #         "business_type": "swap",
        #         "pair": "BTC-USDT",
        #         "symbol": "BTC",
        #         "contract_code": "BTC-USDT",
        #         "trigger_type": "le",
        #         "volume": 1.000000000000000000,
        #         "order_type": 1,
        #         "direction": "buy",
        #         "offset": "open",
        #         "lever_rate": 1,
        #         "order_id": 1103670703588327424,
        #         "order_id_str": "1103670703588327424",
        #         "order_source": "web",
        #         "trigger_price": 25000.000000000000000000,
        #         "order_price": 24000.000000000000000000,
        #         "created_at": 1683177200945,
        #         "order_price_type": "limit",
        #         "status": 2,
        #         "margin_mode": "cross",
        #         "margin_account": "USDT",
        #         "trade_partition": "USDT",
        #         "reduce_only": 0
        #     }
        #
        # stop-loss and take-profit: fetchOpenOrders
        #
        #     {
        #         "contract_type": "swap",
        #         "business_type": "swap",
        #         "pair": "BTC-USDT",
        #         "symbol": "BTC",
        #         "contract_code": "BTC-USDT",
        #         "margin_mode": "cross",
        #         "margin_account": "USDT",
        #         "volume": 1.000000000000000000,
        #         "order_type": 1,
        #         "direction": "sell",
        #         "order_id": 1103680386844839936,
        #         "order_id_str": "1103680386844839936",
        #         "order_source": "web",
        #         "trigger_type": "le",
        #         "trigger_price": 25000.000000000000000000,
        #         "order_price": 0E-18,
        #         "created_at": 1683179509613,
        #         "order_price_type": "market",
        #         "status": 2,
        #         "tpsl_order_type": "sl",
        #         "source_order_id": null,
        #         "relation_tpsl_order_id": "-1",
        #         "trade_partition": "USDT"
        #     }
        #
        # trailing: fetchOpenOrders
        #
        #     {
        #         "contract_type": "swap",
        #         "business_type": "swap",
        #         "pair": "BTC-USDT",
        #         "symbol": "BTC",
        #         "contract_code": "BTC-USDT",
        #         "volume": 1.000000000000000000,
        #         "order_type": 1,
        #         "direction": "sell",
        #         "offset": "close",
        #         "lever_rate": 1,
        #         "order_id": 1192021437253877761,
        #         "order_id_str": "1192021437253877761",
        #         "order_source": "api",
        #         "created_at": 1704241657328,
        #         "order_price_type": "formula_price",
        #         "status": 2,
        #         "callback_rate": 0.050000000000000000,
        #         "active_price": 50000.000000000000000000,
        #         "is_active": 0,
        #         "margin_mode": "cross",
        #         "margin_account": "USDT",
        #         "trade_partition": "USDT",
        #         "reduce_only": 1
        #     }
        #
        # trigger: fetchOrders
        #
        #     {
        #         "contract_type": "swap",
        #         "business_type": "swap",
        #         "pair": "BTC-USDT",
        #         "symbol": "BTC",
        #         "contract_code": "BTC-USDT",
        #         "trigger_type": "le",
        #         "volume": 1.000000000000000000,
        #         "order_type": 1,
        #         "direction": "buy",
        #         "offset": "open",
        #         "lever_rate": 1,
        #         "order_id": 1103670703588327424,
        #         "order_id_str": "1103670703588327424",
        #         "relation_order_id": "-1",
        #         "order_price_type": "limit",
        #         "status": 6,
        #         "order_source": "web",
        #         "trigger_price": 25000.000000000000000000,
        #         "triggered_price": null,
        #         "order_price": 24000.000000000000000000,
        #         "created_at": 1683177200945,
        #         "triggered_at": null,
        #         "order_insert_at": 0,
        #         "canceled_at": 1683179075234,
        #         "fail_code": null,
        #         "fail_reason": null,
        #         "margin_mode": "cross",
        #         "margin_account": "USDT",
        #         "update_time": 1683179075958,
        #         "trade_partition": "USDT",
        #         "reduce_only": 0
        #     }
        #
        # stop-loss and take-profit: fetchOrders
        #
        #     {
        #         "contract_type": "swap",
        #         "business_type": "swap",
        #         "pair": "BTC-USDT",
        #         "symbol": "BTC",
        #         "contract_code": "BTC-USDT",
        #         "margin_mode": "cross",
        #         "margin_account": "USDT",
        #         "volume": 1.000000000000000000,
        #         "order_type": 1,
        #         "tpsl_order_type": "sl",
        #         "direction": "sell",
        #         "order_id": 1103680386844839936,
        #         "order_id_str": "1103680386844839936",
        #         "order_source": "web",
        #         "trigger_type": "le",
        #         "trigger_price": 25000.000000000000000000,
        #         "created_at": 1683179509613,
        #         "order_price_type": "market",
        #         "status": 11,
        #         "source_order_id": null,
        #         "relation_tpsl_order_id": "-1",
        #         "canceled_at": 0,
        #         "fail_code": null,
        #         "fail_reason": null,
        #         "triggered_price": null,
        #         "relation_order_id": "-1",
        #         "update_time": 1683179968231,
        #         "order_price": 0E-18,
        #         "trade_partition": "USDT"
        #     }
        #
        # spot: createOrders
        #
        #     [
        #         {
        #             "order-id": 936847569789079,
        #             "client-order-id": "AA03022abc3a55e82c-0087-4fc2-beac-112fdebb1ee9"
        #         },
        #         {
        #             "client-order-id": "AA03022abcdb3baefb-3cfa-4891-8009-082b3d46ca82",
        #             "err-code": "account-frozen-balance-insufficient-error",
        #             "err-msg": "trade account balance is not enough, left: `89`"
        #         }
        #     ]
        #
        # swap and future: createOrders
        #
        #     [
        #         {
        #             "index": 2,
        #             "err_code": 1047,
        #             "err_msg": "Insufficient margin available."
        #         },
        #         {
        #             "order_id": 1172923090632953857,
        #             "index": 1,
        #             "order_id_str": "1172923090632953857"
        #         }
        #     ]
        #
        rejectedCreateOrders = self.safe_string_2(order, 'err_code', 'err-code')
        status = self.parse_order_status(self.safe_string_2(order, 'state', 'status'))
        if rejectedCreateOrders is not None:
            status = 'rejected'
        id = self.safe_string_n(order, ['id', 'order_id_str', 'order-id'])
        side = self.safe_string(order, 'direction')
        type = self.safe_string(order, 'order_price_type')
        if 'type' in order:
            orderType = order['type'].split('-')
            side = orderType[0]
            type = orderType[1]
        marketId = self.safe_string_2(order, 'contract_code', 'symbol')
        market = self.safe_market(marketId, market)
        timestamp = self.safe_integer_n(order, ['created_at', 'created-at', 'create_date'])
        clientOrderId = self.safe_string_2(order, 'client_order_id', 'client-or' + 'der-id')  # transpiler regex trick for php issue
        cost = None
        amount = None
        if (type is not None) and (type.find('market') >= 0):
            cost = self.safe_string(order, 'field-cash-amount')
        else:
            amount = self.safe_string_2(order, 'volume', 'amount')
            cost = self.safe_string_n(order, ['filled-cash-amount', 'field-cash-amount', 'trade_turnover'])  # same typo here
        filled = self.safe_string_n(order, ['filled-amount', 'field-amount', 'trade_volume'])  # typo in their API, filled amount
        price = self.safe_string_2(order, 'price', 'order_price')
        feeCost = self.safe_string_2(order, 'filled-fees', 'field-fees')  # typo in their API, filled feeSide
        feeCost = self.safe_string(order, 'fee', feeCost)
        fee = None
        if feeCost is not None:
            feeCurrency = None
            feeCurrencyId = self.safe_string(order, 'fee_asset')
            if feeCurrencyId is not None:
                feeCurrency = self.safe_currency_code(feeCurrencyId)
            else:
                feeCurrency = market['quote'] if (side == 'sell') else market['base']
            fee = {
                'cost': feeCost,
                'currency': feeCurrency,
            }
        average = self.safe_string(order, 'trade_avg_price')
        trades = self.safe_value(order, 'trades')
        reduceOnlyInteger = self.safe_integer(order, 'reduce_only')
        reduceOnly = None
        if reduceOnlyInteger is not None:
            reduceOnly = False if (reduceOnlyInteger == 0) else True
        return self.safe_order({
            'info': order,
            'id': id,
            'clientOrderId': clientOrderId,
            'timestamp': timestamp,
            'datetime': self.iso8601(timestamp),
            'lastTradeTimestamp': None,
            'symbol': market['symbol'],
            'type': type,
            'timeInForce': None,
            'postOnly': None,
            'side': side,
            'price': price,
            'triggerPrice': self.safe_string_2(order, 'stop-price', 'trigger_price'),
            'average': average,
            'cost': cost,
            'amount': amount,
            'filled': filled,
            'remaining': None,
            'status': status,
            'reduceOnly': reduceOnly,
            'fee': fee,
            'trades': trades,
        }, market)

    def create_market_buy_order_with_cost(self, symbol: str, cost: float, params={}):
        """
        create a market buy order by providing the symbol and cost

        https://www.htx.com/en-us/opend/newApiPages/?id=7ec4ee16-7773-11ed-9966-0242ac110003

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

    def create_trailing_percent_order(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, trailingPercent: Num = None, trailingTriggerPrice: Num = None, params={}) -> Order:
        """
        create a trailing order by providing the symbol, type, side, amount, price and trailingPercent
        :param str symbol: unified symbol of the market to create an order in
        :param str type: 'market' or 'limit'
        :param str side: 'buy' or 'sell'
        :param float amount: how much you want to trade in units of the base currency, or number of contracts
        :param float [price]: the price for the order to be filled at, in units of the quote currency, ignored in market orders
        :param float trailingPercent: the percent to trail away from the current market price
        :param float trailingTriggerPrice: the price to activate a trailing order, default uses the price argument
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
        """
        if trailingPercent is None:
            raise ArgumentsRequired(self.id + ' createTrailingPercentOrder() requires a trailingPercent argument')
        if trailingTriggerPrice is None:
            raise ArgumentsRequired(self.id + ' createTrailingPercentOrder() requires a trailingTriggerPrice argument')
        params['trailingPercent'] = trailingPercent
        params['trailingTriggerPrice'] = trailingTriggerPrice
        return self.create_order(symbol, type, side, amount, price, params)

    def create_spot_order_request(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
        """
 @ignore
        helper function to build request
        :param str symbol: unified symbol of the market to create an order in
        :param str type: 'market' or 'limit'
        :param str side: 'buy' or 'sell'
        :param float amount: how much you want to trade in units of the base currency
        :param float [price]: the price at which the order is to be fulfilled, in units of the quote currency, ignored in market orders
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :param str [params.timeInForce]: supports 'IOC' and 'FOK'
        :param float [params.cost]: the quote quantity that can be used alternative for the amount for market buy orders
        :returns dict: request to be sent to the exchange
        """
        self.load_markets()
        self.load_accounts()
        market = self.market(symbol)
        marginMode = None
        marginMode, params = self.handle_margin_mode_and_params('createOrder', params)
        accountId = self.fetch_account_id_by_type(market['type'], marginMode, symbol)
        request: dict = {
            # spot -----------------------------------------------------------
            'account-id': accountId,
            'symbol': market['id'],
            # 'type': side + '-' + type,  # buy-market, sell-market, buy-limit, sell-limit, buy-ioc, sell-ioc, buy-limit-maker, sell-limit-maker, buy-stop-limit, sell-stop-limit, buy-limit-fok, sell-limit-fok, buy-stop-limit-fok, sell-stop-limit-fok
            # 'amount': self.amount_to_precision(symbol, amount),  # for buy market orders it's the order cost
            # 'price': self.price_to_precision(symbol, price),
            # 'source': 'spot-api',  # optional, spot-api, margin-api = isolated margin, super-margin-api = cross margin, c2c-margin-api
            # 'client-order-id': clientOrderId,  # optional, max 64 chars, must be unique within 8 hours
            # 'stop-price': self.price_to_precision(symbol, stopPrice),  # trigger price for stop limit orders
            # 'operator': 'gte',  # gte, lte, trigger price condition
        }
        orderType = type.replace('buy-', '')
        orderType = orderType.replace('sell-', '')
        options = self.safe_value(self.options, market['type'], {})
        triggerPrice = self.safe_string_n(params, ['triggerPrice', 'stopPrice', 'stop-price'])
        if triggerPrice is None:
            stopOrderTypes = self.safe_value(options, 'stopOrderTypes', {})
            if orderType in stopOrderTypes:
                raise ArgumentsRequired(self.id + ' createOrder() requires a triggerPrice for a trigger order')
        else:
            defaultOperator = 'lte' if (side == 'sell') else 'gte'
            stopOperator = self.safe_string(params, 'operator', defaultOperator)
            request['stop-price'] = self.price_to_precision(symbol, triggerPrice)
            request['operator'] = stopOperator
            if (orderType == 'limit') or (orderType == 'limit-fok'):
                orderType = 'stop-' + orderType
            elif (orderType != 'stop-limit') and (orderType != 'stop-limit-fok'):
                raise NotSupported(self.id + ' createOrder() does not support ' + type + ' orders')
        postOnly = None
        postOnly, params = self.handle_post_only(orderType == 'market', orderType == 'limit-maker', params)
        if postOnly:
            orderType = 'limit-maker'
        timeInForce = self.safe_string(params, 'timeInForce', 'GTC')
        if timeInForce == 'FOK':
            orderType = orderType + '-fok'
        elif timeInForce == 'IOC':
            orderType = 'ioc'
        request['type'] = side + '-' + orderType
        clientOrderId = self.safe_string_2(params, 'clientOrderId', 'client-order-id')  # must be 64 chars max and unique within 24 hours
        if clientOrderId is None:
            broker = self.safe_value(self.options, 'broker', {})
            brokerId = self.safe_string(broker, 'id')
            request['client-order-id'] = brokerId + self.uuid()
        else:
            request['client-order-id'] = clientOrderId
        if marginMode == 'cross':
            request['source'] = 'super-margin-api'
        elif marginMode == 'isolated':
            request['source'] = 'margin-api'
        elif marginMode == 'c2c':
            request['source'] = 'c2c-margin-api'
        if (orderType == 'market') and (side == 'buy'):
            quoteAmount = None
            createMarketBuyOrderRequiresPrice = True
            createMarketBuyOrderRequiresPrice, params = self.handle_option_and_params(params, 'createOrder', 'createMarketBuyOrderRequiresPrice', True)
            cost = self.safe_number(params, 'cost')
            params = self.omit(params, 'cost')
            if cost is not None:
                quoteAmount = self.amount_to_precision(symbol, cost)
            elif createMarketBuyOrderRequiresPrice:
                if price is None:
                    raise InvalidOrder(self.id + ' createOrder() requires the price argument for market buy orders to calculate the total cost to spend(amount * price), alternatively set the createMarketBuyOrderRequiresPrice option or param to False and pass the cost to spend in the amount argument')
                else:
                    # despite that cost = amount * price is in quote currency and should have quote precision
                    # the exchange API requires the cost supplied in 'amount' to be of base precision
                    # more about it here:
                    # https://github.com/ccxt/ccxt/pull/4395
                    # https://github.com/ccxt/ccxt/issues/7611
                    # we use amountToPrecision here because the exchange requires cost in base precision
                    amountString = self.number_to_string(amount)
                    priceString = self.number_to_string(price)
                    quoteAmount = self.amount_to_precision(symbol, Precise.string_mul(amountString, priceString))
            else:
                quoteAmount = self.amount_to_precision(symbol, amount)
            request['amount'] = quoteAmount
        else:
            request['amount'] = self.amount_to_precision(symbol, amount)
        limitOrderTypes = self.safe_value(options, 'limitOrderTypes', {})
        if orderType in limitOrderTypes:
            request['price'] = self.price_to_precision(symbol, price)
        params = self.omit(params, ['triggerPrice', 'stopPrice', 'stop-price', 'clientOrderId', 'client-order-id', 'operator', 'timeInForce'])
        return self.extend(request, params)

    def create_contract_order_request(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
        """
 @ignore
        helper function to build request
        :param str symbol: unified symbol of the market to create an order in
        :param str type: 'market' or 'limit'
        :param str side: 'buy' or 'sell'
        :param float amount: how much you want to trade in units of the base currency
        :param float [price]: the price at which the order is to be fulfilled, in units of the quote currency, ignored in market orders
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :param str [params.timeInForce]: supports 'IOC' and 'FOK'
        :param float [params.trailingPercent]: *contract only* the percent to trail away from the current market price
        :param float [params.trailingTriggerPrice]: *contract only* the price to trigger a trailing order, default uses the price argument
        :returns dict: request to be sent to the exchange
        """
        market = self.market(symbol)
        request: dict = {
            'contract_code': market['id'],
            'volume': self.amount_to_precision(symbol, amount),
            'direction': side,
        }
        postOnly = None
        postOnly, params = self.handle_post_only(type == 'market', type == 'post_only', params)
        if postOnly:
            type = 'post_only'
        timeInForce = self.safe_string(params, 'timeInForce', 'GTC')
        if timeInForce == 'FOK':
            type = 'fok'
        elif timeInForce == 'IOC':
            type = 'ioc'
        triggerPrice = self.safe_number_n(params, ['triggerPrice', 'stopPrice', 'trigger_price'])
        stopLossTriggerPrice = self.safe_number_2(params, 'stopLossPrice', 'sl_trigger_price')
        takeProfitTriggerPrice = self.safe_number_2(params, 'takeProfitPrice', 'tp_trigger_price')
        trailingPercent = self.safe_string_2(params, 'trailingPercent', 'callback_rate')
        trailingTriggerPrice = self.safe_number(params, 'trailingTriggerPrice', price)
        isTrailingPercentOrder = trailingPercent is not None
        isTrigger = triggerPrice is not None
        isStopLossTriggerOrder = stopLossTriggerPrice is not None
        isTakeProfitTriggerOrder = takeProfitTriggerPrice is not None
        if isTrigger:
            triggerType = self.safe_string_2(params, 'triggerType', 'trigger_type', 'le')
            request['trigger_type'] = triggerType
            request['trigger_price'] = self.price_to_precision(symbol, triggerPrice)
            if price is not None:
                request['order_price'] = self.price_to_precision(symbol, price)
        elif isStopLossTriggerOrder or isTakeProfitTriggerOrder:
            if isStopLossTriggerOrder:
                request['sl_order_price_type'] = type
                request['sl_trigger_price'] = self.price_to_precision(symbol, stopLossTriggerPrice)
                if price is not None:
                    request['sl_order_price'] = self.price_to_precision(symbol, price)
            else:
                request['tp_order_price_type'] = type
                request['tp_trigger_price'] = self.price_to_precision(symbol, takeProfitTriggerPrice)
                if price is not None:
                    request['tp_order_price'] = self.price_to_precision(symbol, price)
        elif isTrailingPercentOrder:
            trailingPercentString = Precise.string_div(trailingPercent, '100')
            request['callback_rate'] = self.parse_to_numeric(trailingPercentString)
            request['active_price'] = trailingTriggerPrice
            request['order_price_type'] = self.safe_string(params, 'order_price_type', 'formula_price')
        else:
            clientOrderId = self.safe_integer_2(params, 'client_order_id', 'clientOrderId')
            if clientOrderId is not None:
                request['client_order_id'] = clientOrderId
                params = self.omit(params, ['clientOrderId'])
            if type == 'limit' or type == 'ioc' or type == 'fok' or type == 'post_only':
                request['price'] = self.price_to_precision(symbol, price)
        reduceOnly = self.safe_bool_2(params, 'reduceOnly', 'reduce_only', False)
        if not isStopLossTriggerOrder and not isTakeProfitTriggerOrder:
            if reduceOnly:
                request['reduce_only'] = 1
            request['lever_rate'] = self.safe_integer_n(params, ['leverRate', 'lever_rate', 'leverage'], 1)
            if not isTrailingPercentOrder:
                request['order_price_type'] = type
        hedged = self.safe_bool(params, 'hedged', False)
        if hedged:
            if reduceOnly:
                request['offset'] = 'close'
            else:
                request['offset'] = 'open'
        broker = self.safe_value(self.options, 'broker', {})
        brokerId = self.safe_string(broker, 'id')
        request['channel_code'] = brokerId
        params = self.omit(params, ['reduceOnly', 'triggerPrice', 'stopPrice', 'stopLossPrice', 'takeProfitPrice', 'triggerType', 'leverRate', 'timeInForce', 'leverage', 'trailingPercent', 'trailingTriggerPrice', 'hedged'])
        return self.extend(request, params)

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

        https://huobiapi.github.io/docs/spot/v1/en/#place-a-new-order                   # spot, margin
        https://huobiapi.github.io/docs/coin_margined_swap/v1/en/#place-an-order        # coin-m swap
        https://huobiapi.github.io/docs/coin_margined_swap/v1/en/#place-trigger-order   # coin-m swap trigger
        https://huobiapi.github.io/docs/usdt_swap/v1/en/#cross-place-an-order           # usdt-m swap cross
        https://huobiapi.github.io/docs/usdt_swap/v1/en/#cross-place-trigger-order      # usdt-m swap cross trigger
        https://huobiapi.github.io/docs/usdt_swap/v1/en/#isolated-place-an-order        # usdt-m swap isolated
        https://huobiapi.github.io/docs/usdt_swap/v1/en/#isolated-place-trigger-order   # usdt-m swap isolated trigger
        https://huobiapi.github.io/docs/usdt_swap/v1/en/#isolated-set-a-take-profit-and-stop-loss-order-for-an-existing-position
        https://huobiapi.github.io/docs/usdt_swap/v1/en/#cross-set-a-take-profit-and-stop-loss-order-for-an-existing-position
        https://huobiapi.github.io/docs/dm/v1/en/#place-an-order                        # coin-m futures
        https://huobiapi.github.io/docs/dm/v1/en/#place-trigger-order                   # coin-m futures contract trigger

        :param str symbol: unified symbol of the market to create an order in
        :param str type: 'market' or 'limit'
        :param str side: 'buy' or 'sell'
        :param float amount: how much you want to trade in units of the base currency
        :param float [price]: the price at which the order is to be fulfilled, in units of the quote currency, ignored in market orders
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :param float [params.triggerPrice]: the price a trigger order is triggered at
        :param str [params.triggerType]: *contract trigger orders only* ge: greater than or equal to, le: less than or equal to
        :param float [params.stopLossPrice]: *contract only* the price a stop-loss order is triggered at
        :param float [params.takeProfitPrice]: *contract only* the price a take-profit order is triggered at
        :param str [params.operator]: *spot and margin only* gte or lte, trigger price condition
        :param str [params.offset]: *contract only* 'both'(linear only), 'open', or 'close', required in hedge mode and for inverse markets
        :param bool [params.postOnly]: *contract only* True or False
        :param int [params.leverRate]: *contract only* required for all contract orders except tpsl, leverage greater than 20x requires prior approval of high-leverage agreement
        :param str [params.timeInForce]: supports 'IOC' and 'FOK'
        :param float [params.cost]: *spot market buy only* the quote quantity that can be used alternative for the amount
        :param float [params.trailingPercent]: *contract only* the percent to trail away from the current market price
        :param float [params.trailingTriggerPrice]: *contract only* the price to trigger a trailing order, default uses the price argument
        :param bool [params.hedged]: *contract only* True for hedged mode, False for one way mode, default is False
        :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
        """
        self.load_markets()
        market = self.market(symbol)
        triggerPrice = self.safe_number_n(params, ['triggerPrice', 'stopPrice', 'trigger_price'])
        stopLossTriggerPrice = self.safe_number_2(params, 'stopLossPrice', 'sl_trigger_price')
        takeProfitTriggerPrice = self.safe_number_2(params, 'takeProfitPrice', 'tp_trigger_price')
        trailingPercent = self.safe_number(params, 'trailingPercent')
        isTrailingPercentOrder = trailingPercent is not None
        isTrigger = triggerPrice is not None
        isStopLossTriggerOrder = stopLossTriggerPrice is not None
        isTakeProfitTriggerOrder = takeProfitTriggerPrice is not None
        response = None
        if market['spot']:
            if isTrailingPercentOrder:
                raise NotSupported(self.id + ' createOrder() does not support trailing orders for spot markets')
            spotRequest = self.create_spot_order_request(symbol, type, side, amount, price, params)
            response = self.spotPrivatePostV1OrderOrdersPlace(spotRequest)
        else:
            contractRequest = self.create_contract_order_request(symbol, type, side, amount, price, params)
            if market['linear']:
                marginMode = None
                marginMode, contractRequest = self.handle_margin_mode_and_params('createOrder', contractRequest)
                marginMode = 'cross' if (marginMode is None) else marginMode
                if marginMode == 'isolated':
                    if isTrigger:
                        response = self.contractPrivatePostLinearSwapApiV1SwapTriggerOrder(contractRequest)
                    elif isStopLossTriggerOrder or isTakeProfitTriggerOrder:
                        response = self.contractPrivatePostLinearSwapApiV1SwapTpslOrder(contractRequest)
                    elif isTrailingPercentOrder:
                        response = self.contractPrivatePostLinearSwapApiV1SwapTrackOrder(contractRequest)
                    else:
                        response = self.contractPrivatePostLinearSwapApiV1SwapOrder(contractRequest)
                elif marginMode == 'cross':
                    if isTrigger:
                        response = self.contractPrivatePostLinearSwapApiV1SwapCrossTriggerOrder(contractRequest)
                    elif isStopLossTriggerOrder or isTakeProfitTriggerOrder:
                        response = self.contractPrivatePostLinearSwapApiV1SwapCrossTpslOrder(contractRequest)
                    elif isTrailingPercentOrder:
                        response = self.contractPrivatePostLinearSwapApiV1SwapCrossTrackOrder(contractRequest)
                    else:
                        response = self.contractPrivatePostLinearSwapApiV1SwapCrossOrder(contractRequest)
            elif market['inverse']:
                offset = self.safe_string(params, 'offset')
                if offset is None:
                    raise ArgumentsRequired(self.id + ' createOrder() requires an extra parameter params["offset"] to be set to "open" or "close" when placing orders in inverse markets')
                if market['swap']:
                    if isTrigger:
                        response = self.contractPrivatePostSwapApiV1SwapTriggerOrder(contractRequest)
                    elif isStopLossTriggerOrder or isTakeProfitTriggerOrder:
                        response = self.contractPrivatePostSwapApiV1SwapTpslOrder(contractRequest)
                    elif isTrailingPercentOrder:
                        response = self.contractPrivatePostSwapApiV1SwapTrackOrder(contractRequest)
                    else:
                        response = self.contractPrivatePostSwapApiV1SwapOrder(contractRequest)
                elif market['future']:
                    if isTrigger:
                        response = self.contractPrivatePostApiV1ContractTriggerOrder(contractRequest)
                    elif isStopLossTriggerOrder or isTakeProfitTriggerOrder:
                        response = self.contractPrivatePostApiV1ContractTpslOrder(contractRequest)
                    elif isTrailingPercentOrder:
                        response = self.contractPrivatePostApiV1ContractTrackOrder(contractRequest)
                    else:
                        response = self.contractPrivatePostApiV1ContractOrder(contractRequest)
        #
        # spot
        #
        #     {"status":"ok","data":"438398393065481"}
        #
        # swap and future
        #
        #     {
        #         "status": "ok",
        #         "data": {
        #             "order_id": 924660854912552960,
        #             "order_id_str": "924660854912552960"
        #         },
        #         "ts": 1640497927185
        #     }
        #
        # stop-loss and take-profit
        #
        #     {
        #         "status": "ok",
        #         "data": {
        #             "tp_order": {
        #                 "order_id": 1101494204040163328,
        #                 "order_id_str": "1101494204040163328"
        #             },
        #             "sl_order": null
        #         },
        #         "ts": :1682658283024
        #     }
        #
        data = None
        result = None
        if market['spot']:
            return self.safe_order({
                'info': response,
                'id': self.safe_string(response, 'data'),
                'timestamp': None,
                'datetime': None,
                'lastTradeTimestamp': None,
                'status': None,
                'symbol': None,
                'type': type,
                'side': side,
                'price': price,
                'amount': amount,
                'filled': None,
                'remaining': None,
                'cost': None,
                'trades': None,
                'fee': None,
                'clientOrderId': None,
                'average': None,
            }, market)
        elif isStopLossTriggerOrder:
            data = self.safe_value(response, 'data', {})
            result = self.safe_value(data, 'sl_order', {})
        elif isTakeProfitTriggerOrder:
            data = self.safe_value(response, 'data', {})
            result = self.safe_value(data, 'tp_order', {})
        else:
            result = self.safe_value(response, 'data', {})
        return self.parse_order(result, market)

    def create_orders(self, orders: List[OrderRequest], params={}):
        """
        create a list of trade orders

        https://huobiapi.github.io/docs/spot/v1/en/#place-a-batch-of-orders
        https://huobiapi.github.io/docs/dm/v1/en/#place-a-batch-of-orders
        https://huobiapi.github.io/docs/coin_margined_swap/v1/en/#place-a-batch-of-orders
        https://huobiapi.github.io/docs/usdt_swap/v1/en/#isolated-place-a-batch-of-orders
        https://huobiapi.github.io/docs/usdt_swap/v1/en/#cross-place-a-batch-of-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 dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
        """
        self.load_markets()
        ordersRequests = []
        symbol = None
        market = None
        marginMode = None
        for i in range(0, len(orders)):
            rawOrder = orders[i]
            marketId = self.safe_string(rawOrder, 'symbol')
            if symbol is None:
                symbol = marketId
            else:
                if symbol != marketId:
                    raise BadRequest(self.id + ' createOrders() requires all orders to have the same symbol')
            type = self.safe_string(rawOrder, 'type')
            side = self.safe_string(rawOrder, 'side')
            amount = self.safe_value(rawOrder, 'amount')
            price = self.safe_value(rawOrder, 'price')
            orderParams = self.safe_value(rawOrder, 'params', {})
            marginResult = self.handle_margin_mode_and_params('createOrders', orderParams)
            currentMarginMode = marginResult[0]
            if currentMarginMode is not None:
                if marginMode is None:
                    marginMode = currentMarginMode
                else:
                    if marginMode != currentMarginMode:
                        raise BadRequest(self.id + ' createOrders() requires all orders to have the same margin mode(isolated or cross)')
            market = self.market(symbol)
            orderRequest = None
            if market['spot']:
                orderRequest = self.create_spot_order_request(marketId, type, side, amount, price, orderParams)
            else:
                orderRequest = self.create_contract_order_request(marketId, type, side, amount, price, orderParams)
            orderRequest = self.omit(orderRequest, 'marginMode')
            ordersRequests.append(orderRequest)
        request: dict = {}
        response = None
        if market['spot']:
            response = self.privatePostOrderBatchOrders(ordersRequests)
        else:
            request['orders_data'] = ordersRequests
            if market['linear']:
                marginMode = 'cross' if (marginMode is None) else marginMode
                if marginMode == 'isolated':
                    response = self.contractPrivatePostLinearSwapApiV1SwapBatchorder(request)
                elif marginMode == 'cross':
                    response = self.contractPrivatePostLinearSwapApiV1SwapCrossBatchorder(request)
            elif market['inverse']:
                if market['swap']:
                    response = self.contractPrivatePostSwapApiV1SwapBatchorder(request)
                elif market['future']:
                    response = self.contractPrivatePostApiV1ContractBatchorder(request)
        #
        # spot
        #
        #     {
        #         "status": "ok",
        #         "data": [
        #             {
        #                 "order-id": 936847569789079,
        #                 "client-order-id": "AA03022abc3a55e82c-0087-4fc2-beac-112fdebb1ee9"
        #             },
        #             {
        #                 "client-order-id": "AA03022abcdb3baefb-3cfa-4891-8009-082b3d46ca82",
        #                 "err-code": "account-frozen-balance-insufficient-error",
        #                 "err-msg": "trade account balance is not enough, left: `89`"
        #             }
        #         ]
        #     }
        #
        # swap and future
        #
        #     {
        #         "status": "ok",
        #         "data": {
        #             "errors": [
        #                 {
        #                     "index": 2,
        #                     "err_code": 1047,
        #                     "err_msg": "Insufficient margin available."
        #                 }
        #             ],
        #             "success": [
        #                 {
        #                     "order_id": 1172923090632953857,
        #                     "index": 1,
        #                     "order_id_str": "1172923090632953857"
        #                 }
        #             ]
        #         },
        #         "ts": 1699688256671
        #     }
        #
        result = None
        if market['spot']:
            result = self.safe_value(response, 'data', [])
        else:
            data = self.safe_value(response, 'data', {})
            success = self.safe_value(data, 'success', [])
            errors = self.safe_value(data, 'errors', [])
            result = self.array_concat(success, errors)
        return self.parse_orders(result, market)

    def cancel_order(self, id: str, symbol: Str = None, params={}):
        """
        cancels an open order
        :param str id: order id
        :param str symbol: unified symbol of the market the order was made in
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :param boolean [params.trigger]: *contract only* if the order is a trigger trigger order or not
        :param boolean [params.stopLossTakeProfit]: *contract only* if the order is a stop-loss or take-profit order
        :param boolean [params.trailing]: *contract only* set to True if you want to cancel a trailing order
        :returns dict: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
        """
        self.load_markets()
        market = None
        if symbol is not None:
            market = self.market(symbol)
        marketType = None
        marketType, params = self.handle_market_type_and_params('cancelOrder', market, params)
        request: dict = {
            # spot -----------------------------------------------------------
            # 'order-id': 'id',
            # 'symbol': market['id'],
            # 'client-order-id': clientOrderId,
            # contracts ------------------------------------------------------
            # 'order_id': id,
            # 'client_order_id': clientOrderId,
            # 'contract_code': market['id'],
            # 'pair': 'BTC-USDT',
            # 'contract_type': 'this_week',  # swap, self_week, next_week, quarter, next_ quarter
        }
        response = None
        if marketType == 'spot':
            clientOrderId = self.safe_string_2(params, 'client-order-id', 'clientOrderId')
            if clientOrderId is None:
                request['order-id'] = id
                response = self.spotPrivatePostV1OrderOrdersOrderIdSubmitcancel(self.extend(request, params))
            else:
                request['client-order-id'] = clientOrderId
                params = self.omit(params, ['client-order-id', 'clientOrderId'])
                response = self.spotPrivatePostV1OrderOrdersSubmitCancelClientOrder(self.extend(request, params))
        else:
            if symbol is None:
                raise ArgumentsRequired(self.id + ' cancelOrder() requires a symbol argument')
            clientOrderId = self.safe_string_2(params, 'client_order_id', 'clientOrderId')
            if clientOrderId is None:
                request['order_id'] = id
            else:
                request['client_order_id'] = clientOrderId
                params = self.omit(params, ['client_order_id', 'clientOrderId'])
            if market['future']:
                request['symbol'] = market['settleId']
            else:
                request['contract_code'] = market['id']
            trigger = self.safe_bool_2(params, 'stop', 'trigger')
            stopLossTakeProfit = self.safe_value(params, 'stopLossTakeProfit')
            trailing = self.safe_bool(params, 'trailing', False)
            params = self.omit(params, ['stop', 'stopLossTakeProfit', 'trailing', 'trigger'])
            if market['linear']:
                marginMode = None
                marginMode, params = self.handle_margin_mode_and_params('cancelOrder', params)
                marginMode = 'cross' if (marginMode is None) else marginMode
                if marginMode == 'isolated':
                    if trigger:
                        response = self.contractPrivatePostLinearSwapApiV1SwapTriggerCancel(self.extend(request, params))
                    elif stopLossTakeProfit:
                        response = self.contractPrivatePostLinearSwapApiV1SwapTpslCancel(self.extend(request, params))
                    elif trailing:
                        response = self.contractPrivatePostLinearSwapApiV1SwapTrackCancel(self.extend(request, params))
                    else:
                        response = self.contractPrivatePostLinearSwapApiV1SwapCancel(self.extend(request, params))
                elif marginMode == 'cross':
                    if trigger:
                        response = self.contractPrivatePostLinearSwapApiV1SwapCrossTriggerCancel(self.extend(request, params))
                    elif stopLossTakeProfit:
                        response = self.contractPrivatePostLinearSwapApiV1SwapCrossTpslCancel(self.extend(request, params))
                    elif trailing:
                        response = self.contractPrivatePostLinearSwapApiV1SwapCrossTrackCancel(self.extend(request, params))
                    else:
                        response = self.contractPrivatePostLinearSwapApiV1SwapCrossCancel(self.extend(request, params))
            elif market['inverse']:
                if market['swap']:
                    if trigger:
                        response = self.contractPrivatePostSwapApiV1SwapTriggerCancel(self.extend(request, params))
                    elif stopLossTakeProfit:
                        response = self.contractPrivatePostSwapApiV1SwapTpslCancel(self.extend(request, params))
                    elif trailing:
                        response = self.contractPrivatePostSwapApiV1SwapTrackCancel(self.extend(request, params))
                    else:
                        response = self.contractPrivatePostSwapApiV1SwapCancel(self.extend(request, params))
                elif market['future']:
                    if trigger:
                        response = self.contractPrivatePostApiV1ContractTriggerCancel(self.extend(request, params))
                    elif stopLossTakeProfit:
                        response = self.contractPrivatePostApiV1ContractTpslCancel(self.extend(request, params))
                    elif trailing:
                        response = self.contractPrivatePostApiV1ContractTrackCancel(self.extend(request, params))
                    else:
                        response = self.contractPrivatePostApiV1ContractCancel(self.extend(request, params))
            else:
                raise NotSupported(self.id + ' cancelOrder() does not support ' + marketType + ' markets')
        #
        # spot
        #
        #     {
        #         "status": "ok",
        #         "data": "10138899000",
        #     }
        #
        # future and swap
        #
        #     {
        #         "status": "ok",
        #         "data": {
        #             "errors": [],
        #             "successes": "924660854912552960"
        #         },
        #         "ts": 1640504486089
        #     }
        #
        return self.extend(self.parse_order(response, market), {
            'id': id,
            'status': 'canceled',
        })

    def cancel_orders(self, ids: List[str], symbol: Str = None, params={}):
        """
        cancel multiple orders
        :param str[] ids: order ids
        :param str symbol: unified market symbol, default is None
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :param bool [params.trigger]: *contract only* if the orders are trigger trigger orders or not
        :param bool [params.stopLossTakeProfit]: *contract only* if the orders are stop-loss or take-profit orders
        :returns dict: an list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
        """
        self.load_markets()
        market: Market = None
        if symbol is not None:
            market = self.market(symbol)
        marketType = None
        marketType, params = self.handle_market_type_and_params('cancelOrders', market, params)
        request: dict = {
            # spot -----------------------------------------------------------
            # 'order-ids': ','.join(ids),  # max 50
            # 'client-order-ids': ','.join(ids),  # max 50
            # contracts ------------------------------------------------------
            # 'order_id': id,  # comma separated, max 10
            # 'client_order_id': clientOrderId,  # comma separated, max 10
            # 'contract_code': market['id'],
            # 'symbol': market['settleId'],
        }
        response = None
        if marketType == 'spot':
            clientOrderIds = self.safe_value_2(params, 'client-order-id', 'clientOrderId')
            clientOrderIds = self.safe_value_2(params, 'client-order-ids', 'clientOrderIds', clientOrderIds)
            if clientOrderIds is None:
                if isinstance(clientOrderIds, str):
                    request['order-ids'] = [ids]
                else:
                    request['order-ids'] = ids
            else:
                if isinstance(clientOrderIds, str):
                    request['client-order-ids'] = [clientOrderIds]
                else:
                    request['client-order-ids'] = clientOrderIds
                params = self.omit(params, ['client-order-id', 'client-order-ids', 'clientOrderId', 'clientOrderIds'])
            response = self.spotPrivatePostV1OrderOrdersBatchcancel(self.extend(request, params))
        else:
            if symbol is None:
                raise ArgumentsRequired(self.id + ' cancelOrders() requires a symbol argument')
            clientOrderIds = self.safe_string_2(params, 'client_order_id', 'clientOrderId')
            clientOrderIds = self.safe_string_2(params, 'client_order_ids', 'clientOrderIds', clientOrderIds)
            if clientOrderIds is None:
                request['order_id'] = ','.join(ids)
            else:
                request['client_order_id'] = clientOrderIds
                params = self.omit(params, ['client_order_id', 'client_order_ids', 'clientOrderId', 'clientOrderIds'])
            if market['future']:
                request['symbol'] = market['settleId']
            else:
                request['contract_code'] = market['id']
            trigger = self.safe_bool_2(params, 'stop', 'trigger')
            stopLossTakeProfit = self.safe_value(params, 'stopLossTakeProfit')
            params = self.omit(params, ['stop', 'stopLossTakeProfit', 'trigger'])
            if market['linear']:
                marginMode = None
                marginMode, params = self.handle_margin_mode_and_params('cancelOrders', params)
                marginMode = 'cross' if (marginMode is None) else marginMode
                if marginMode == 'isolated':
                    if trigger:
                        response = self.contractPrivatePostLinearSwapApiV1SwapTriggerCancel(self.extend(request, params))
                    elif stopLossTakeProfit:
                        response = self.contractPrivatePostLinearSwapApiV1SwapTpslCancel(self.extend(request, params))
                    else:
                        response = self.contractPrivatePostLinearSwapApiV1SwapCancel(self.extend(request, params))
                elif marginMode == 'cross':
                    if trigger:
                        response = self.contractPrivatePostLinearSwapApiV1SwapCrossTriggerCancel(self.extend(request, params))
                    elif stopLossTakeProfit:
                        response = self.contractPrivatePostLinearSwapApiV1SwapCrossTpslCancel(self.extend(request, params))
                    else:
                        response = self.contractPrivatePostLinearSwapApiV1SwapCrossCancel(self.extend(request, params))
            elif market['inverse']:
                if market['swap']:
                    if trigger:
                        response = self.contractPrivatePostSwapApiV1SwapTriggerCancel(self.extend(request, params))
                    elif stopLossTakeProfit:
                        response = self.contractPrivatePostSwapApiV1SwapTpslCancel(self.extend(request, params))
                    else:
                        response = self.contractPrivatePostSwapApiV1SwapCancel(self.extend(request, params))
                elif market['future']:
                    if trigger:
                        response = self.contractPrivatePostApiV1ContractTriggerCancel(self.extend(request, params))
                    elif stopLossTakeProfit:
                        response = self.contractPrivatePostApiV1ContractTpslCancel(self.extend(request, params))
                    else:
                        response = self.contractPrivatePostApiV1ContractCancel(self.extend(request, params))
            else:
                raise NotSupported(self.id + ' cancelOrders() does not support ' + marketType + ' markets')
        #
        # spot
        #
        #     {
        #         "status": "ok",
        #         "data": {
        #             "success": [
        #                 "5983466"
        #             ],
        #             "failed": [
        #                 {
        #                     "err-msg": "Incorrect order state",
        #                     "order-state": 7,
        #                     "order-id": "",
        #                     "err-code": "order-orderstate-error",
        #                     "client-order-id": "first"
        #                 },
        #                 {
        #                     "err-msg": "Incorrect order state",
        #                     "order-state": 7,
        #                     "order-id": "",
        #                     "err-code": "order-orderstate-error",
        #                     "client-order-id": "second"
        #                 },
        #                 {
        #                     "err-msg": "The record is not found.",
        #                     "order-id": "",
        #                     "err-code": "base-not-found",
        #                     "client-order-id": "third"
        #                 }
        #             ]
        #         }
        #     }
        #
        # future and swap
        #
        #     {
        #         "status": "ok",
        #         "data": {
        #             "errors": [
        #                 {
        #                     "order_id": "769206471845261312",
        #                     "err_code": 1061,
        #                     "err_msg": "This order doesnt exist."
        #                 }
        #             ],
        #             "successes": "773120304138219520"
        #         },
        #         "ts": 1604367997451
        #     }
        #
        data = self.safe_dict(response, 'data')
        return self.parse_cancel_orders(data)

    def parse_cancel_orders(self, orders):
        #
        #    {
        #        "success": [
        #            "5983466"
        #        ],
        #        "failed": [
        #            {
        #                "err-msg": "Incorrect order state",
        #                "order-state": 7,
        #                "order-id": "",
        #                "err-code": "order-orderstate-error",
        #                "client-order-id": "first"
        #            },
        #            ...
        #        ]
        #    }
        #
        #    {
        #        "errors": [
        #            {
        #                "order_id": "769206471845261312",
        #                "err_code": 1061,
        #                "err_msg": "This order doesnt exist."
        #            }
        #        ],
        #        "successes": "1258075374411399168,1258075393254871040"
        #    }
        #
        successes = self.safe_string(orders, 'successes')
        success = None
        if successes is not None:
            success = successes.split(',')
        else:
            success = self.safe_list(orders, 'success', [])
        failed = self.safe_list_2(orders, 'errors', 'failed', [])
        result = []
        for i in range(0, len(success)):
            order = success[i]
            result.append(self.safe_order({
                'info': order,
                'id': order,
                'status': 'canceled',
            }))
        for i in range(0, len(failed)):
            order = failed[i]
            result.append(self.safe_order({
                'info': order,
                'id': self.safe_string_2(order, 'order-id', 'order_id'),
                'status': 'failed',
                'clientOrderId': self.safe_string(order, 'client-order-id'),
            }))
        return result

    def cancel_all_orders(self, symbol: Str = None, params={}):
        """
        cancel all open orders
        :param str symbol: unified market symbol, only orders in the market of self symbol are cancelled when symbol is not None
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :param boolean [params.trigger]: *contract only* if the orders are trigger trigger orders or not
        :param boolean [params.stopLossTakeProfit]: *contract only* if the orders are stop-loss or take-profit orders
        :param boolean [params.trailing]: *contract only* set to True if you want to cancel all trailing orders
        :returns dict[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
        """
        self.load_markets()
        market = None
        if symbol is not None:
            market = self.market(symbol)
        marketType = None
        marketType, params = self.handle_market_type_and_params('cancelAllOrders', market, params)
        request: dict = {
            # spot -----------------------------------------------------------
            # 'account-id': account['id'],
            # 'symbol': market['id'],  # a list of comma-separated symbols, all symbols by default
            # 'types' 'string', buy-market, sell-market, buy-limit, sell-limit, buy-ioc, sell-ioc, buy-stop-limit, sell-stop-limit, buy-limit-fok, sell-limit-fok, buy-stop-limit-fok, sell-stop-limit-fok
            # 'side': 'buy',  # or 'sell'
            # 'size': 100,  # the number of orders to cancel 1-100
            # contract -------------------------------------------------------
            # 'symbol': market['settleId'],  # required
            # 'contract_code': market['id'],
            # 'contract_type': 'this_week',  # swap, self_week, next_week, quarter, next_ quarter
            # 'direction': 'buy':  # buy, sell
            # 'offset': 'open',  # open, close
        }
        response = None
        if marketType == 'spot':
            if symbol is not None:
                request['symbol'] = market['id']
            response = self.spotPrivatePostV1OrderOrdersBatchCancelOpenOrders(self.extend(request, params))
            #
            #     {
            #         "code": 200,
            #         "data": {
            #             "success-count": 2,
            #             "failed-count": 0,
            #             "next-id": 5454600
            #         }
            #     }
            #
            data = self.safe_dict(response, 'data')
            return [
                self.safe_order({
                    'info': data,
                }),
            ]
        else:
            if symbol is None:
                raise ArgumentsRequired(self.id + ' cancelAllOrders() requires a symbol argument')
            if market['future']:
                request['symbol'] = market['settleId']
            request['contract_code'] = market['id']
            trigger = self.safe_bool_2(params, 'stop', 'trigger')
            stopLossTakeProfit = self.safe_value(params, 'stopLossTakeProfit')
            trailing = self.safe_bool(params, 'trailing', False)
            params = self.omit(params, ['stop', 'stopLossTakeProfit', 'trailing', 'trigger'])
            if market['linear']:
                marginMode = None
                marginMode, params = self.handle_margin_mode_and_params('cancelAllOrders', params)
                marginMode = 'cross' if (marginMode is None) else marginMode
                if marginMode == 'isolated':
                    if trigger:
                        response = self.contractPrivatePostLinearSwapApiV1SwapTriggerCancelall(self.extend(request, params))
                    elif stopLossTakeProfit:
                        response = self.contractPrivatePostLinearSwapApiV1SwapTpslCancelall(self.extend(request, params))
                    elif trailing:
                        response = self.contractPrivatePostLinearSwapApiV1SwapTrackCancelall(self.extend(request, params))
                    else:
                        response = self.contractPrivatePostLinearSwapApiV1SwapCancelall(self.extend(request, params))
                elif marginMode == 'cross':
                    if trigger:
                        response = self.contractPrivatePostLinearSwapApiV1SwapCrossTriggerCancelall(self.extend(request, params))
                    elif stopLossTakeProfit:
                        response = self.contractPrivatePostLinearSwapApiV1SwapCrossTpslCancelall(self.extend(request, params))
                    elif trailing:
                        response = self.contractPrivatePostLinearSwapApiV1SwapCrossTrackCancelall(self.extend(request, params))
                    else:
                        response = self.contractPrivatePostLinearSwapApiV1SwapCrossCancelall(self.extend(request, params))
            elif market['inverse']:
                if market['swap']:
                    if trigger:
                        response = self.contractPrivatePostSwapApiV1SwapTriggerCancelall(self.extend(request, params))
                    elif stopLossTakeProfit:
                        response = self.contractPrivatePostSwapApiV1SwapTpslCancelall(self.extend(request, params))
                    elif trailing:
                        response = self.contractPrivatePostSwapApiV1SwapTrackCancelall(self.extend(request, params))
                    else:
                        response = self.contractPrivatePostSwapApiV1SwapCancelall(self.extend(request, params))
                elif market['future']:
                    if trigger:
                        response = self.contractPrivatePostApiV1ContractTriggerCancelall(self.extend(request, params))
                    elif stopLossTakeProfit:
                        response = self.contractPrivatePostApiV1ContractTpslCancelall(self.extend(request, params))
                    elif trailing:
                        response = self.contractPrivatePostApiV1ContractTrackCancelall(self.extend(request, params))
                    else:
                        response = self.contractPrivatePostApiV1ContractCancelall(self.extend(request, params))
            else:
                raise NotSupported(self.id + ' cancelAllOrders() does not support ' + marketType + ' markets')
            #
            #     {
            #         "status": "ok",
            #         "data": {
            #             "errors": [],
            #             "successes": "1104754904426696704"
            #         },
            #         "ts": "1683435723755"
            #     }
            #
            data = self.safe_dict(response, 'data')
            return self.parse_cancel_orders(data)

    def cancel_all_orders_after(self, timeout: Int, params={}):
        """
        dead man's switch, cancel all orders after the given timeout

        https://huobiapi.github.io/docs/spot/v1/en/#dead-man-s-switch

        :param number timeout: time in milliseconds, 0 represents cancel the timer
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: the api result
        """
        self.load_markets()
        request: dict = {
            'timeout': self.parse_to_int(timeout / 1000) if (timeout > 0) else 0,
        }
        response = self.v2PrivatePostAlgoOrdersCancelAllAfter(self.extend(request, params))
        #
        #     {
        #         "code": 200,
        #         "message": "success",
        #         "data": {
        #             "currentTime": 1630491627230,
        #             "triggerTime": 1630491637230
        #         }
        #     }
        #
        return response

    def parse_deposit_address(self, depositAddress, currency: Currency = None):
        #
        #     {
        #         "currency": "usdt",
        #         "address": "0xf7292eb9ba7bc50358e27f0e025a4d225a64127b",
        #         "addressTag": "",
        #         "chain": "usdterc20",  # trc20usdt, hrc20usdt, usdt, algousdt
        #     }
        #
        address = self.safe_string(depositAddress, 'address')
        tag = self.safe_string(depositAddress, 'addressTag')
        currencyId = self.safe_string(depositAddress, 'currency')
        currency = self.safe_currency(currencyId, currency)
        code = self.safe_currency_code(currencyId, currency)
        note = self.safe_string(depositAddress, 'note')
        networkId = self.safe_string(depositAddress, 'chain')
        self.check_address(address)
        return {
            'currency': code,
            'address': address,
            'tag': tag,
            'network': self.network_id_to_code(networkId),
            'note': note,
            'info': depositAddress,
        }

    def fetch_deposit_addresses_by_network(self, code: str, params={}) -> List[DepositAddress]:
        """

        https://www.htx.com/en-us/opend/newApiPages/?id=7ec50029-7773-11ed-9966-0242ac110003

        fetch a dictionary of addresses for a currency, indexed by network
        :param str code: unified currency code of the currency for the deposit address
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: a dictionary of `address structures <https://docs.ccxt.com/#/?id=address-structure>` indexed by the network
        """
        self.load_markets()
        currency = self.currency(code)
        request: dict = {
            'currency': currency['id'],
        }
        response = self.spotPrivateGetV2AccountDepositAddress(self.extend(request, params))
        #
        #     {
        #         "code": 200,
        #         "data": [
        #             {
        #                 "currency": "eth",
        #                 "address": "0xf7292eb9ba7bc50358e27f0e025a4d225a64127b",
        #                 "addressTag": "",
        #                 "chain": "eth"
        #             }
        #         ]
        #     }
        #
        data = self.safe_value(response, 'data', [])
        parsed = self.parse_deposit_addresses(data, [currency['code']], False)
        return self.index_by(parsed, 'network')

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

        https://www.htx.com/en-us/opend/newApiPages/?id=7ec50029-7773-11ed-9966-0242ac110003

        :param str code: unified currency code
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: an `address structure <https://docs.ccxt.com/#/?id=address-structure>`
        """
        self.load_markets()
        currency = self.currency(code)
        networkCode, paramsOmited = self.handle_network_code_and_params(params)
        indexedAddresses = self.fetch_deposit_addresses_by_network(code, paramsOmited)
        selectedNetworkCode = self.select_network_code_from_unified_networks(currency['code'], networkCode, indexedAddresses)
        return indexedAddresses[selectedNetworkCode]

    def fetch_withdraw_addresses(self, code: str, note=None, networkCode=None, params={}):
        self.load_markets()
        currency = self.currency(code)
        request: dict = {
            'currency': currency['id'],
        }
        response = self.spotPrivateGetV2AccountWithdrawAddress(self.extend(request, params))
        #
        #     {
        #         "code": 200,
        #         "data": [
        #             {
        #                 "currency": "eth",
        #                 "chain": "eth"
        #                 "note": "Binance - TRC20",
        #                 "addressTag": "",
        #                 "address": "0xf7292eb9ba7bc50358e27f0e025a4d225a64127b",
        #             }
        #         ]
        #     }
        #
        data = self.safe_value(response, 'data', [])
        allAddresses = self.parse_deposit_addresses(data, [currency['code']], False)  # cjg: to do remove self weird object or array ambiguity
        addresses = []
        for i in range(0, len(allAddresses)):
            address = allAddresses[i]
            noteMatch = (note is None) or (address['note'] == note)
            networkMatch = (networkCode is None) or (address['network'] == networkCode)
            if noteMatch and networkMatch:
                addresses.append(address)
        return addresses

    def fetch_deposits(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Transaction]:
        """

        https://www.htx.com/en-us/opend/newApiPages/?id=7ec4f050-7773-11ed-9966-0242ac110003

        fetch all deposits made to an account
        :param str code: unified currency code
        :param int [since]: the earliest time in ms to fetch deposits for
        :param int [limit]: the maximum number of deposits structures to retrieve
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict[]: a list of `transaction structures <https://docs.ccxt.com/#/?id=transaction-structure>`
        """
        if limit is None or limit > 100:
            limit = 100
        self.load_markets()
        currency = None
        if code is not None:
            currency = self.currency(code)
        request: dict = {
            'type': 'deposit',
            'direct': 'next',
            'from': 0,  # From 'id' ... if you want to get results after a particular transaction id, pass the id in params.from
        }
        if currency is not None:
            request['currency'] = currency['id']
        if limit is not None:
            request['size'] = limit  # max 100
        response = self.spotPrivateGetV1QueryDepositWithdraw(self.extend(request, params))
        #
        #    {
        #         "status": "ok",
        #         "data": [
        #             {
        #                 "id": "75115912",
        #                 "type": "deposit",
        #                 "sub-type": "NORMAL",
        #                 "request-id": "trc20usdt-a2e229a44ef2a948c874366230bb56aa73631cc0a03d177bd8b4c9d38262d7ff-200",
        #                 "currency": "usdt",
        #                 "chain": "trc20usdt",
        #                 "tx-hash": "a2e229a44ef2a948c874366230bb56aa73631cc0a03d177bd8b4c9d38262d7ff",
        #                 "amount": "12.000000000000000000",
        #                 "from-addr-tag": "",
        #                 "address-id": "0",
        #                 "address": "TRFTd1FxepQE6CnpwzUEMEbFaLm5bJK67s",
        #                 "address-tag": "",
        #                 "fee": "0",
        #                 "state": "safe",
        #                 "wallet-confirm": "2",
        #                 "created-at": "1621843808662",
        #                 "updated-at": "1621843857137"
        #             },
        #         ]
        #     }
        #
        return self.parse_transactions(response['data'], currency, since, limit)

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

        https://huobiapi.github.io/docs/spot/v1/en/#search-for-existed-withdraws-and-deposits

        :param str code: unified currency code
        :param int [since]: the earliest time in ms to fetch withdrawals for
        :param int [limit]: the maximum number of withdrawals structures to retrieve
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict[]: a list of `transaction structures <https://docs.ccxt.com/#/?id=transaction-structure>`
        """
        if limit is None or limit > 100:
            limit = 100
        self.load_markets()
        currency = None
        if code is not None:
            currency = self.currency(code)
        request: dict = {
            'type': 'withdraw',
            'direct': 'next',
            'from': 0,  # From 'id' ... if you want to get results after a particular transaction id, pass the id in params.from
        }
        if currency is not None:
            request['currency'] = currency['id']
        if limit is not None:
            request['size'] = limit  # max 100
        response = self.spotPrivateGetV1QueryDepositWithdraw(self.extend(request, params))
        #
        #    {
        #         "status": "ok",
        #         "data": [
        #             {
        #                 "id": "61335312",
        #                 "type": "withdraw",
        #                 "sub-type": "NORMAL",
        #                 "currency": "usdt",
        #                 "chain": "trc20usdt",
        #                 "tx-hash": "30a3111f2fead74fae45c6218ca3150fc33cab2aa59cfe41526b96aae79ce4ec",
        #                 "amount": "12.000000000000000000",
        #                 "from-addr-tag": "",
        #                 "address-id": "27321591",
        #                 "address": "TRf5JacJQRsF4Nm2zu11W6maDGeiEWQu9e",
        #                 "address-tag": "",
        #                 "fee": "1.000000000000000000",
        #                 "state": "confirmed",
        #                 "created-at": "1621852316553",
        #                 "updated-at": "1621852467041"
        #             },
        #         ]
        #     }
        #
        return self.parse_transactions(response['data'], currency, since, limit)

    def parse_transaction(self, transaction: dict, currency: Currency = None) -> Transaction:
        #
        # fetchDeposits
        #
        #     {
        #         "id": "75115912",
        #         "type": "deposit",
        #         "sub-type": "NORMAL",
        #         "request-id": "trc20usdt-a2e229a44ef2a948c874366230bb56aa73631cc0a03d177bd8b4c9d38262d7ff-200",
        #         "currency": "usdt",
        #         "chain": "trc20usdt",
        #         "tx-hash": "a2e229a44ef2a948c874366230bb56aa73631cc0a03d177bd8b4c9d38262d7ff",
        #         "amount": "2849.000000000000000000",
        #         "from-addr-tag": "",
        #         "address-id": "0",
        #         "address": "TRFTd1FxepQE6CnpwzUEMEbFaLm5bJK67s",
        #         "address-tag": "",
        #         "fee": "0",
        #         "state": "safe",
        #         "wallet-confirm": "2",
        #         "created-at": "1621843808662",
        #         "updated-at": "1621843857137"
        #     },
        #
        # fetchWithdrawals
        #
        #     {
        #         "id": "61335312",
        #         "type": "withdraw",
        #         "sub-type": "NORMAL",
        #         "currency": "usdt",
        #         "chain": "trc20usdt",
        #         "tx-hash": "30a3111f2fead74fae45c6218ca3150fc33cab2aa59cfe41526b96aae79ce4ec",
        #         "amount": "12.000000000000000000",
        #         "from-addr-tag": "",
        #         "address-id": "27321591",
        #         "address": "TRf5JacJQRsF4Nm2zu11W6maDGeiEWQu9e",
        #         "address-tag": "",
        #         "fee": "1.000000000000000000",
        #         "state": "confirmed",
        #         "created-at": "1621852316553",
        #         "updated-at": "1621852467041"
        #     }
        #
        # withdraw
        #
        #     {
        #         "status": "ok",
        #         "data": "99562054"
        #     }
        #
        timestamp = self.safe_integer(transaction, 'created-at')
        code = self.safe_currency_code(self.safe_string(transaction, 'currency'))
        type = self.safe_string(transaction, 'type')
        if type == 'withdraw':
            type = 'withdrawal'
        feeCost = self.safe_string(transaction, 'fee')
        if feeCost is not None:
            feeCost = Precise.string_abs(feeCost)
        networkId = self.safe_string(transaction, 'chain')
        txHash = self.safe_string(transaction, 'tx-hash')
        if networkId == 'ETH' and txHash.find('0x') < 0:
            txHash = '0x' + txHash
        subType = self.safe_string(transaction, 'sub-type')
        internal = subType == 'FAST'
        return {
            'info': transaction,
            'id': self.safe_string_2(transaction, 'id', 'data'),
            'txid': txHash,
            'timestamp': timestamp,
            'datetime': self.iso8601(timestamp),
            'network': self.network_id_to_code(networkId),
            'address': self.safe_string(transaction, 'address'),
            'addressTo': None,
            'addressFrom': None,
            'tag': self.safe_string(transaction, 'address-tag'),
            'tagTo': None,
            'tagFrom': None,
            'type': type,
            'amount': self.safe_number(transaction, 'amount'),
            'currency': code,
            'status': self.parse_transaction_status(self.safe_string(transaction, 'state')),
            'updated': self.safe_integer(transaction, 'updated-at'),
            'comment': None,
            'internal': internal,
            'fee': {
                'currency': code,
                'cost': self.parse_number(feeCost),
                'rate': None,
            },
        }

    def parse_transaction_status(self, status: Str):
        statuses: dict = {
            # deposit statuses
            'unknown': 'failed',
            'confirming': 'pending',
            'confirmed': 'ok',
            'safe': 'ok',
            'orphan': 'failed',
            # withdrawal statuses
            'submitted': 'pending',
            'canceled': 'canceled',
            'reexamine': 'pending',
            'reject': 'failed',
            'pass': 'pending',
            'wallet-reject': 'failed',
            # 'confirmed': 'ok',  # present in deposit statuses
            'confirm-error': 'failed',
            'repealed': 'failed',
            'wallet-transfer': 'pending',
            'pre-transfer': 'pending',
            'verifying': 'pending',
        }
        return self.safe_string(statuses, status, status)

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

        https://www.htx.com/en-us/opend/newApiPages/?id=7ec4cc41-7773-11ed-9966-0242ac110003

        make a withdrawal
        :param str code: unified currency code
        :param float amount: the amount to withdraw
        :param str address: the address to withdraw to
        :param str tag:
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: a `transaction structure <https://docs.ccxt.com/#/?id=transaction-structure>`
        """
        tag, params = self.handle_withdraw_tag_and_params(tag, params)
        self.load_markets()
        self.check_address(address)
        currency = self.currency(code)
        request: dict = {
            'address': address,  # only supports existing addresses in your withdraw address list
            'currency': currency['id'].lower(),
        }
        if tag is not None:
            request['addr-tag'] = tag  # only for XRP?
        networkCode = None
        networkCode, params = self.handle_network_code_and_params(params)
        if networkCode is not None:
            request['chain'] = self.network_code_to_id(networkCode, code)
        amount = float(self.currency_to_precision(code, amount, networkCode))
        withdrawOptions = self.safe_value(self.options, 'withdraw', {})
        if self.safe_bool(withdrawOptions, 'includeFee', False):
            fee = self.safe_number(params, 'fee')
            if fee is None:
                currencies = self.fetch_currencies()
                self.currencies = self.map_to_safe_map(self.deep_extend(self.currencies, currencies))
                targetNetwork = self.safe_value(currency['networks'], networkCode, {})
                fee = self.safe_number(targetNetwork, 'fee')
                if fee is None:
                    raise ArgumentsRequired(self.id + ' withdraw() function can not find withdraw fee for chosen network. You need to re-load markets with "exchange.loadMarkets(True)", or provide the "fee" parameter')
            # fee needs to be deducted from whole amount
            feeString = self.currency_to_precision(code, fee, networkCode)
            params = self.omit(params, 'fee')
            amountString = self.number_to_string(amount)
            amountSubtractedString = Precise.string_sub(amountString, feeString)
            amountSubtracted = float(amountSubtractedString)
            request['fee'] = float(feeString)
            amount = float(self.currency_to_precision(code, amountSubtracted, networkCode))
        request['amount'] = amount
        response = self.spotPrivatePostV1DwWithdrawApiCreate(self.extend(request, params))
        #
        #     {
        #         "status": "ok",
        #         "data": "99562054"
        #     }
        #
        return self.parse_transaction(response, currency)

    def parse_transfer(self, transfer: dict, currency: Currency = None) -> TransferEntry:
        #
        # transfer
        #
        #     {
        #         "data": 12345,
        #         "status": "ok"
        #     }
        #
        id = self.safe_string(transfer, 'data')
        code = self.safe_currency_code(None, currency)
        return {
            'info': transfer,
            'id': id,
            'timestamp': None,
            'datetime': None,
            'currency': code,
            'amount': None,
            'fromAccount': None,
            'toAccount': None,
            'status': None,
        }

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

        https://huobiapi.github.io/docs/dm/v1/en/#transfer-margin-between-spot-account-and-future-account
        https://huobiapi.github.io/docs/spot/v1/en/#transfer-fund-between-spot-account-and-future-contract-account
        https://huobiapi.github.io/docs/usdt_swap/v1/en/#general-transfer-margin-between-spot-account-and-usdt-margined-contracts-account
        https://huobiapi.github.io/docs/spot/v1/en/#transfer-asset-from-spot-trading-account-to-cross-margin-account-cross
        https://huobiapi.github.io/docs/spot/v1/en/#transfer-asset-from-spot-trading-account-to-isolated-margin-account-isolated
        https://huobiapi.github.io/docs/spot/v1/en/#transfer-asset-from-cross-margin-account-to-spot-trading-account-cross
        https://huobiapi.github.io/docs/spot/v1/en/#transfer-asset-from-isolated-margin-account-to-spot-trading-account-isolated

        :param str code: unified currency code
        :param float amount: amount to transfer
        :param str fromAccount: account to transfer from 'spot', 'future', 'swap'
        :param str toAccount: account to transfer to 'spot', 'future', 'swap'
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :param str [params.symbol]: used for isolated margin transfer
        :param str [params.subType]: 'linear' or 'inverse', only used when transfering to/from swap accounts
        :returns dict: a `transfer structure <https://docs.ccxt.com/#/?id=transfer-structure>`
        """
        self.load_markets()
        currency = self.currency(code)
        request: dict = {
            'currency': currency['id'],
            'amount': float(self.currency_to_precision(code, amount)),
        }
        subType = None
        subType, params = self.handle_sub_type_and_params('transfer', None, params)
        fromAccountId = self.convert_type_to_account(fromAccount)
        toAccountId = self.convert_type_to_account(toAccount)
        toCross = toAccountId == 'cross'
        fromCross = fromAccountId == 'cross'
        toIsolated = self.in_array(toAccountId, self.ids)
        fromIsolated = self.in_array(fromAccountId, self.ids)
        fromSpot = fromAccountId == 'pro'
        toSpot = toAccountId == 'pro'
        if fromSpot and toSpot:
            raise BadRequest(self.id + ' transfer() cannot make a transfer between ' + fromAccount + ' and ' + toAccount)
        fromOrToFuturesAccount = (fromAccountId == 'futures') or (toAccountId == 'futures')
        response = None
        if fromOrToFuturesAccount:
            type = fromAccountId + '-to-' + toAccountId
            type = self.safe_string(params, 'type', type)
            request['type'] = type
            response = self.spotPrivatePostV1FuturesTransfer(self.extend(request, params))
        elif fromSpot and toCross:
            response = self.privatePostCrossMarginTransferIn(self.extend(request, params))
        elif fromCross and toSpot:
            response = self.privatePostCrossMarginTransferOut(self.extend(request, params))
        elif fromSpot and toIsolated:
            request['symbol'] = toAccountId
            response = self.privatePostDwTransferInMargin(self.extend(request, params))
        elif fromIsolated and toSpot:
            request['symbol'] = fromAccountId
            response = self.privatePostDwTransferOutMargin(self.extend(request, params))
        else:
            if subType == 'linear':
                if (fromAccountId == 'swap') or (fromAccount == 'linear-swap'):
                    fromAccountId = 'linear-swap'
                else:
                    toAccountId = 'linear-swap'
                # check if cross-margin or isolated
                symbol = self.safe_string(params, 'symbol')
                params = self.omit(params, 'symbol')
                if symbol is not None:
                    symbol = self.market_id(symbol)
                    request['margin-account'] = symbol
                else:
                    request['margin-account'] = 'USDT'  # cross-margin
            request['from'] = 'spot' if fromSpot else fromAccountId
            request['to'] = 'spot' if toSpot else toAccountId
            response = self.v2PrivatePostAccountTransfer(self.extend(request, params))
        #
        #    {
        #        "code": "200",
        #        "data": "660150061",
        #        "message": "Succeed",
        #        "success": True,
        #        "print-log": True
        #    }
        #
        return self.parse_transfer(response, currency)

    def fetch_isolated_borrow_rates(self, params={}) -> IsolatedBorrowRates:
        """
        fetch the borrow interest rates of all currencies

        https://huobiapi.github.io/docs/spot/v1/en/#get-loan-interest-rate-and-quota-isolated

        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: a list of `isolated borrow rate structures <https://docs.ccxt.com/#/?id=isolated-borrow-rate-structure>`
        """
        self.load_markets()
        response = self.spotPrivateGetV1MarginLoanInfo(params)
        #
        # {
        #     "status": "ok",
        #     "data": [
        #         {
        #             "symbol": "1inchusdt",
        #             "currencies": [
        #                 {
        #                     "currency": "1inch",
        #                     "interest-rate": "0.00098",
        #                     "min-loan-amt": "90.000000000000000000",
        #                     "max-loan-amt": "1000.000000000000000000",
        #                     "loanable-amt": "0.0",
        #                     "actual-rate": "0.00098"
        #                 },
        #                 {
        #                     "currency": "usdt",
        #                     "interest-rate": "0.00098",
        #                     "min-loan-amt": "100.000000000000000000",
        #                     "max-loan-amt": "1000.000000000000000000",
        #                     "loanable-amt": "0.0",
        #                     "actual-rate": "0.00098"
        #                 }
        #             ]
        #         },
        #         ...
        #     ]
        # }
        #
        data = self.safe_value(response, 'data', [])
        return self.parse_isolated_borrow_rates(data)

    def parse_isolated_borrow_rate(self, info: dict, market: Market = None) -> IsolatedBorrowRate:
        #
        #     {
        #         "symbol": "1inchusdt",
        #         "currencies": [
        #             {
        #                 "currency": "1inch",
        #                 "interest-rate": "0.00098",
        #                 "min-loan-amt": "90.000000000000000000",
        #                 "max-loan-amt": "1000.000000000000000000",
        #                 "loanable-amt": "0.0",
        #                 "actual-rate": "0.00098"
        #             },
        #             {
        #                 "currency": "usdt",
        #                 "interest-rate": "0.00098",
        #                 "min-loan-amt": "100.000000000000000000",
        #                 "max-loan-amt": "1000.000000000000000000",
        #                 "loanable-amt": "0.0",
        #                 "actual-rate": "0.00098"
        #             }
        #         ]
        #     },
        #
        marketId = self.safe_string(info, 'symbol')
        symbol = self.safe_symbol(marketId, market)
        currencies = self.safe_value(info, 'currencies', [])
        baseData = self.safe_value(currencies, 0)
        quoteData = self.safe_value(currencies, 1)
        baseId = self.safe_string(baseData, 'currency')
        quoteId = self.safe_string(quoteData, 'currency')
        return {
            'symbol': symbol,
            'base': self.safe_currency_code(baseId),
            'baseRate': self.safe_number(baseData, 'actual-rate'),
            'quote': self.safe_currency_code(quoteId),
            'quoteRate': self.safe_number(quoteData, 'actual-rate'),
            'period': 86400000,
            'timestamp': None,
            'datetime': None,
            'info': info,
        }

    def fetch_funding_rate_history(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
        """

        https://huobiapi.github.io/docs/usdt_swap/v1/en/#general-query-historical-funding-rate
        https://huobiapi.github.io/docs/coin_margined_swap/v1/en/#query-historical-funding-rate

        fetches historical funding rate prices
        :param str symbol: unified symbol of the market to fetch the funding rate history for
        :param int [since]: not used by huobi, but filtered internally by ccxt
        :param int [limit]: not used by huobi, but filtered internally by ccxt
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :param boolean [params.paginate]: default False, when True will automatically paginate by calling self endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
        :returns dict[]: a list of `funding rate structures <https://docs.ccxt.com/#/?id=funding-rate-history-structure>`
        """
        if symbol is None:
            raise ArgumentsRequired(self.id + ' fetchFundingRateHistory() requires a symbol argument')
        paginate = False
        paginate, params = self.handle_option_and_params(params, 'fetchFundingRateHistory', 'paginate')
        if paginate:
            return self.fetch_paginated_call_cursor('fetchFundingRateHistory', symbol, since, limit, params, 'current_page', 'page_index', 1, 50)
        self.load_markets()
        market = self.market(symbol)
        request: dict = {
            'contract_code': market['id'],
        }
        if limit is not None:
            request['page_size'] = limit
        else:
            request['page_size'] = 50  # max
        response = None
        if market['inverse']:
            response = self.contractPublicGetSwapApiV1SwapHistoricalFundingRate(self.extend(request, params))
        elif market['linear']:
            response = self.contractPublicGetLinearSwapApiV1SwapHistoricalFundingRate(self.extend(request, params))
        else:
            raise NotSupported(self.id + ' fetchFundingRateHistory() supports inverse and linear swaps only')
        #
        # {
        #     "status": "ok",
        #     "data": {
        #         "total_page": 62,
        #         "current_page": 1,
        #         "total_size": 1237,
        #         "data": [
        #             {
        #                 "avg_premium_index": "-0.000208064395065541",
        #                 "funding_rate": "0.000100000000000000",
        #                 "realized_rate": "0.000100000000000000",
        #                 "funding_time": "1638921600000",
        #                 "contract_code": "BTC-USDT",
        #                 "symbol": "BTC",
        #                 "fee_asset": "USDT"
        #             },
        #         ]
        #     },
        #     "ts": 1638939294277
        # }
        #
        data = self.safe_value(response, 'data')
        cursor = self.safe_value(data, 'current_page')
        result = self.safe_value(data, 'data', [])
        rates = []
        for i in range(0, len(result)):
            entry = result[i]
            entry['current_page'] = cursor
            marketId = self.safe_string(entry, 'contract_code')
            symbolInner = self.safe_symbol(marketId)
            timestamp = self.safe_integer(entry, 'funding_time')
            rates.append({
                'info': entry,
                'symbol': symbolInner,
                'fundingRate': self.safe_number(entry, 'funding_rate'),
                'timestamp': timestamp,
                'datetime': self.iso8601(timestamp),
            })
        sorted = self.sort_by(rates, 'timestamp')
        return self.filter_by_symbol_since_limit(sorted, market['symbol'], since, limit)

    def parse_funding_rate(self, contract, market: Market = None) -> FundingRate:
        #
        # {
        #      "status": "ok",
        #      "data": {
        #         "estimated_rate": "0.000100000000000000",
        #         "funding_rate": "0.000100000000000000",
        #         "contract_code": "BCH-USD",
        #         "symbol": "BCH",
        #         "fee_asset": "BCH",
        #         "funding_time": "1639094400000",
        #         "next_funding_time": "1639123200000"
        #     },
        #     "ts": 1639085854775
        # }
        #
        nextFundingRate = self.safe_number(contract, 'estimated_rate')
        fundingTimestamp = self.safe_integer(contract, 'funding_time')
        nextFundingTimestamp = self.safe_integer(contract, 'next_funding_time')
        fundingTimeString = self.safe_string(contract, 'funding_time')
        nextFundingTimeString = self.safe_string(contract, 'next_funding_time')
        millisecondsInterval = Precise.string_sub(nextFundingTimeString, fundingTimeString)
        marketId = self.safe_string(contract, 'contract_code')
        symbol = self.safe_symbol(marketId, market)
        return {
            'info': contract,
            'symbol': symbol,
            'markPrice': None,
            'indexPrice': None,
            'interestRate': None,
            'estimatedSettlePrice': None,
            'timestamp': None,
            'datetime': None,
            'fundingRate': self.safe_number(contract, 'funding_rate'),
            'fundingTimestamp': fundingTimestamp,
            'fundingDatetime': self.iso8601(fundingTimestamp),
            'nextFundingRate': nextFundingRate,
            'nextFundingTimestamp': nextFundingTimestamp,
            'nextFundingDatetime': self.iso8601(nextFundingTimestamp),
            'previousFundingRate': None,
            'previousFundingTimestamp': None,
            'previousFundingDatetime': None,
            'interval': self.parse_funding_interval(millisecondsInterval),
        }

    def parse_funding_interval(self, interval):
        intervals: dict = {
            '3600000': '1h',
            '14400000': '4h',
            '28800000': '8h',
            '57600000': '16h',
            '86400000': '24h',
        }
        return self.safe_string(intervals, interval, interval)

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

        https://huobiapi.github.io/docs/coin_margined_swap/v1/en/#query-funding-rate
        https://huobiapi.github.io/docs/usdt_swap/v1/en/#general-query-funding-rate

        :param str symbol: unified market symbol
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: a `funding rate structure <https://docs.ccxt.com/#/?id=funding-rate-structure>`
        """
        self.load_markets()
        market = self.market(symbol)
        request: dict = {
            'contract_code': market['id'],
        }
        response = None
        if market['inverse']:
            response = self.contractPublicGetSwapApiV1SwapFundingRate(self.extend(request, params))
        elif market['linear']:
            response = self.contractPublicGetLinearSwapApiV1SwapFundingRate(self.extend(request, params))
        else:
            raise NotSupported(self.id + ' fetchFundingRate() supports inverse and linear swaps only')
        #
        # {
        #     "status": "ok",
        #     "data": {
        #         "estimated_rate": "0.000100000000000000",
        #         "funding_rate": "0.000100000000000000",
        #         "contract_code": "BTC-USDT",
        #         "symbol": "BTC",
        #         "fee_asset": "USDT",
        #         "funding_time": "1603699200000",
        #         "next_funding_time": "1603728000000"
        #     },
        #     "ts": 1603696494714
        # }
        #
        result = self.safe_value(response, 'data', {})
        return self.parse_funding_rate(result, market)

    def fetch_funding_rates(self, symbols: Strings = None, params={}) -> FundingRates:
        """
        fetch the funding rate for multiple markets

        https://huobiapi.github.io/docs/usdt_swap/v1/en/#general-query-a-batch-of-funding-rate
        https://huobiapi.github.io/docs/coin_margined_swap/v1/en/#query-a-batch-of-funding-rate

        :param str[]|None symbols: list of unified market symbols
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict[]: a list of `funding rate structures <https://docs.ccxt.com/#/?id=funding-rates-structure>`, indexed by market symbols
        """
        self.load_markets()
        symbols = self.market_symbols(symbols)
        defaultSubType = self.safe_string(self.options, 'defaultSubType', 'linear')
        subType = None
        subType, params = self.handle_option_and_params(params, 'fetchFundingRates', 'subType', defaultSubType)
        if symbols is not None:
            firstSymbol = self.safe_string(symbols, 0)
            market = self.market(firstSymbol)
            isLinear = market['linear']
            subType = 'linear' if isLinear else 'inverse'
        request: dict = {
            # 'contract_code': market['id'],
        }
        response = None
        if subType == 'linear':
            response = self.contractPublicGetLinearSwapApiV1SwapBatchFundingRate(self.extend(request, params))
        elif subType == 'inverse':
            response = self.contractPublicGetSwapApiV1SwapBatchFundingRate(self.extend(request, params))
        else:
            raise NotSupported(self.id + ' fetchFundingRates() not support self market type')
        #
        #     {
        #         "status": "ok",
        #         "data": [
        #             {
        #                 "estimated_rate": "0.000100000000000000",
        #                 "funding_rate": "0.000100000000000000",
        #                 "contract_code": "MANA-USDT",
        #                 "symbol": "MANA",
        #                 "fee_asset": "USDT",
        #                 "funding_time": "1643356800000",
        #                 "next_funding_time": "1643385600000",
        #                 "trade_partition":"USDT"
        #             },
        #         ],
        #         "ts": 1643346173103
        #     }
        #
        data = self.safe_value(response, 'data', [])
        return self.parse_funding_rates(data, symbols)

    def fetch_borrow_interest(self, code: Str = None, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[BorrowInterest]:
        """
        fetch the interest owed by the user for borrowing currency for margin trading

        https://huobiapi.github.io/docs/spot/v1/en/#search-past-margin-orders-cross
        https://huobiapi.github.io/docs/spot/v1/en/#search-past-margin-orders-isolated

        :param str code: unified currency code
        :param str symbol: unified market symbol when fetch interest in isolated markets
        :param int [since]: the earliest time in ms to fetch borrrow interest for
        :param int [limit]: the maximum number of structures to retrieve
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict[]: a list of `borrow interest structures <https://docs.ccxt.com/#/?id=borrow-interest-structure>`
        """
        self.load_markets()
        marginMode = None
        marginMode, params = self.handle_margin_mode_and_params('fetchBorrowInterest', params)
        marginMode = 'cross' if (marginMode is None) else marginMode
        request: dict = {}
        if since is not None:
            request['start-date'] = self.yyyymmdd(since)
        if limit is not None:
            request['size'] = limit
        market = None
        response = None
        if marginMode == 'isolated':
            if symbol is not None:
                market = self.market(symbol)
                request['symbol'] = market['id']
            response = self.privateGetMarginLoanOrders(self.extend(request, params))
        else:  # Cross
            if code is not None:
                currency = self.currency(code)
                request['currency'] = currency['id']
            response = self.privateGetCrossMarginLoanOrders(self.extend(request, params))
        #
        #    {
        #        "status":"ok",
        #        "data":[
        #            {
        #                "loan-balance":"0.100000000000000000",
        #                "interest-balance":"0.000200000000000000",
        #                "loan-amount":"0.100000000000000000",
        #                "accrued-at":1511169724531,
        #                "interest-amount":"0.000200000000000000",
        #                "filled-points":"0.2",
        #                "filled-ht":"0.2",
        #                "currency":"btc",
        #                "id":394,
        #                "state":"accrual",
        #                "account-id":17747,
        #                "user-id":119913,
        #                "created-at":1511169724531
        #            }
        #        ]
        #    }
        #
        data = self.safe_value(response, 'data')
        interest = self.parse_borrow_interests(data, market)
        return self.filter_by_currency_since_limit(interest, code, since, limit)

    def parse_borrow_interest(self, info: dict, market: Market = None) -> BorrowInterest:
        # isolated
        #    {
        #        "interest-rate":"0.000040830000000000",
        #        "user-id":35930539,
        #        "account-id":48916071,
        #        "updated-at":1649320794195,
        #        "deduct-rate":"1",
        #        "day-interest-rate":"0.000980000000000000",
        #        "hour-interest-rate":"0.000040830000000000",
        #        "loan-balance":"100.790000000000000000",
        #        "interest-balance":"0.004115260000000000",
        #        "loan-amount":"100.790000000000000000",
        #        "paid-coin":"0.000000000000000000",
        #        "accrued-at":1649320794148,
        #        "created-at":1649320794148,
        #        "interest-amount":"0.004115260000000000",
        #        "deduct-amount":"0",
        #        "deduct-currency":"",
        #        "paid-point":"0.000000000000000000",
        #        "currency":"usdt",
        #        "symbol":"ltcusdt",
        #        "id":20242721,
        #    }
        #
        # cross
        #   {
        #       "id":3416576,
        #       "user-id":35930539,
        #       "account-id":48956839,
        #       "currency":"usdt",
        #       "loan-amount":"102",
        #       "loan-balance":"102",
        #       "interest-amount":"0.00416466",
        #       "interest-balance":"0.00416466",
        #       "created-at":1649322735333,
        #       "accrued-at":1649322735382,
        #       "state":"accrual",
        #       "filled-points":"0",
        #       "filled-ht":"0"
        #   }
        #
        marketId = self.safe_string(info, 'symbol')
        marginMode = 'cross' if (marketId is None) else 'isolated'
        market = self.safe_market(marketId)
        symbol = self.safe_string(market, 'symbol')
        timestamp = self.safe_integer(info, 'accrued-at')
        return {
            'info': info,
            'symbol': symbol,
            'currency': self.safe_currency_code(self.safe_string(info, 'currency')),
            'interest': self.safe_number(info, 'interest-amount'),
            'interestRate': self.safe_number(info, 'interest-rate'),
            'amountBorrowed': self.safe_number(info, 'loan-amount'),
            'marginMode': marginMode,
            'timestamp': timestamp,  # Interest accrued time
            'datetime': self.iso8601(timestamp),
        }

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

    def sign(self, path, api='public', method='GET', params={}, headers=None, body=None):
        url = '/'
        query = self.omit(params, self.extract_params(path))
        if isinstance(api, str):
            # signing implementation for the old endpoints
            if (api == 'public') or (api == 'private'):
                url += self.version
            elif (api == 'v2Public') or (api == 'v2Private'):
                url += 'v2'
            url += '/' + self.implode_params(path, params)
            if api == 'private' or api == 'v2Private':
                self.check_required_credentials()
                timestamp = self.ymdhms(self.nonce(), 'T')
                request: dict = {
                    'SignatureMethod': 'HmacSHA256',
                    'SignatureVersion': '2',
                    'AccessKeyId': self.apiKey,
                    'Timestamp': timestamp,
                }
                if method != 'POST':
                    request = self.extend(request, query)
                sortedRequest = self.keysort(request)
                auth = self.urlencode(sortedRequest, True)  # True is a go only requirment
                # unfortunately, PHP demands double quotes for the escaped newline symbol
                payload = "\n".join([method, self.hostname, url, auth])  # eslint-disable-line quotes
                signature = self.hmac(self.encode(payload), self.encode(self.secret), hashlib.sha256, 'base64')
                auth += '&' + self.urlencode({'Signature': signature})
                url += '?' + auth
                if method == 'POST':
                    body = self.json(query)
                    headers = {
                        'Content-Type': 'application/json',
                    }
                else:
                    headers = {
                        'Content-Type': 'application/x-www-form-urlencoded',
                    }
            else:
                if query:
                    url += '?' + self.urlencode(query)
            url = self.implode_params(self.urls['api'][api], {
                'hostname': self.hostname,
            }) + url
        else:
            # signing implementation for the new endpoints
            # type, access = api
            type = self.safe_string(api, 0)
            access = self.safe_string(api, 1)
            levelOneNestedPath = self.safe_string(api, 2)
            levelTwoNestedPath = self.safe_string(api, 3)
            hostname = None
            hostnames = self.safe_value(self.urls['hostnames'], type)
            if not isinstance(hostnames, str):
                hostnames = self.safe_value(hostnames, levelOneNestedPath)
                if (not isinstance(hostnames, str)) and (levelTwoNestedPath is not None):
                    hostnames = self.safe_value(hostnames, levelTwoNestedPath)
            hostname = hostnames
            url += self.implode_params(path, params)
            if access == 'public':
                if query:
                    url += '?' + self.urlencode(query)
            elif access == 'private':
                self.check_required_credentials()
                if method == 'POST':
                    options = self.safe_value(self.options, 'broker', {})
                    id = self.safe_string(options, 'id', 'AA03022abc')
                    if path.find('cancel') == -1 and path.endswith('order'):
                        # swap order placement
                        channelCode = self.safe_string(params, 'channel_code')
                        if channelCode is None:
                            params['channel_code'] = id
                    elif path.endswith('orders/place'):
                        # spot order placement
                        clientOrderId = self.safe_string(params, 'client-order-id')
                        if clientOrderId is None:
                            params['client-order-id'] = id + self.uuid()
                timestamp = self.ymdhms(self.nonce(), 'T')
                request: dict = {
                    'SignatureMethod': 'HmacSHA256',
                    'SignatureVersion': '2',
                    'AccessKeyId': self.apiKey,
                    'Timestamp': timestamp,
                }
                # sorting needs such flow exactly, before urlencoding(more at: https://github.com/ccxt/ccxt/issues/24930 )
                request = self.keysort(request)
                if method != 'POST':
                    sortedQuery = self.keysort(query)
                    request = self.extend(request, sortedQuery)
                auth = self.urlencode(request, True).replace('%2c', '%2C')  # in c# it manually needs to be uppercased
                # unfortunately, PHP demands double quotes for the escaped newline symbol
                payload = "\n".join([method, hostname, url, auth])  # eslint-disable-line quotes
                signature = self.hmac(self.encode(payload), self.encode(self.secret), hashlib.sha256, 'base64')
                auth += '&' + self.urlencode({'Signature': signature})
                url += '?' + auth
                if method == 'POST':
                    body = self.json(query)
                    if len(body) == 2:
                        body = '{}'
                    headers = {
                        'Content-Type': 'application/json',
                    }
                else:
                    headers = {
                        'Content-Type': 'application/x-www-form-urlencoded',
                    }
            url = self.implode_params(self.urls['api'][type], {
                'hostname': hostname,
            }) + url
        return {'url': url, 'method': method, 'body': body, 'headers': headers}

    def handle_errors(self, httpCode: int, reason: str, url: str, method: str, headers: dict, body: str, response, requestHeaders, requestBody):
        if response is None:
            return None  # fallback to default error handler
        if 'status' in response:
            #
            #     {"status":"error","err-code":"order-limitorder-amount-min-error","err-msg":"limit order amount error, min: `0.001`","data":null}
            #     {"status":"ok","data":{"errors":[{"order_id":"1349442392365359104","err_code":1061,"err_msg":"The order does not exist."}],"successes":""},"ts":1741773744526}
            #
            status = self.safe_string(response, 'status')
            if status == 'error':
                code = self.safe_string_2(response, 'err-code', 'err_code')
                feedback = self.id + ' ' + body
                self.throw_broadly_matched_exception(self.exceptions['broad'], body, feedback)
                self.throw_exactly_matched_exception(self.exceptions['exact'], code, feedback)
                message = self.safe_string_2(response, 'err-msg', 'err_msg')
                self.throw_exactly_matched_exception(self.exceptions['exact'], message, feedback)
                raise ExchangeError(feedback)
        if 'code' in response:
            # {code: '1003', message: 'invalid signature'}
            feedback = self.id + ' ' + body
            code = self.safe_string(response, 'code')
            self.throw_exactly_matched_exception(self.exceptions['exact'], code, feedback)
        data = self.safe_dict(response, 'data')
        errorsList = self.safe_list(data, 'errors')
        if errorsList is not None:
            first = self.safe_dict(errorsList, 0)
            errcode = self.safe_string(first, 'err_code')
            errmessage = self.safe_string(first, 'err_msg')
            feedBack = self.id + ' ' + body
            self.throw_exactly_matched_exception(self.exceptions['exact'], errcode, feedBack)
            self.throw_exactly_matched_exception(self.exceptions['exact'], errmessage, feedBack)
        return None

    def fetch_funding_history(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
        """
        fetch the history of funding payments paid and received on self account

        https://huobiapi.github.io/docs/usdt_swap/v1/en/#general-query-account-financial-records-via-multiple-fields-new   # linear swaps
        https://huobiapi.github.io/docs/dm/v1/en/#query-financial-records-via-multiple-fields-new                          # coin-m futures
        https://huobiapi.github.io/docs/coin_margined_swap/v1/en/#query-financial-records-via-multiple-fields-new          # coin-m swaps

        :param str 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 dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: a `funding history structure <https://docs.ccxt.com/#/?id=funding-history-structure>`
        """
        self.load_markets()
        market = self.market(symbol)
        marketType, query = self.handle_market_type_and_params('fetchFundingHistory', market, params)
        request: dict = {
            'type': '30,31',
        }
        if since is not None:
            request['start_date'] = since
        response = None
        if marketType == 'swap':
            request['contract'] = market['id']
            if market['linear']:
                #
                #    {
                #        "status": "ok",
                #        "data": {
                #           "financial_record": [
                #               {
                #                   "id": "1320088022",
                #                   "type": "30",
                #                   "amount": "0.004732510000000000",
                #                   "ts": "1641168019321",
                #                   "contract_code": "BTC-USDT",
                #                   "asset": "USDT",
                #                   "margin_account": "BTC-USDT",
                #                   "face_margin_account": ''
                #               },
                #           ],
                #           "remain_size": "0",
                #           "next_id": null
                #        },
                #        "ts": "1641189898425"
                #    }
                #
                marginMode = None
                marginMode, params = self.handle_margin_mode_and_params('fetchFundingHistory', params)
                marginMode = 'cross' if (marginMode is None) else marginMode
                if marginMode == 'isolated':
                    request['mar_acct'] = market['id']
                else:
                    request['mar_acct'] = market['quoteId']
                response = self.contractPrivatePostLinearSwapApiV3SwapFinancialRecordExact(self.extend(request, query))
            else:
                #
                #     {
                #         "code": 200,
                #         "msg": "",
                #         "data": [
                #             {
                #                 "query_id": 138798248,
                #                 "id": 117840,
                #                 "type": 5,
                #                 "amount": -0.024464850000000000,
                #                 "ts": 1638758435635,
                #                 "contract_code": "BTC-USDT-211210",
                #                 "asset": "USDT",
                #                 "margin_account": "USDT",
                #                 "face_margin_account": ""
                #             }
                #         ],
                #         "ts": 1604312615051
                #     }
                #
                response = self.contractPrivatePostSwapApiV3SwapFinancialRecordExact(self.extend(request, query))
        else:
            request['symbol'] = market['id']
            response = self.contractPrivatePostApiV3ContractFinancialRecordExact(self.extend(request, query))
        data = self.safe_list(response, 'data', [])
        return self.parse_incomes(data, market, since, limit)

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

        https://huobiapi.github.io/docs/usdt_swap/v1/en/#isolated-switch-leverage
        https://huobiapi.github.io/docs/usdt_swap/v1/en/#cross-switch-leverage
        https://huobiapi.github.io/docs/coin_margined_swap/v1/en/#switch-leverage
        https://huobiapi.github.io/docs/dm/v1/en/#switch-leverage  # Coin-m futures

        :param float leverage: the rate of leverage
        :param str symbol: unified market symbol
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: response from the exchange
        """
        if symbol is None:
            raise ArgumentsRequired(self.id + ' setLeverage() requires a symbol argument')
        self.load_markets()
        market = self.market(symbol)
        marketType, query = self.handle_market_type_and_params('setLeverage', market, params)
        request: dict = {
            'lever_rate': leverage,
        }
        if marketType == 'future' and market['inverse']:
            request['symbol'] = market['settleId']
        else:
            request['contract_code'] = market['id']
        response = None
        if market['linear']:
            marginMode = None
            marginMode, params = self.handle_margin_mode_and_params('setLeverage', params)
            marginMode = 'cross' if (marginMode is None) else marginMode
            if marginMode == 'isolated':
                response = self.contractPrivatePostLinearSwapApiV1SwapSwitchLeverRate(self.extend(request, query))
            elif marginMode == 'cross':
                response = self.contractPrivatePostLinearSwapApiV1SwapCrossSwitchLeverRate(self.extend(request, query))
            else:
                raise NotSupported(self.id + ' setLeverage() not support self market type')
            #
            #     {
            #       "status": "ok",
            #       "data": {
            #         "contract_code": "BTC-USDT",
            #         "lever_rate": "100",
            #         "margin_mode": "isolated"
            #       },
            #       "ts": "1641184710649"
            #     }
            #
        else:
            if marketType == 'future':
                response = self.contractPrivatePostApiV1ContractSwitchLeverRate(self.extend(request, query))
            elif marketType == 'swap':
                response = self.contractPrivatePostSwapApiV1SwapSwitchLeverRate(self.extend(request, query))
            else:
                raise NotSupported(self.id + ' setLeverage() not support self market type')
            #
            # future
            #     {
            #       "status": "ok",
            #       "data": {symbol: "BTC", lever_rate: 5},
            #       "ts": 1641184578678
            #     }
            #
            # swap
            #
            #     {
            #       "status": "ok",
            #       "data": {contract_code: "BTC-USD", lever_rate: "5"},
            #       "ts": "1641184652979"
            #     }
            #
        return response

    def parse_income(self, income, market: Market = None):
        #
        #     {
        #       "id": "1667161118",
        #       "symbol": "BTC",
        #       "type": "31",
        #       "amount": "-2.11306593188E-7",
        #       "ts": "1641139308983",
        #       "contract_code": "BTC-USD"
        #     }
        #
        marketId = self.safe_string(income, 'contract_code')
        symbol = self.safe_symbol(marketId, market)
        amount = self.safe_number(income, 'amount')
        timestamp = self.safe_integer(income, 'ts')
        id = self.safe_string(income, 'id')
        currencyId = self.safe_string_2(income, 'symbol', 'asset')
        code = self.safe_currency_code(currencyId)
        return {
            'info': income,
            'symbol': symbol,
            'code': code,
            'timestamp': timestamp,
            'datetime': self.iso8601(timestamp),
            'id': id,
            'amount': amount,
        }

    def parse_position(self, position: dict, market: Market = None):
        #
        #    {
        #        "symbol": "BTC",
        #        "contract_code": "BTC-USDT",
        #        "volume": "1.000000000000000000",
        #        "available": "1.000000000000000000",
        #        "frozen": "0E-18",
        #        "cost_open": "47162.000000000000000000",
        #        "cost_hold": "47151.300000000000000000",
        #        "profit_unreal": "0.007300000000000000",
        #        "profit_rate": "-0.000144183876850008",
        #        "lever_rate": "2",
        #        "position_margin": "23.579300000000000000",
        #        "direction": "buy",
        #        "profit": "-0.003400000000000000",
        #        "last_price": "47158.6",
        #        "margin_asset": "USDT",
        #        "margin_mode": "isolated",
        #        "margin_account": "BTC-USDT",
        #        "margin_balance": "24.973020070000000000",
        #        "margin_position": "23.579300000000000000",
        #        "margin_frozen": "0",
        #        "margin_available": "1.393720070000000000",
        #        "profit_real": "0E-18",
        #        "risk_rate": "1.044107779705080303",
        #        "withdraw_available": "1.386420070000000000000000000000000000",
        #        "liquidation_price": "22353.229148614609571788",
        #        "adjust_factor": "0.015000000000000000",
        #        "margin_static": "24.965720070000000000"
        #    }
        #
        market = self.safe_market(self.safe_string(position, 'contract_code'))
        symbol = market['symbol']
        contracts = self.safe_string(position, 'volume')
        contractSize = self.safe_value(market, 'contractSize')
        contractSizeString = self.number_to_string(contractSize)
        entryPrice = self.safe_number(position, 'cost_open')
        initialMargin = self.safe_string(position, 'position_margin')
        rawSide = self.safe_string(position, 'direction')
        side = 'long' if (rawSide == 'buy') else 'short'
        unrealizedProfit = self.safe_number(position, 'profit_unreal')
        marginMode = self.safe_string(position, 'margin_mode')
        leverage = self.safe_string(position, 'lever_rate')
        percentage = Precise.string_mul(self.safe_string(position, 'profit_rate'), '100')
        lastPrice = self.safe_string(position, 'last_price')
        faceValue = Precise.string_mul(contracts, contractSizeString)
        notional = None
        if market['linear']:
            notional = Precise.string_mul(faceValue, lastPrice)
        else:
            notional = Precise.string_div(faceValue, lastPrice)
            marginMode = 'cross'
        intialMarginPercentage = Precise.string_div(initialMargin, notional)
        collateral = self.safe_string(position, 'margin_balance')
        liquidationPrice = self.safe_number(position, 'liquidation_price')
        adjustmentFactor = self.safe_string(position, 'adjust_factor')
        maintenanceMarginPercentage = Precise.string_div(adjustmentFactor, leverage)
        maintenanceMargin = Precise.string_mul(maintenanceMarginPercentage, notional)
        marginRatio = Precise.string_div(maintenanceMargin, collateral)
        return self.safe_position({
            'info': position,
            'id': None,
            'symbol': symbol,
            'contracts': self.parse_number(contracts),
            'contractSize': contractSize,
            'entryPrice': entryPrice,
            'collateral': self.parse_number(collateral),
            'side': side,
            'unrealizedPnl': unrealizedProfit,
            'leverage': self.parse_number(leverage),
            'percentage': self.parse_number(percentage),
            'marginMode': marginMode,
            'notional': self.parse_number(notional),
            'markPrice': None,
            'lastPrice': None,
            'liquidationPrice': liquidationPrice,
            'initialMargin': self.parse_number(initialMargin),
            'initialMarginPercentage': self.parse_number(intialMarginPercentage),
            'maintenanceMargin': self.parse_number(maintenanceMargin),
            'maintenanceMarginPercentage': self.parse_number(maintenanceMarginPercentage),
            'marginRatio': self.parse_number(marginRatio),
            'timestamp': None,
            'datetime': None,
            'hedged': None,
            'lastUpdateTimestamp': None,
            'stopLossPrice': None,
            'takeProfitPrice': None,
        })

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

        https://huobiapi.github.io/docs/usdt_swap/v1/en/#cross-query-user-39-s-position-information
        https://huobiapi.github.io/docs/usdt_swap/v1/en/#isolated-query-user-s-position-information
        https://huobiapi.github.io/docs/coin_margined_swap/v1/en/#query-user-s-position-information
        https://huobiapi.github.io/docs/dm/v1/en/#query-user-s-position-information

        :param str[] [symbols]: list of unified market symbols
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :param str [params.subType]: 'linear' or 'inverse'
        :param str [params.type]: *inverse only* 'future', or 'swap'
        :param str [params.marginMode]: *linear only* 'cross' or 'isolated'
        :returns dict[]: a list of `position structure <https://docs.ccxt.com/#/?id=position-structure>`
        """
        self.load_markets()
        symbols = self.market_symbols(symbols)
        market = None
        if symbols is not None:
            symbolsLength = len(symbols)
            if symbolsLength > 0:
                first = self.safe_string(symbols, 0)
                market = self.market(first)
        marginMode = None
        marginMode, params = self.handle_margin_mode_and_params('fetchPositions', params, 'cross')
        subType = None
        subType, params = self.handle_sub_type_and_params('fetchPositions', market, params, 'linear')
        marketType = None
        marketType, params = self.handle_market_type_and_params('fetchPositions', market, params)
        if marketType == 'spot':
            marketType = 'future'
        response = None
        if subType == 'linear':
            if marginMode == 'isolated':
                response = self.contractPrivatePostLinearSwapApiV1SwapPositionInfo(params)
            elif marginMode == 'cross':
                response = self.contractPrivatePostLinearSwapApiV1SwapCrossPositionInfo(params)
            else:
                raise NotSupported(self.id + ' fetchPositions() not support self market type')
            #
            #     {
            #       "status": "ok",
            #       "data": [
            #         {
            #           "symbol": "BTC",
            #           "contract_code": "BTC-USDT",
            #           "volume": "1.000000000000000000",
            #           "available": "1.000000000000000000",
            #           "frozen": "0E-18",
            #           "cost_open": "47162.000000000000000000",
            #           "cost_hold": "47162.000000000000000000",
            #           "profit_unreal": "0.047300000000000000",
            #           "profit_rate": "0.002005852169119206",
            #           "lever_rate": "2",
            #           "position_margin": "23.604650000000000000",
            #           "direction": "buy",
            #           "profit": "0.047300000000000000",
            #           "last_price": "47209.3",
            #           "margin_asset": "USDT",
            #           "margin_mode": "isolated",
            #           "margin_account": "BTC-USDT"
            #         }
            #       ],
            #       "ts": "1641108676768"
            #     }
            #
        else:
            if marketType == 'future':
                response = self.contractPrivatePostApiV1ContractPositionInfo(params)
            elif marketType == 'swap':
                response = self.contractPrivatePostSwapApiV1SwapPositionInfo(params)
            else:
                raise NotSupported(self.id + ' fetchPositions() not support self market type')
            #
            # future
            #     {
            #       "status": "ok",
            #       "data": [
            #         {
            #           "symbol": "BTC",
            #           "contract_code": "BTC220624",
            #           "contract_type": "next_quarter",
            #           "volume": "1.000000000000000000",
            #           "available": "1.000000000000000000",
            #           "frozen": "0E-18",
            #           "cost_open": "49018.880000000009853343",
            #           "cost_hold": "49018.880000000009853343",
            #           "profit_unreal": "-8.62360608500000000000000000000000000000000000000E-7",
            #           "profit_rate": "-0.000845439023678622",
            #           "lever_rate": "2",
            #           "position_margin": "0.001019583964880634",
            #           "direction": "sell",
            #           "profit": "-8.62360608500000000000000000000000000000000000000E-7",
            #           "last_price": "49039.61"
            #         }
            #       ],
            #       "ts": "1641109895199"
            #     }
            #
            # swap
            #     {
            #       "status": "ok",
            #       "data": [
            #         {
            #           "symbol": "BTC",
            #           "contract_code": "BTC-USD",
            #           "volume": "1.000000000000000000",
            #           "available": "1.000000000000000000",
            #           "frozen": "0E-18",
            #           "cost_open": "47150.000000000012353300",
            #           "cost_hold": "47150.000000000012353300",
            #           "profit_unreal": "0E-54",
            #           "profit_rate": "-7.86E-16",
            #           "lever_rate": "3",
            #           "position_margin": "0.000706963591375044",
            #           "direction": "buy",
            #           "profit": "0E-54",
            #           "last_price": "47150"
            #         }
            #       ],
            #       "ts": "1641109636572"
            #     }
            #
        data = self.safe_value(response, 'data', [])
        timestamp = self.safe_integer(response, 'ts')
        result = []
        for i in range(0, len(data)):
            position = data[i]
            parsed = self.parse_position(position)
            result.append(self.extend(parsed, {
                'timestamp': timestamp,
                'datetime': self.iso8601(timestamp),
            }))
        return self.filter_by_array_positions(result, 'symbol', symbols, False)

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

        https://huobiapi.github.io/docs/usdt_swap/v1/en/#cross-query-assets-and-positions
        https://huobiapi.github.io/docs/usdt_swap/v1/en/#isolated-query-assets-and-positions
        https://huobiapi.github.io/docs/coin_margined_swap/v1/en/#query-assets-and-positions
        https://huobiapi.github.io/docs/dm/v1/en/#query-assets-and-positions

        :param str symbol: unified market symbol of the market the position is held in, default is None
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: a `position structure <https://docs.ccxt.com/#/?id=position-structure>`
        """
        self.load_markets()
        market = self.market(symbol)
        marginMode = None
        marginMode, params = self.handle_margin_mode_and_params('fetchPosition', params)
        marginMode = 'cross' if (marginMode is None) else marginMode
        marketType, query = self.handle_market_type_and_params('fetchPosition', market, params)
        request: dict = {}
        if market['future'] and market['inverse']:
            request['symbol'] = market['settleId']
        else:
            if marginMode == 'cross':
                request['margin_account'] = 'USDT'  # only allowed value
            request['contract_code'] = market['id']
        response = None
        if market['linear']:
            if marginMode == 'isolated':
                response = self.contractPrivatePostLinearSwapApiV1SwapAccountPositionInfo(self.extend(request, query))
            elif marginMode == 'cross':
                response = self.contractPrivatePostLinearSwapApiV1SwapCrossAccountPositionInfo(self.extend(request, query))
            else:
                raise NotSupported(self.id + ' fetchPosition() not support self market type')
            #
            # isolated
            #
            #     {
            #         "status": "ok",
            #         "data": [
            #             {
            #                 "positions": [],
            #                 "symbol": "BTC",
            #                 "margin_balance": 1.949728350000000000,
            #                 "margin_position": 0,
            #                 "margin_frozen": 0E-18,
            #                 "margin_available": 1.949728350000000000,
            #                 "profit_real": -0.050271650000000000,
            #                 "profit_unreal": 0,
            #                 "risk_rate": null,
            #                 "withdraw_available": 1.949728350000000000,
            #                 "liquidation_price": null,
            #                 "lever_rate": 20,
            #                 "adjust_factor": 0.150000000000000000,
            #                 "margin_static": 1.949728350000000000,
            #                 "contract_code": "BTC-USDT",
            #                 "margin_asset": "USDT",
            #                 "margin_mode": "isolated",
            #                 "margin_account": "BTC-USDT",
            #                 "trade_partition": "USDT",
            #                 "position_mode": "dual_side"
            #             },
            #             ... opposite side position can be present here too(if hedge)
            #         ],
            #         "ts": 1653605008286
            #     }
            #
            # cross
            #
            #     {
            #         "status": "ok",
            #         "data": {
            #             "positions": [
            #                 {
            #                     "symbol": "BTC",
            #                     "contract_code": "BTC-USDT",
            #                     "volume": "1.000000000000000000",
            #                     "available": "1.000000000000000000",
            #                     "frozen": "0E-18",
            #                     "cost_open": "29530.000000000000000000",
            #                     "cost_hold": "29530.000000000000000000",
            #                     "profit_unreal": "-0.010000000000000000",
            #                     "profit_rate": "-0.016931933626820200",
            #                     "lever_rate": "50",
            #                     "position_margin": "0.590400000000000000",
            #                     "direction": "buy",
            #                     "profit": "-0.010000000000000000",
            #                     "last_price": "29520",
            #                     "margin_asset": "USDT",
            #                     "margin_mode": "cross",
            #                     "margin_account": "USDT",
            #                     "contract_type": "swap",
            #                     "pair": "BTC-USDT",
            #                     "business_type": "swap",
            #                     "trade_partition": "USDT",
            #                     "position_mode": "dual_side"
            #                 },
            #                 ... opposite side position can be present here too(if hedge)
            #             ],
            #             "futures_contract_detail": [
            #                 {
            #                     "symbol": "BTC",
            #                     "contract_code": "BTC-USDT-220624",
            #                     "margin_position": "0",
            #                     "margin_frozen": "0E-18",
            #                     "margin_available": "1.497799766913531118",
            #                     "profit_unreal": "0",
            #                     "liquidation_price": null,
            #                     "lever_rate": "30",
            #                     "adjust_factor": "0.250000000000000000",
            #                     "contract_type": "quarter",
            #                     "pair": "BTC-USDT",
            #                     "business_type": "futures",
            #                     "trade_partition": "USDT"
            #                 },
            #                 ... other items listed with different expiration(contract_code)
            #             ],
            #             "margin_mode": "cross",
            #             "margin_account": "USDT",
            #             "margin_asset": "USDT",
            #             "margin_balance": "2.088199766913531118",
            #             "margin_static": "2.098199766913531118",
            #             "margin_position": "0.590400000000000000",
            #             "margin_frozen": "0E-18",
            #             "profit_real": "-0.016972710000000000",
            #             "profit_unreal": "-0.010000000000000000",
            #             "withdraw_available": "1.497799766913531118",
            #             "risk_rate": "9.105496355562965147",
            #             "contract_detail": [
            #                {
            #                     "symbol": "BTC",
            #                     "contract_code": "BTC-USDT",
            #                     "margin_position": "0.590400000000000000",
            #                     "margin_frozen": "0E-18",
            #                     "margin_available": "1.497799766913531118",
            #                     "profit_unreal": "-0.010000000000000000",
            #                     "liquidation_price": "27625.176468365024050352",
            #                     "lever_rate": "50",
            #                     "adjust_factor": "0.350000000000000000",
            #                     "contract_type": "swap",
            #                     "pair": "BTC-USDT",
            #                     "business_type": "swap",
            #                     "trade_partition": "USDT"
            #                 },
            #                 ... all symbols listed
            #             ],
            #             "position_mode": "dual_side"
            #         },
            #         "ts": "1653604697466"
            #     }
            #
        else:
            if marketType == 'future':
                response = self.contractPrivatePostApiV1ContractAccountPositionInfo(self.extend(request, query))
            elif marketType == 'swap':
                response = self.contractPrivatePostSwapApiV1SwapAccountPositionInfo(self.extend(request, query))
            else:
                raise NotSupported(self.id + ' setLeverage() not support self market type')
            #
            # future, swap
            #
            #     {
            #       "status": "ok",
            #       "data": [
            #         {
            #             "symbol": "XRP",
            #             "contract_code": "XRP-USD",  # only present in swap
            #             "margin_balance": 12.186361450698276582,
            #             "margin_position": 5.036261079774375503,
            #             "margin_frozen": 0E-18,
            #             "margin_available": 7.150100370923901079,
            #             "profit_real": -0.012672343876723438,
            #             "profit_unreal": 0.163382354575000020,
            #             "risk_rate": 2.344723929650649798,
            #             "withdraw_available": 6.986718016348901059,
            #             "liquidation_price": 0.271625200493799547,
            #             "lever_rate": 5,
            #             "adjust_factor": 0.075000000000000000,
            #             "margin_static": 12.022979096123276562,
            #             "positions": [
            #                 {
            #                     "symbol": "XRP",
            #                     "contract_code": "XRP-USD",
            #                     # "contract_type": "self_week",  # only present in future
            #                     "volume": 1.0,
            #                     "available": 1.0,
            #                     "frozen": 0E-18,
            #                     "cost_open": 0.394560000000000000,
            #                     "cost_hold": 0.394560000000000000,
            #                     "profit_unreal": 0.163382354575000020,
            #                     "profit_rate": 0.032232070910556005,
            #                     "lever_rate": 5,
            #                     "position_margin": 5.036261079774375503,
            #                     "direction": "buy",
            #                     "profit": 0.163382354575000020,
            #                     "last_price": 0.39712
            #                 },
            #                 ... opposite side position can be present here too(if hedge)
            #             ]
            #         }
            #       ],
            #       "ts": 1653600470199
            #     }
            #
            # cross usdt swap
            #
            #     {
            #         "status":"ok",
            #         "data":{
            #             "positions":[],
            #             "futures_contract_detail":[]
            #             "margin_mode":"cross",
            #             "margin_account":"USDT",
            #             "margin_asset":"USDT",
            #             "margin_balance":"1.000000000000000000",
            #             "margin_static":"1.000000000000000000",
            #             "margin_position":"0",
            #             "margin_frozen":"1.000000000000000000",
            #             "profit_real":"0E-18",
            #             "profit_unreal":"0",
            #             "withdraw_available":"0",
            #             "risk_rate":"15.666666666666666666",
            #             "contract_detail":[]
            #         },
            #         "ts":"1645521118946"
            #     }
            #
        data = self.safe_value(response, 'data')
        account = None
        if marginMode == 'cross':
            account = data
        else:
            account = self.safe_value(data, 0)
        omitted = self.omit(account, ['positions'])
        positions = self.safe_value(account, 'positions')
        position = None
        if market['future'] and market['inverse']:
            for i in range(0, len(positions)):
                entry = positions[i]
                if entry['contract_code'] == market['id']:
                    position = entry
                    break
        else:
            position = self.safe_value(positions, 0)
        timestamp = self.safe_integer(response, 'ts')
        parsed = self.parse_position(self.extend(position, omitted))
        parsed['timestamp'] = timestamp
        parsed['datetime'] = self.iso8601(timestamp)
        return parsed

    def parse_ledger_entry_type(self, type):
        types: dict = {
            'trade': 'trade',
            'etf': 'trade',
            'transact-fee': 'fee',
            'fee-deduction': 'fee',
            'transfer': 'transfer',
            'credit': 'credit',
            'liquidation': 'trade',
            'interest': 'credit',
            'deposit': 'deposit',
            'withdraw': 'withdrawal',
            'withdraw-fee': 'fee',
            'exchange': 'exchange',
            'other-types': 'transfer',
            'rebate': 'rebate',
        }
        return self.safe_string(types, type, type)

    def parse_ledger_entry(self, item: dict, currency: Currency = None) -> LedgerEntry:
        #
        #     {
        #         "accountId": 10000001,
        #         "currency": "usdt",
        #         "transactAmt": 10.000000000000000000,
        #         "transactType": "transfer",
        #         "transferType": "margin-transfer-out",
        #         "transactId": 0,
        #         "transactTime": 1629882331066,
        #         "transferer": 28483123,
        #         "transferee": 13496526
        #     }
        #
        currencyId = self.safe_string(item, 'currency')
        code = self.safe_currency_code(currencyId, currency)
        currency = self.safe_currency(currencyId, currency)
        id = self.safe_string(item, 'transactId')
        transferType = self.safe_string(item, 'transferType')
        timestamp = self.safe_integer(item, 'transactTime')
        account = self.safe_string(item, 'accountId')
        return self.safe_ledger_entry({
            'info': item,
            'id': id,
            'direction': self.safe_string(item, 'direction'),
            'account': account,
            'referenceId': id,
            'referenceAccount': account,
            'type': self.parse_ledger_entry_type(transferType),
            'currency': code,
            'amount': self.safe_number(item, 'transactAmt'),
            'timestamp': timestamp,
            'datetime': self.iso8601(timestamp),
            'before': None,
            'after': None,
            'status': None,
            'fee': None,
        }, currency)

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

        https://huobiapi.github.io/docs/spot/v1/en/#get-account-history

        :param str [code]: unified currency code, default is None
        :param int [since]: timestamp in ms of the earliest ledger entry, default is None
        :param int [limit]: max number of ledger entries to return, default is None
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :param int [params.until]: the latest time in ms to fetch entries for
        :param boolean [params.paginate]: default False, when True will automatically paginate by calling self endpoint multiple times. See in the docs all the [available parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
        :returns dict: a `ledger structure <https://docs.ccxt.com/#/?id=ledger>`
        """
        self.load_markets()
        paginate = False
        paginate, params = self.handle_option_and_params(params, 'fetchLedger', 'paginate')
        if paginate:
            return self.fetch_paginated_call_dynamic('fetchLedger', code, since, limit, params, 500)
        accountId = self.fetch_account_id_by_type('spot', None, None, params)
        request: dict = {
            'accountId': accountId,
            # 'currency': code,
            # 'transactTypes': 'all',  # default all
            # 'startTime': 1546272000000,
            # 'endTime': 1546272000000,
            # 'sort': asc,  # asc, desc
            # 'limit': 100,  # range 1-500
            # 'fromId': 323  # first record hasattr(self, ID) query for pagination
        }
        currency = None
        if code is not None:
            currency = self.currency(code)
            request['currency'] = currency['id']
        if since is not None:
            request['startTime'] = since
        if limit is not None:
            request['limit'] = limit  # max 500
        request, params = self.handle_until_option('endTime', request, params)
        response = self.spotPrivateGetV2AccountLedger(self.extend(request, params))
        #
        #     {
        #         "code": 200,
        #         "message": "success",
        #         "data": [
        #             {
        #                 "accountId": 10000001,
        #                 "currency": "usdt",
        #                 "transactAmt": 10.000000000000000000,
        #                 "transactType": "transfer",
        #                 "transferType": "margin-transfer-out",
        #                 "transactId": 0,
        #                 "transactTime": 1629882331066,
        #                 "transferer": 28483123,
        #                 "transferee": 13496526
        #             },
        #             {
        #                 "accountId": 10000001,
        #                 "currency": "usdt",
        #                 "transactAmt": -10.000000000000000000,
        #                 "transactType": "transfer",
        #                 "transferType": "margin-transfer-in",
        #                 "transactId": 0,
        #                 "transactTime": 1629882096562,
        #                 "transferer": 13496526,
        #                 "transferee": 28483123
        #             }
        #         ],
        #         "nextId": 1624316679,
        #         "ok": True
        #     }
        #
        data = self.safe_value(response, 'data', [])
        return self.parse_ledger(data, currency, since, limit)

    def fetch_leverage_tiers(self, symbols: Strings = None, params={}) -> LeverageTiers:
        """
        retrieve information on the maximum leverage, and maintenance margin for trades of varying trade sizes
        :param str[]|None symbols: list of unified market symbols
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: a dictionary of `leverage tiers structures <https://docs.ccxt.com/#/?id=leverage-tiers-structure>`, indexed by market symbols
        """
        self.load_markets()
        response = self.contractPublicGetLinearSwapApiV1SwapAdjustfactor(params)
        #
        #    {
        #        "status": "ok",
        #        "data": [
        #            {
        #                "symbol": "MANA",
        #                "contract_code": "MANA-USDT",
        #                "margin_mode": "isolated",
        #                "trade_partition": "USDT",
        #                "list": [
        #                    {
        #                        "lever_rate": 75,
        #                        "ladders": [
        #                            {
        #                                "ladder": 0,
        #                                "min_size": 0,
        #                                "max_size": 999,
        #                                "adjust_factor": 0.7
        #                            },
        #                            ...
        #                        ]
        #                    }
        #                    ...
        #                ]
        #            },
        #            ...
        #        ]
        #    }
        #
        data = self.safe_list(response, 'data', [])
        return self.parse_leverage_tiers(data, symbols, 'contract_code')

    def parse_market_leverage_tiers(self, info, market: Market = None) -> List[LeverageTier]:
        currencyId = self.safe_string(info, 'trade_partition')
        marketId = self.safe_string(info, 'contract_code')
        tiers = []
        brackets = self.safe_list(info, 'list', [])
        for i in range(0, len(brackets)):
            item = brackets[i]
            leverage = self.safe_string(item, 'lever_rate')
            ladders = self.safe_list(item, 'ladders', [])
            for k in range(0, len(ladders)):
                bracket = ladders[k]
                adjustFactor = self.safe_string(bracket, 'adjust_factor')
                tiers.append({
                    'tier': self.safe_integer(bracket, 'ladder'),
                    'symbol': self.safe_symbol(marketId, market, None, 'swap'),
                    'currency': self.safe_currency_code(currencyId),
                    'minNotional': self.safe_number(bracket, 'min_size'),
                    'maxNotional': self.safe_number(bracket, 'max_size'),
                    'maintenanceMarginRate': self.parse_number(Precise.string_div(adjustFactor, leverage)),
                    'maxLeverage': self.parse_number(leverage),
                    'info': bracket,
                })
        return tiers

    def fetch_open_interest_history(self, symbol: str, timeframe='1h', since: Int = None, limit: Int = None, params={}):
        """
        Retrieves the open interest history of a currency

        https://huobiapi.github.io/docs/dm/v1/en/#query-information-on-open-interest
        https://huobiapi.github.io/docs/coin_margined_swap/v1/en/#query-information-on-open-interest
        https://huobiapi.github.io/docs/usdt_swap/v1/en/#general-query-information-on-open-interest

        :param str symbol: Unified CCXT market symbol
        :param str timeframe: '1h', '4h', '12h', or '1d'
        :param int [since]: Not used by huobi api, but response parsed by CCXT
        :param int [limit]: Default：48，Data Range [1,200]
        :param dict [params]: Exchange specific parameters
        :param int [params.amount_type]: *required* Open interest unit. 1-cont，2-cryptocurrency
        :param int [params.pair]: eg BTC-USDT *Only for USDT-M*
        :returns dict: an array of `open interest structures <https://docs.ccxt.com/#/?id=open-interest-structure>`
        """
        if timeframe != '1h' and timeframe != '4h' and timeframe != '12h' and timeframe != '1d':
            raise BadRequest(self.id + ' fetchOpenInterestHistory cannot only use the 1h, 4h, 12h and 1d timeframe')
        self.load_markets()
        timeframes: dict = {
            '1h': '60min',
            '4h': '4hour',
            '12h': '12hour',
            '1d': '1day',
        }
        market = self.market(symbol)
        amountType = self.safe_integer_2(params, 'amount_type', 'amountType', 2)
        request: dict = {
            'period': timeframes[timeframe],
            'amount_type': amountType,
        }
        if limit is not None:
            request['size'] = limit
        response = None
        if market['future']:
            request['contract_type'] = self.safe_string(market['info'], 'contract_type')
            request['symbol'] = market['baseId']  # currency code on coin-m futures
            # coin-m futures
            response = self.contractPublicGetApiV1ContractHisOpenInterest(self.extend(request, params))
        elif market['linear']:
            request['contract_type'] = 'swap'
            request['contract_code'] = market['id']
            request['contract_code'] = market['id']
            # USDT-M
            response = self.contractPublicGetLinearSwapApiV1SwapHisOpenInterest(self.extend(request, params))
        else:
            request['contract_code'] = market['id']
            # coin-m swaps
            response = self.contractPublicGetSwapApiV1SwapHisOpenInterest(self.extend(request, params))
        #
        #  contractPublicGetlinearSwapApiV1SwapHisOpenInterest
        #    {
        #        "status": "ok",
        #        "data": {
        #            "symbol": "BTC",
        #            "tick": [
        #                {
        #                    "volume": "4385.4350000000000000",
        #                    "amount_type": "2",
        #                    "ts": "1648220400000",
        #                    "value": "194059884.1850000000000000"
        #                },
        #                ...
        #            ],
        #            "contract_code": "BTC-USDT",
        #            "business_type": "swap",
        #            "pair": "BTC-USDT",
        #            "contract_type": "swap",
        #            "trade_partition": "USDT"
        #        },
        #        "ts": "1648223733007"
        #    }
        #
        #  contractPublicGetSwapApiV1SwapHisOpenInterest
        #    {
        #        "status": "ok",
        #        "data": {
        #            "symbol": "CRV",
        #            "tick": [
        #                {
        #                    "volume": 19174.0000000000000000,
        #                    "amount_type": 1,
        #                    "ts": 1648224000000
        #                },
        #                ...
        #            ],
        #            "contract_code": "CRV-USD"
        #        },
        #        "ts": 1648226554260
        #    }
        #
        #  contractPublicGetApiV1ContractHisOpenInterest
        #    {
        #         "status": "ok",
        #         "data": {
        #             "symbol": "BTC",
        #             "contract_type": "self_week",
        #             "tick": [
        #                {
        #                     "volume": "48419.0000000000000000",
        #                     "amount_type": 1,
        #                     "ts": 1648224000000
        #                },
        #                ...
        #            ]
        #        },
        #        "ts": 1648227062944
        #    }
        #
        data = self.safe_value(response, 'data')
        tick = self.safe_list(data, 'tick')
        return self.parse_open_interests_history(tick, market, since, limit)

    def fetch_open_interests(self, symbols: Strings = None, params={}):
        """
        Retrieves the open interest for a list of symbols

        https://huobiapi.github.io/docs/dm/v1/en/#get-contract-open-interest-information
        https://huobiapi.github.io/docs/coin_margined_swap/v1/en/#get-swap-open-interest-information
        https://huobiapi.github.io/docs/usdt_swap/v1/en/#general-get-swap-open-interest-information

        :param str[] [symbols]: a list of unified CCXT market symbols
        :param dict [params]: exchange specific parameters
        :returns dict[]: a list of `open interest structures <https://docs.ccxt.com/#/?id=open-interest-structure>`
        """
        self.load_markets()
        symbols = self.market_symbols(symbols)
        market = None
        if symbols is not None:
            symbolsLength = len(symbols)
            if symbolsLength > 0:
                first = self.safe_string(symbols, 0)
                market = self.market(first)
        request: dict = {}
        subType = None
        subType, params = self.handle_sub_type_and_params('fetchPositions', market, params, 'linear')
        marketType = None
        marketType, params = self.handle_market_type_and_params('fetchPositions', market, params)
        response = None
        if marketType == 'future':
            response = self.contractPublicGetApiV1ContractOpenInterest(self.extend(request, params))
            #
            #     {
            #         "status": "ok",
            #         "data": [
            #             {
            #                 "volume": 118850.000000000000000000,
            #                 "amount": 635.502025211544374189,
            #                 "symbol": "BTC",
            #                 "contract_type": "self_week",
            #                 "contract_code": "BTC220930",
            #                 "trade_amount": 1470.9400749347598691119206024033947897351,
            #                 "trade_volume": 286286,
            #                 "trade_turnover": 28628600.000000000000000000
            #             }
            #         ],
            #         "ts": 1664337928805
            #     }
            #
        elif subType == 'inverse':
            response = self.contractPublicGetSwapApiV1SwapOpenInterest(self.extend(request, params))
            #
            #     {
            #         "status": "ok",
            #         "data": [
            #             {
            #                 "volume": 518018.000000000000000000,
            #                 "amount": 2769.675777407074725180,
            #                 "symbol": "BTC",
            #                 "contract_code": "BTC-USD",
            #                 "trade_amount": 9544.4032080046491323463688602729806842458,
            #                 "trade_volume": 1848448,
            #                 "trade_turnover": 184844800.000000000000000000
            #             }
            #         ],
            #         "ts": 1664337226028
            #     }
            #
        else:
            request['contract_type'] = 'swap'
            response = self.contractPublicGetLinearSwapApiV1SwapOpenInterest(self.extend(request, params))
            #
            #     {
            #         "status": "ok",
            #         "data": [
            #             {
            #                 "volume": 7192610.000000000000000000,
            #                 "amount": 7192.610000000000000000,
            #                 "symbol": "BTC",
            #                 "value": 134654290.332000000000000000,
            #                 "contract_code": "BTC-USDT",
            #                 "trade_amount": 70692.804,
            #                 "trade_volume": 70692804,
            #                 "trade_turnover": 1379302592.9518,
            #                 "business_type": "swap",
            #                 "pair": "BTC-USDT",
            #                 "contract_type": "swap",
            #                 "trade_partition": "USDT"
            #             }
            #         ],
            #         "ts": 1664336503144
            #     }
            #
        data = self.safe_list(response, 'data', [])
        return self.parse_open_interests(data, symbols)

    def fetch_open_interest(self, symbol: str, params={}):
        """
        Retrieves the open interest of a currency

        https://huobiapi.github.io/docs/dm/v1/en/#get-contract-open-interest-information
        https://huobiapi.github.io/docs/coin_margined_swap/v1/en/#get-swap-open-interest-information
        https://huobiapi.github.io/docs/usdt_swap/v1/en/#general-get-swap-open-interest-information

        :param str symbol: Unified CCXT market symbol
        :param dict [params]: exchange specific parameters
        :returns dict} an open interest structure{@link https://docs.ccxt.com/#/?id=open-interest-structure:
        """
        self.load_markets()
        market = self.market(symbol)
        if not market['contract']:
            raise BadRequest(self.id + ' fetchOpenInterest() supports contract markets only')
        if market['option']:
            raise NotSupported(self.id + ' fetchOpenInterest() does not currently support option markets')
        request: dict = {
            'contract_code': market['id'],
        }
        response = None
        if market['future']:
            request['contract_type'] = self.safe_string(market['info'], 'contract_type')
            request['symbol'] = market['baseId']
            # COIN-M futures
            response = self.contractPublicGetApiV1ContractOpenInterest(self.extend(request, params))
        elif market['linear']:
            request['contract_type'] = 'swap'
            # USDT-M
            response = self.contractPublicGetLinearSwapApiV1SwapOpenInterest(self.extend(request, params))
        else:
            # COIN-M swaps
            response = self.contractPublicGetSwapApiV1SwapOpenInterest(self.extend(request, params))
        #
        # USDT-M contractPublicGetLinearSwapApiV1SwapOpenInterest
        #
        #     {
        #         "status": "ok",
        #         "data": [
        #             {
        #                 "volume": 7192610.000000000000000000,
        #                 "amount": 7192.610000000000000000,
        #                 "symbol": "BTC",
        #                 "value": 134654290.332000000000000000,
        #                 "contract_code": "BTC-USDT",
        #                 "trade_amount": 70692.804,
        #                 "trade_volume": 70692804,
        #                 "trade_turnover": 1379302592.9518,
        #                 "business_type": "swap",
        #                 "pair": "BTC-USDT",
        #                 "contract_type": "swap",
        #                 "trade_partition": "USDT"
        #             }
        #         ],
        #         "ts": 1664336503144
        #     }
        #
        # COIN-M Swap contractPublicGetSwapApiV1SwapOpenInterest
        #
        #     {
        #         "status": "ok",
        #         "data": [
        #             {
        #                 "volume": 518018.000000000000000000,
        #                 "amount": 2769.675777407074725180,
        #                 "symbol": "BTC",
        #                 "contract_code": "BTC-USD",
        #                 "trade_amount": 9544.4032080046491323463688602729806842458,
        #                 "trade_volume": 1848448,
        #                 "trade_turnover": 184844800.000000000000000000
        #             }
        #         ],
        #         "ts": 1664337226028
        #     }
        #
        # COIN-M Futures contractPublicGetApiV1ContractOpenInterest
        #
        #     {
        #         "status": "ok",
        #         "data": [
        #             {
        #                 "volume": 118850.000000000000000000,
        #                 "amount": 635.502025211544374189,
        #                 "symbol": "BTC",
        #                 "contract_type": "self_week",
        #                 "contract_code": "BTC220930",
        #                 "trade_amount": 1470.9400749347598691119206024033947897351,
        #                 "trade_volume": 286286,
        #                 "trade_turnover": 28628600.000000000000000000
        #             }
        #         ],
        #         "ts": 1664337928805
        #     }
        #
        data = self.safe_value(response, 'data', [])
        openInterest = self.parse_open_interest(data[0], market)
        timestamp = self.safe_integer(response, 'ts')
        openInterest['timestamp'] = timestamp
        openInterest['datetime'] = self.iso8601(timestamp)
        return openInterest

    def parse_open_interest(self, interest, market: Market = None):
        #
        # fetchOpenInterestHistory
        #
        #    {
        #        "volume": "4385.4350000000000000",
        #        "amount_type": "2",
        #        "ts": "1648220400000",
        #        "value": "194059884.1850000000000000"
        #    }
        #
        # fetchOpenInterest: USDT-M
        #
        #     {
        #         "volume": 7192610.000000000000000000,
        #         "amount": 7192.610000000000000000,
        #         "symbol": "BTC",
        #         "value": 134654290.332000000000000000,
        #         "contract_code": "BTC-USDT",
        #         "trade_amount": 70692.804,
        #         "trade_volume": 70692804,
        #         "trade_turnover": 1379302592.9518,
        #         "business_type": "swap",
        #         "pair": "BTC-USDT",
        #         "contract_type": "swap",
        #         "trade_partition": "USDT"
        #     }
        #
        # fetchOpenInterest: COIN-M Swap
        #
        #     {
        #         "volume": 518018.000000000000000000,
        #         "amount": 2769.675777407074725180,
        #         "symbol": "BTC",
        #         "contract_code": "BTC-USD",
        #         "trade_amount": 9544.4032080046491323463688602729806842458,
        #         "trade_volume": 1848448,
        #         "trade_turnover": 184844800.000000000000000000
        #     }
        #
        # fetchOpenInterest: COIN-M Futures
        #
        #     {
        #         "volume": 118850.000000000000000000,
        #         "amount": 635.502025211544374189,
        #         "symbol": "BTC",
        #         "contract_type": "self_week",
        #         "contract_code": "BTC220930",
        #         "trade_amount": 1470.9400749347598691119206024033947897351,
        #         "trade_volume": 286286,
        #         "trade_turnover": 28628600.000000000000000000
        #     }
        #
        timestamp = self.safe_integer(interest, 'ts')
        amount = self.safe_number(interest, 'volume')
        value = self.safe_number(interest, 'value')
        marketId = self.safe_string(interest, 'contract_code')
        return self.safe_open_interest({
            'symbol': self.safe_symbol(marketId, market),
            'baseVolume': amount,  # deprecated
            'quoteVolume': value,  # deprecated
            'openInterestAmount': amount,
            'openInterestValue': value,
            'timestamp': timestamp,
            'datetime': self.iso8601(timestamp),
            'info': interest,
        }, market)

    def borrow_isolated_margin(self, symbol: str, code: str, amount: float, params={}):
        """
        create a loan to borrow margin

        https://huobiapi.github.io/docs/spot/v1/en/#request-a-margin-loan-isolated
        https://huobiapi.github.io/docs/spot/v1/en/#request-a-margin-loan-cross

        :param str symbol: unified market symbol, required for isolated margin
        :param str code: unified currency code of the currency to borrow
        :param float amount: the amount to borrow
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: a `margin loan structure <https://docs.ccxt.com/#/?id=margin-loan-structure>`
        """
        self.load_markets()
        currency = self.currency(code)
        market = self.market(symbol)
        request: dict = {
            'currency': currency['id'],
            'amount': self.currency_to_precision(code, amount),
            'symbol': market['id'],
        }
        response = self.privatePostMarginOrders(self.extend(request, params))
        #
        # Isolated
        #
        #     {
        #         "data": 1000
        #     }
        #
        transaction = self.parse_margin_loan(response, currency)
        return self.extend(transaction, {
            'amount': amount,
            'symbol': symbol,
        })

    def borrow_cross_margin(self, code: str, amount: float, params={}):
        """
        create a loan to borrow margin

        https://huobiapi.github.io/docs/spot/v1/en/#request-a-margin-loan-isolated
        https://huobiapi.github.io/docs/spot/v1/en/#request-a-margin-loan-cross

        :param str code: unified currency code of the currency to borrow
        :param float amount: the amount to borrow
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: a `margin loan structure <https://docs.ccxt.com/#/?id=margin-loan-structure>`
        """
        self.load_markets()
        currency = self.currency(code)
        request: dict = {
            'currency': currency['id'],
            'amount': self.currency_to_precision(code, amount),
        }
        response = self.privatePostCrossMarginOrders(self.extend(request, params))
        #
        # Cross
        #
        #     {
        #         "status": "ok",
        #         "data": null
        #     }
        #
        transaction = self.parse_margin_loan(response, currency)
        return self.extend(transaction, {
            'amount': amount,
        })

    def repay_isolated_margin(self, symbol: str, code: str, amount, params={}):
        """
        repay borrowed margin and interest

        https://huobiapi.github.io/docs/spot/v1/en/#repay-margin-loan-cross-isolated

        :param str symbol: unified market symbol
        :param str code: unified currency code of the currency to repay
        :param float amount: the amount to repay
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: a `margin loan structure <https://docs.ccxt.com/#/?id=margin-loan-structure>`
        """
        self.load_markets()
        currency = self.currency(code)
        accountId = self.fetch_account_id_by_type('spot', 'isolated', symbol, params)
        request: dict = {
            'currency': currency['id'],
            'amount': self.currency_to_precision(code, amount),
            'accountId': accountId,
        }
        response = self.v2PrivatePostAccountRepayment(self.extend(request, params))
        #
        #     {
        #         "code":200,
        #         "data": [
        #             {
        #                 "repayId":1174424,
        #                 "repayTime":1600747722018
        #             }
        #         ]
        #     }
        #
        data = self.safe_value(response, 'Data', [])
        loan = self.safe_value(data, 0)
        transaction = self.parse_margin_loan(loan, currency)
        return self.extend(transaction, {
            'amount': amount,
            'symbol': symbol,
        })

    def repay_cross_margin(self, code: str, amount, params={}):
        """
        repay borrowed margin and interest

        https://huobiapi.github.io/docs/spot/v1/en/#repay-margin-loan-cross-isolated

        :param str code: unified currency code of the currency to repay
        :param float amount: the amount to repay
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: a `margin loan structure <https://docs.ccxt.com/#/?id=margin-loan-structure>`
        """
        self.load_markets()
        currency = self.currency(code)
        accountId = self.fetch_account_id_by_type('spot', 'cross', None, params)
        request: dict = {
            'currency': currency['id'],
            'amount': self.currency_to_precision(code, amount),
            'accountId': accountId,
        }
        response = self.v2PrivatePostAccountRepayment(self.extend(request, params))
        #
        #     {
        #         "code":200,
        #         "data": [
        #             {
        #                 "repayId":1174424,
        #                 "repayTime":1600747722018
        #             }
        #         ]
        #     }
        #
        data = self.safe_value(response, 'Data', [])
        loan = self.safe_value(data, 0)
        transaction = self.parse_margin_loan(loan, currency)
        return self.extend(transaction, {
            'amount': amount,
        })

    def parse_margin_loan(self, info, currency: Currency = None):
        #
        # borrowMargin cross
        #
        #     {
        #         "status": "ok",
        #         "data": null
        #     }
        #
        # borrowMargin isolated
        #
        #     {
        #         "data": 1000
        #     }
        #
        # repayMargin
        #
        #     {
        #         "repayId":1174424,
        #         "repayTime":1600747722018
        #     }
        #
        timestamp = self.safe_integer(info, 'repayTime')
        return {
            'id': self.safe_string_2(info, 'repayId', 'data'),
            'currency': self.safe_currency_code(None, currency),
            'amount': None,
            'symbol': None,
            'timestamp': timestamp,
            'datetime': self.iso8601(timestamp),
            'info': info,
        }

    def fetch_settlement_history(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
        """
        Fetches historical settlement records

        https://huobiapi.github.io/docs/dm/v1/en/#query-historical-settlement-records-of-the-platform-interface
        https://huobiapi.github.io/docs/coin_margined_swap/v1/en/#query-historical-settlement-records-of-the-platform-interface
        https://huobiapi.github.io/docs/usdt_swap/v1/en/#general-query-historical-settlement-records-of-the-platform-interface

        :param str symbol: unified symbol of the market to fetch the settlement history for
        :param int [since]: timestamp in ms, value range = current time - 90 days，default = current time - 90 days
        :param int [limit]: page items, default 20, shall not exceed 50
        :param dict [params]: exchange specific params
        :param int [params.until]: timestamp in ms, value range = start_time -> current time，default = current time
        :param int [params.page_index]: page index, default page 1 if not filled
        :param int [params.code]: unified currency code, can be used when symbol is None
        :returns dict[]: a list of `settlement history objects <https://docs.ccxt.com/#/?id=settlement-history-structure>`
        """
        if symbol is None:
            raise ArgumentsRequired(self.id + ' fetchSettlementHistory() requires a symbol argument')
        until = self.safe_integer(params, 'until')
        params = self.omit(params, ['until'])
        market = self.market(symbol)
        request: dict = {}
        if market['future']:
            request['symbol'] = market['baseId']
        else:
            request['contract_code'] = market['id']
        if since is not None:
            request['start_at'] = since
        if limit is not None:
            request['page_size'] = limit
        if until is not None:
            request['end_at'] = until
        response = None
        if market['swap']:
            if market['linear']:
                response = self.contractPublicGetLinearSwapApiV1SwapSettlementRecords(self.extend(request, params))
            else:
                response = self.contractPublicGetSwapApiV1SwapSettlementRecords(self.extend(request, params))
        else:
            response = self.contractPublicGetApiV1ContractSettlementRecords(self.extend(request, params))
        #
        # linear swap, coin-m swap
        #
        #    {
        #        "status": "ok",
        #        "data": {
        #        "total_page": 14,
        #        "current_page": 1,
        #        "total_size": 270,
        #        "settlement_record": [
        #            {
        #                "symbol": "ADA",
        #                "contract_code": "ADA-USDT",
        #                "settlement_time": 1652313600000,
        #                "clawback_ratio": 0E-18,
        #                "settlement_price": 0.512303000000000000,
        #                "settlement_type": "settlement",
        #                "business_type": "swap",
        #                "pair": "ADA-USDT",
        #                "trade_partition": "USDT"
        #            },
        #            ...
        #        ],
        #        "ts": 1652338693256
        #    }
        #
        # coin-m future
        #
        #    {
        #        "status": "ok",
        #        "data": {
        #            "total_page": 5,
        #            "current_page": 1,
        #            "total_size": 90,
        #            "settlement_record": [
        #                {
        #                    "symbol": "FIL",
        #                    "settlement_time": 1652342400000,
        #                    "clawback_ratio": 0E-18,
        #                    "list": [
        #                        {
        #                            "contract_code": "FIL220513",
        #                            "settlement_price": 7.016000000000000000,
        #                            "settlement_type": "settlement"
        #                        },
        #                        ...
        #                    ]
        #                },
        #            ]
        #        }
        #    }
        #
        data = self.safe_value(response, 'data')
        settlementRecord = self.safe_value(data, 'settlement_record')
        settlements = self.parse_settlements(settlementRecord, market)
        return self.sort_by(settlements, 'timestamp')

    def fetch_deposit_withdraw_fees(self, codes: Strings = None, params={}):
        """
        fetch deposit and withdraw fees

        https://huobiapi.github.io/docs/spot/v1/en/#get-all-supported-currencies-v2

        :param str[]|None codes: list of unified currency codes
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict[]: a list of `fees structures <https://docs.ccxt.com/#/?id=fee-structure>`
        """
        self.load_markets()
        response = self.spotPublicGetV2ReferenceCurrencies(params)
        #
        #    {
        #        "code": 200,
        #        "data": [
        #            {
        #                "currency": "sxp",
        #                "assetType": "1",
        #                "chains": [
        #                    {
        #                        "chain": "sxp",
        #                        "displayName": "ERC20",
        #                        "baseChain": "ETH",
        #                        "baseChainProtocol": "ERC20",
        #                        "isDynamic": True,
        #                        "numOfConfirmations": "12",
        #                        "numOfFastConfirmations": "12",
        #                        "depositStatus": "allowed",
        #                        "minDepositAmt": "0.23",
        #                        "withdrawStatus": "allowed",
        #                        "minWithdrawAmt": "0.23",
        #                        "withdrawPrecision": "8",
        #                        "maxWithdrawAmt": "227000.000000000000000000",
        #                        "withdrawQuotaPerDay": "227000.000000000000000000",
        #                        "withdrawQuotaPerYear": null,
        #                        "withdrawQuotaTotal": null,
        #                        "withdrawFeeType": "fixed",
        #                        "transactFeeWithdraw": "11.1653",
        #                        "addrWithTag": False,
        #                        "addrDepositTag": False
        #                    }
        #                ],
        #                "instStatus": "normal"
        #            }
        #        ]
        #    }
        #
        data = self.safe_list(response, 'data')
        return self.parse_deposit_withdraw_fees(data, codes, 'currency')

    def parse_deposit_withdraw_fee(self, fee, currency: Currency = None):
        #
        #            {
        #              "currency": "sxp",
        #              "assetType": "1",
        #              "chains": [
        #                  {
        #                      "chain": "sxp",
        #                      "displayName": "ERC20",
        #                      "baseChain": "ETH",
        #                      "baseChainProtocol": "ERC20",
        #                      "isDynamic": True,
        #                      "numOfConfirmations": "12",
        #                      "numOfFastConfirmations": "12",
        #                      "depositStatus": "allowed",
        #                      "minDepositAmt": "0.23",
        #                      "withdrawStatus": "allowed",
        #                      "minWithdrawAmt": "0.23",
        #                      "withdrawPrecision": "8",
        #                      "maxWithdrawAmt": "227000.000000000000000000",
        #                      "withdrawQuotaPerDay": "227000.000000000000000000",
        #                      "withdrawQuotaPerYear": null,
        #                      "withdrawQuotaTotal": null,
        #                      "withdrawFeeType": "fixed",
        #                      "transactFeeWithdraw": "11.1653",
        #                      "addrWithTag": False,
        #                      "addrDepositTag": False
        #                  }
        #              ],
        #              "instStatus": "normal"
        #          }
        #
        chains = self.safe_value(fee, 'chains', [])
        result = self.deposit_withdraw_fee(fee)
        for j in range(0, len(chains)):
            chainEntry = chains[j]
            networkId = self.safe_string(chainEntry, 'chain')
            withdrawFeeType = self.safe_string(chainEntry, 'withdrawFeeType')
            networkCode = self.network_id_to_code(networkId)
            withdrawFee = None
            withdrawResult = None
            if withdrawFeeType == 'fixed':
                withdrawFee = self.safe_number(chainEntry, 'transactFeeWithdraw')
                withdrawResult = {
                    'fee': withdrawFee,
                    'percentage': False,
                }
            else:
                withdrawFee = self.safe_number(chainEntry, 'transactFeeRateWithdraw')
                withdrawResult = {
                    'fee': withdrawFee,
                    'percentage': True,
                }
            result['networks'][networkCode] = {
                'withdraw': withdrawResult,
                'deposit': {
                    'fee': None,
                    'percentage': None,
                },
            }
            result = self.assign_default_deposit_withdraw_fees(result, currency)
        return result

    def parse_settlements(self, settlements, market):
        #
        # linear swap, coin-m swap, fetchSettlementHistory
        #
        #    [
        #        {
        #            "symbol": "ADA",
        #            "contract_code": "ADA-USDT",
        #            "settlement_time": 1652313600000,
        #            "clawback_ratio": 0E-18,
        #            "settlement_price": 0.512303000000000000,
        #            "settlement_type": "settlement",
        #            "business_type": "swap",
        #            "pair": "ADA-USDT",
        #            "trade_partition": "USDT"
        #        },
        #        ...
        #    ]
        #
        # coin-m future, fetchSettlementHistory
        #
        #    [
        #        {
        #            "symbol": "FIL",
        #            "settlement_time": 1652342400000,
        #            "clawback_ratio": 0E-18,
        #            "list": [
        #                {
        #                    "contract_code": "FIL220513",
        #                    "settlement_price": 7.016000000000000000,
        #                    "settlement_type": "settlement"
        #                },
        #                ...
        #            ]
        #        },
        #    ]
        #
        result = []
        for i in range(0, len(settlements)):
            settlement = settlements[i]
            list = self.safe_value(settlement, 'list')
            if list is not None:
                timestamp = self.safe_integer(settlement, 'settlement_time')
                timestampDetails: dict = {
                    'timestamp': timestamp,
                    'datetime': self.iso8601(timestamp),
                }
                for j in range(0, len(list)):
                    item = list[j]
                    parsedSettlement = self.parse_settlement(item, market)
                    result.append(self.extend(parsedSettlement, timestampDetails))
            else:
                result.append(self.parse_settlement(settlements[i], market))
        return result

    def parse_settlement(self, settlement, market):
        #
        # linear swap, coin-m swap, fetchSettlementHistory
        #
        #    {
        #        "symbol": "ADA",
        #        "contract_code": "ADA-USDT",
        #        "settlement_time": 1652313600000,
        #        "clawback_ratio": 0E-18,
        #        "settlement_price": 0.512303000000000000,
        #        "settlement_type": "settlement",
        #        "business_type": "swap",
        #        "pair": "ADA-USDT",
        #        "trade_partition": "USDT"
        #    }
        #
        # coin-m future, fetchSettlementHistory
        #
        #    {
        #        "contract_code": "FIL220513",
        #        "settlement_price": 7.016000000000000000,
        #        "settlement_type": "settlement"
        #    }
        #
        timestamp = self.safe_integer(settlement, 'settlement_time')
        marketId = self.safe_string(settlement, 'contract_code')
        return {
            'info': settlement,
            'symbol': self.safe_symbol(marketId, market),
            'price': self.safe_number(settlement, 'settlement_price'),
            'timestamp': timestamp,
            'datetime': self.iso8601(timestamp),
        }

    def fetch_liquidations(self, symbol: str, since: Int = None, limit: Int = None, params={}):
        """
        retrieves the public liquidations of a trading pair

        https://huobiapi.github.io/docs/usdt_swap/v1/en/#general-query-liquidation-orders-new
        https://huobiapi.github.io/docs/coin_margined_swap/v1/en/#query-liquidation-orders-new
        https://huobiapi.github.io/docs/dm/v1/en/#query-liquidation-order-information-new

        :param str symbol: unified CCXT market symbol
        :param int [since]: the earliest time in ms to fetch liquidations for
        :param int [limit]: the maximum number of liquidation structures to retrieve
        :param dict [params]: exchange specific parameters for the huobi api endpoint
        :param int [params.until]: timestamp in ms of the latest liquidation
        :param int [params.tradeType]: default 0, linear swap 0: all liquidated orders, 5: liquidated longs; 6: liquidated shorts, inverse swap and future 0: filled liquidated orders, 5: liquidated close orders, 6: liquidated open orders
        :returns dict: an array of `liquidation structures <https://docs.ccxt.com/#/?id=liquidation-structure>`
        """
        self.load_markets()
        market = self.market(symbol)
        tradeType = self.safe_integer(params, 'trade_type', 0)
        request: dict = {
            'trade_type': tradeType,
        }
        if since is not None:
            request['start_time'] = since
        request, params = self.handle_until_option('end_time', request, params)
        response = None
        if market['swap']:
            request['contract'] = market['id']
            if market['linear']:
                response = self.contractPublicGetLinearSwapApiV3SwapLiquidationOrders(self.extend(request, params))
            else:
                response = self.contractPublicGetSwapApiV3SwapLiquidationOrders(self.extend(request, params))
        elif market['future']:
            request['symbol'] = market['id']
            response = self.contractPublicGetApiV3ContractLiquidationOrders(self.extend(request, params))
        else:
            raise NotSupported(self.id + ' fetchLiquidations() does not support ' + market['type'] + ' orders')
        #
        #     {
        #         "code": 200,
        #         "msg": "",
        #         "data": [
        #             {
        #                 "query_id": 452057,
        #                 "contract_code": "BTC-USDT-211210",
        #                 "symbol": "USDT",
        #                 "direction": "sell",
        #                 "offset": "close",
        #                 "volume": 479.000000000000000000,
        #                 "price": 51441.700000000000000000,
        #                 "created_at": 1638593647864,
        #                 "amount": 0.479000000000000000,
        #                 "trade_turnover": 24640.574300000000000000,
        #                 "business_type": "futures",
        #                 "pair": "BTC-USDT"
        #             }
        #         ],
        #         "ts": 1604312615051
        #     }
        #
        data = self.safe_list(response, 'data', [])
        return self.parse_liquidations(data, market, since, limit)

    def parse_liquidation(self, liquidation, market: Market = None):
        #
        #     {
        #         "query_id": 452057,
        #         "contract_code": "BTC-USDT-211210",
        #         "symbol": "USDT",
        #         "direction": "sell",
        #         "offset": "close",
        #         "volume": 479.000000000000000000,
        #         "price": 51441.700000000000000000,
        #         "created_at": 1638593647864,
        #         "amount": 0.479000000000000000,
        #         "trade_turnover": 24640.574300000000000000,
        #         "business_type": "futures",
        #         "pair": "BTC-USDT"
        #     }
        #
        marketId = self.safe_string(liquidation, 'contract_code')
        timestamp = self.safe_integer(liquidation, 'created_at')
        return self.safe_liquidation({
            'info': liquidation,
            'symbol': self.safe_symbol(marketId, market),
            'contracts': self.safe_number(liquidation, 'volume'),
            'contractSize': self.safe_number(market, 'contractSize'),
            'price': self.safe_number(liquidation, 'price'),
            'side': self.safe_string_lower(liquidation, 'direction'),
            'baseValue': self.safe_number(liquidation, 'amount'),
            'quoteValue': self.safe_number(liquidation, 'trade_turnover'),
            'timestamp': timestamp,
            'datetime': self.iso8601(timestamp),
        })

    def close_position(self, symbol: str, side: OrderSide = None, params={}) -> Order:
        """
        closes open positions for a contract market, requires 'amount' in params, unlike other exchanges

        https://huobiapi.github.io/docs/usdt_swap/v1/en/#isolated-place-lightning-close-order  # USDT-M(isolated)
        https://huobiapi.github.io/docs/usdt_swap/v1/en/#cross-place-lightning-close-position  # USDT-M(cross)
        https://huobiapi.github.io/docs/coin_margined_swap/v1/en/#place-lightning-close-order  # Coin-M swap
        https://huobiapi.github.io/docs/dm/v1/en/#place-flash-close-order                      # Coin-M futures

        :param str symbol: unified CCXT market symbol
        :param str side: 'buy' or 'sell', the side of the closing order, opposite side side
        :param dict [params]: extra parameters specific to the okx api endpoint
        :param str [params.clientOrderId]: client needs to provide unique API and have to maintain the API themselves afterwards. [1, 9223372036854775807]
        :param dict [params.marginMode]: 'cross' or 'isolated', required for linear markets

 EXCHANGE SPECIFIC PARAMETERS
        :param number [params.amount]: order quantity
        :param str [params.order_price_type]: 'lightning' by default, 'lightning_fok': lightning fok type, 'lightning_ioc': lightning ioc type 'market' by default, 'market': market order type, 'lightning_fok': lightning
        :returns dict: `an order structure <https://docs.ccxt.com/#/?id=position-structure>`
        """
        self.load_markets()
        market = self.market(symbol)
        clientOrderId = self.safe_string(params, 'clientOrderId')
        if not market['contract']:
            raise BadRequest(self.id + ' closePosition() symbol supports contract markets only')
        self.check_required_argument('closePosition', side, 'side')
        request: dict = {
            'contract_code': market['id'],
            'direction': side,
        }
        if clientOrderId is not None:
            request['client_order_id'] = clientOrderId
        if market['inverse']:
            amount = self.safe_string_2(params, 'volume', 'amount')
            if amount is None:
                raise ArgumentsRequired(self.id + ' closePosition() requires an extra argument params["amount"] for inverse markets')
            request['volume'] = self.amount_to_precision(symbol, amount)
        params = self.omit(params, ['clientOrderId', 'volume', 'amount'])
        response = None
        if market['inverse']:  # Coin-M
            if market['swap']:
                response = self.contractPrivatePostSwapApiV1SwapLightningClosePosition(self.extend(request, params))
            else:  # future
                response = self.contractPrivatePostApiV1LightningClosePosition(self.extend(request, params))
        else:  # USDT-M
            marginMode = None
            marginMode, params = self.handle_margin_mode_and_params('closePosition', params, 'cross')
            if marginMode == 'cross':
                response = self.contractPrivatePostLinearSwapApiV1SwapCrossLightningClosePosition(self.extend(request, params))
            else:  # isolated
                response = self.contractPrivatePostLinearSwapApiV1SwapLightningClosePosition(self.extend(request, params))
        return self.parse_order(response, market)

    def set_position_mode(self, hedged: bool, symbol: Str = None, params={}):
        """
        set hedged to True or False

        https://huobiapi.github.io/docs/usdt_swap/v1/en/#isolated-switch-position-mode
        https://huobiapi.github.io/docs/usdt_swap/v1/en/#cross-switch-position-mode

        :param bool hedged: set to True to for hedged mode, must be set separately for each market in isolated margin mode, only valid for linear markets
        :param str [symbol]: unified market symbol, required for isolated margin mode
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :param str [params.marginMode]: "cross"(default) or "isolated"
        :returns dict: response from the exchange
        """
        self.load_markets()
        posMode = 'dual_side' if hedged else 'single_side'
        market = None
        if symbol is not None:
            market = self.market(symbol)
        marginMode = None
        marginMode, params = self.handle_margin_mode_and_params('setPositionMode', params, 'cross')
        request: dict = {
            'position_mode': posMode,
        }
        response = None
        if (market is not None) and (market['inverse']):
            raise BadRequest(self.id + ' setPositionMode can only be used for linear markets')
        if marginMode == 'isolated':
            if symbol is None:
                raise ArgumentsRequired(self.id + ' setPositionMode requires a symbol argument for isolated margin mode')
            request['margin_account'] = market['id']
            response = self.contractPrivatePostLinearSwapApiV1SwapSwitchPositionMode(self.extend(request, params))
            #
            #    {
            #        "status": "ok",
            #        "data": [
            #            {
            #                "margin_account": "BTC-USDT",
            #                "position_mode": "single_side"
            #            }
            #        ],
            #        "ts": 1566899973811
            #    }
            #
        else:
            request['margin_account'] = 'USDT'
            response = self.contractPrivatePostLinearSwapApiV1SwapCrossSwitchPositionMode(self.extend(request, params))
            #
            #    {
            #        "status": "ok",
            #        "data": [
            #            {
            #                "margin_account": "USDT",
            #                "position_mode": "single_side"
            #            }
            #        ],
            #        "ts": 1566899973811
            #    }
            #
        return response
