# -*- 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.async_support.base.exchange import Exchange
import asyncio
import hashlib
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 NetworkError
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 huobi(Exchange):

    def describe(self):
        return self.deep_extend(super(huobi, self).describe(), {
            'id': 'huobi',
            'name': 'Huobi',
            '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,
                'borrowMargin': True,
                'cancelAllOrders': True,
                'cancelOrder': True,
                'cancelOrders': True,
                'createDepositAddress': None,
                'createOrder': True,
                'createReduceOnlyOrder': False,
                'createStopLimitOrder': True,
                'createStopMarketOrder': True,
                'createStopOrder': True,
                'fetchAccounts': True,
                'fetchBalance': True,
                'fetchBidsAsks': None,
                'fetchBorrowInterest': True,
                'fetchBorrowRate': None,
                'fetchBorrowRateHistories': None,
                'fetchBorrowRateHistory': None,
                'fetchBorrowRates': True,
                'fetchBorrowRatesPerSymbol': True,
                'fetchCanceledOrders': None,
                'fetchClosedOrder': None,
                'fetchClosedOrders': True,
                '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,
                'fetchL3OrderBook': None,
                'fetchLedger': True,
                'fetchLedgerEntry': None,
                'fetchLeverage': False,
                'fetchLeverageTiers': True,
                'fetchMarketLeverageTiers': True,
                'fetchMarkets': True,
                'fetchMarkOHLCV': True,
                'fetchMyTrades': True,
                'fetchOHLCV': True,
                'fetchOpenInterest': True,
                'fetchOpenInterestHistory': True,
                'fetchOpenOrder': None,
                'fetchOpenOrders': True,
                'fetchOrder': True,
                'fetchOrderBook': True,
                'fetchOrderBooks': None,
                'fetchOrders': True,
                'fetchOrderTrades': True,
                'fetchPosition': True,
                'fetchPositions': True,
                '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,
                'repayMargin': True,
                'setLeverage': True,
                'setMarginMode': False,
                'setPositionMode': False,
                '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.huobi.com/en-us/v/register/double-invite/?inviter_id=11343840&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/',
                ],
                '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/detail/': 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,
                            # Trading
                            'v1/order/orders/place': 0.2,
                            'v1/order/batch-orders': 0.4,
                            '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_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_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_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_api_trading_status': 1,
                            # Swap Account Interface
                            'swap-api/v1/swap_api_trading_status': 1,
                            # Swap Account Interface
                            'linear-swap-api/v1/swap_api_trading_status': 1,
                            'linear-swap-api/v3/unified_account_info': 1,
                            'linear-swap-api/v3/swap_unified_account_type': 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_order': 1,
                            'v1/contract_batchorder': 1,
                            'api/v1/contract_cancel': 1,
                            'api/v1/contract_cancelall': 1,
                            'api/v1/contract_switch_lever_rate': 1,
                            '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_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': 1,
                            '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': 1,
                            'linear-swap-api/v1/swap_cross_switch_lever_rate': 1,
                            '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/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/swap_switch_account_type': 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,
                },
                '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}
                    '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 as you 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}
                    '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}
                },
            },
            'precisionMode': TICK_SIZE,
            'options': {
                'fetchMarkets': {
                    'types': {
                        'spot': True,
                        'future': {
                            'linear': True,
                            'inverse': True,
                        },
                        'swap': {
                            'linear': True,
                            'inverse': 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
                    'ALGO': 'ALGO',
                    'ALGORAND': 'ALGO',
                    'BEP20': 'BEP20',
                    'BSC': 'BEP20',
                    'ERC20': 'ERC20',
                    'ETH': 'ERC20',
                    'AVALANCHE': 'AVAXCCHAIN',
                    'AVAX': 'AVAXCCHAIN',
                    'HRC20': 'HECO',
                    'HECO': 'HECO',
                    # 'HT': 'HECO',  # HT is not acceptable networkcode for unification
                    'TRC20': 'TRC20',
                    'TRX': 'TRC20',
                    'BTC': 'BTC',
                    'BITCOIN': 'BTC',
                    'ARBITRUM': 'ARB',
                    'ARB': 'ARB',
                    'SOLANA': 'SOL',
                    'SOL': 'SOL',
                    'SPL': 'SOL',
                    'PRC20': 'PRC20',
                    'POLYGON': 'PRC20',
                    'MATIC': 'PRC20',
                },
                'networksById': {
                    'ALGO': 'ALGO',
                    'BEP20': 'BEP20',
                    'ERC20': 'ERC20',
                    'AVAXCCHAIN': 'AVALANCHE',
                    'HECO': 'HRC20',
                    'TRC20': 'TRC20',
                    'BTC': 'BTC',
                    'ARB': 'ARBITRUM',
                    'SOL': 'SOLANA',
                    'PRC20': 'POLYGON',
                },
                # 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',
                },
                'marginAccounts': {
                    'cross': 'super-margin',
                    'isolated': 'margin',
                },
                '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
                'GET': 'Themis',  # conflict with GET(Guaranteed Entrance Token, GET Protocol)
                'GTC': 'Game.com',  # conflict with Gitcoin and Gastrocoin
                'HIT': 'HitChain',
                'HOT': 'Hydro Protocol',  # conflict with HOT(Holo) https://github.com/ccxt/ccxt/issues/4929
                # 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': 'Super Bitcoin',
                'SOUL': 'Soulsaver',
                'BIFI': 'Bitcoin File',  # conflict with Beefy.Finance https://github.com/ccxt/ccxt/issues/8706
            },
        })

    async def fetch_status(self, params={}):
        await self.load_markets()
        marketType = None
        marketType, params = self.handle_market_type_and_params('fetchMyTrades', None, params)
        method = 'statusPublicSpotGetApiV2SummaryJson'
        if marketType != 'spot':
            subType = self.safe_string(params, 'subType', self.options['defaultSubType'])
            if marketType == 'swap':
                if subType == 'linear':
                    method = 'statusPublicSwapLinearGetApiV2SummaryJson'
                elif subType == 'inverse':
                    method = 'statusPublicSwapInverseGetApiV2SummaryJson'
            elif marketType == 'future':
                if subType == 'linear':
                    method = 'statusPublicFutureLinearGetApiV2SummaryJson'
                elif subType == 'inverse':
                    method = 'statusPublicFutureInverseGetApiV2SummaryJson'
            elif marketType == 'contract':
                method = 'contractPublicGetHeartbeat'
        response = await getattr(self, method)()
        #
        # 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 method == 'contractPublicGetHeartbeat':
            statusRaw = self.safe_string(response, 'status')
            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,
        }

    async def fetch_time(self, params={}):
        """
        fetches the current integer timestamp in milliseconds from the exchange server
        :param dict params: extra parameters specific to the huobi 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)
        method = 'spotPublicGetV1CommonTimestamp'
        if (type == 'future') or (type == 'swap'):
            method = 'contractPublicGetApiV1Timestamp'
        response = await getattr(self, method)(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, market=None):
        #
        #     {
        #         "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'),
        }

    async def fetch_trading_fee(self, symbol, params={}):
        """
        fetch the trading fees for a market
        :param str symbol: unified market symbol
        :param dict params: extra parameters specific to the huobi api endpoint
        :returns dict: a `fee structure <https://docs.ccxt.com/en/latest/manual.html#fee-structure>`
        """
        await self.load_markets()
        market = self.market(symbol)
        request = {
            'symbols': market['id'],  # trading symbols comma-separated
        }
        response = await 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)

    async def fetch_trading_limits(self, symbols=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
        await self.load_markets()
        if symbols is None:
            symbols = self.symbols
        result = {}
        for i in range(0, len(symbols)):
            symbol = symbols[i]
            result[symbol] = await self.fetch_trading_limits_by_id(self.market_id(symbol), params)
        return result

    async def fetch_trading_limits_by_id(self, id, params={}):
        request = {
            'symbol': id,
        }
        response = await 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=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)

    async def fetch_markets(self, params={}):
        """
        retrieves data on all markets for huobi
        :param dict params: extra parameters specific to the exchange api endpoint
        :returns [dict]: an array of objects representing market data
        """
        options = self.safe_value(self.options, 'fetchMarkets', {})
        types = self.safe_value(options, 'types', {})
        allMarkets = []
        promises = []
        keys = list(types.keys())
        for i in range(0, len(keys)):
            type = keys[i]
            value = self.safe_value(types, type)
            if value is True:
                promises.append(self.fetch_markets_by_type_and_sub_type(type, None, params))
            elif value:
                subKeys = list(value.keys())
                for j in range(0, len(subKeys)):
                    subType = subKeys[j]
                    subValue = self.safe_value(value, subType)
                    if subValue:
                        promises.append(self.fetch_markets_by_type_and_sub_type(type, subType, params))
        promises = await asyncio.gather(*promises)
        for i in range(0, len(promises)):
            allMarkets = self.array_concat(allMarkets, promises[i])
        return allMarkets

    async def fetch_markets_by_type_and_sub_type(self, type, subType, params={}):
        method = 'spotPublicGetV1CommonSymbols'
        query = self.omit(params, ['type', 'subType'])
        spot = (type == 'spot')
        contract = (type != 'spot')
        future = (type == 'future')
        swap = (type == 'swap')
        linear = None
        inverse = None
        request = {}
        if contract:
            linear = (subType == 'linear')
            inverse = (subType == 'inverse')
            if linear:
                method = 'contractPublicGetLinearSwapApiV1SwapContractInfo'
                if future:
                    request['business_type'] = 'futures'
            elif inverse:
                if future:
                    method = 'contractPublicGetApiV1ContractContractInfo'
                elif swap:
                    method = 'contractPublicGetSwapApiV1SwapContractInfo'
        response = await getattr(self, method)(self.extend(request, query))
        #
        # 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 future
        #
        #     {
        #         "status":"ok",
        #         "data":[
        #             {
        #                 "symbol":"BTC",
        #                 "contract_code":"BTC211126",
        #                 "contract_type":"self_week",
        #                 "contract_size":100.000000000000000000,
        #                 "price_tick":0.010000000000000000,
        #                 "delivery_date":"20211126",
        #                 "delivery_time":"1637913600000",
        #                 "create_date":"20211112",
        #                 "contract_status":1,
        #                 "settlement_time":"1637481600000"
        #             },
        #         ],
        #         "ts":1637474595140
        #     }
        #
        # linear futures
        #
        #     {
        #         "status":"ok",
        #         "data":[
        #             {
        #                 "symbol":"BTC",
        #                 "contract_code":"BTC-USDT-211231",
        #                 "contract_size":0.001000000000000000,
        #                 "price_tick":0.100000000000000000,
        #                 "delivery_date":"20211231",
        #                 "delivery_time":"1640937600000",
        #                 "create_date":"20211228",
        #                 "contract_status":1,
        #                 "settlement_date":"1640764800000",
        #                 "support_margin_mode":"cross",
        #                 "business_type":"futures",
        #                 "pair":"BTC-USDT",
        #                 "contract_type":"self_week"  # next_week, quarter
        #             },
        #         ],
        #         "ts":1640736207263
        #     }
        #
        # swaps
        #
        #     {
        #         "status":"ok",
        #         "data":[
        #             {
        #                 "symbol":"BTC",
        #                 "contract_code":"BTC-USDT",
        #                 "contract_size":0.001000000000000000,
        #                 "price_tick":0.100000000000000000,
        #                 "delivery_time":"",
        #                 "create_date":"20201021",
        #                 "contract_status":1,
        #                 "settlement_date":"1637481600000",
        #                 "support_margin_mode":"all",  # isolated
        #             },
        #         ],
        #         "ts":1637474774467
        #     }
        #
        markets = self.safe_value(response, 'data', [])
        numMarkets = len(markets)
        if numMarkets < 1:
            raise NetworkError(self.id + ' fetchMarkets() returned an empty response: ' + self.json(markets))
        result = []
        for i in range(0, len(markets)):
            market = markets[i]
            baseId = None
            quoteId = None
            settleId = None
            id = None
            lowercaseId = None
            lowercaseBaseId = None
            if contract:
                id = self.safe_string(market, 'contract_code')
                lowercaseId = id.lower()
                if swap:
                    parts = id.split('-')
                    baseId = self.safe_string(market, 'symbol')
                    lowercaseBaseId = baseId.lower()
                    quoteId = self.safe_string_lower(parts, 1)
                    settleId = baseId if inverse else quoteId
                elif future:
                    baseId = self.safe_string(market, 'symbol')
                    lowercaseBaseId = baseId.lower()
                    if inverse:
                        quoteId = 'USD'
                        settleId = baseId
                    else:
                        pair = self.safe_string(market, 'pair')
                        parts = pair.split('-')
                        quoteId = self.safe_string(parts, 1)
                        settleId = quoteId
            else:
                baseId = self.safe_string(market, 'base-currency')
                lowercaseBaseId = baseId.lower()
                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
            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')))
            else:
                pricePrecision = self.safe_number(market, 'price_tick')
                amountPrecision = self.parse_number('1')  # other markets have step size of 1 contract
            maker = None
            taker = None
            if spot:
                maker = self.parse_number('0') if (base == 'OMG') else self.parse_number('0.002')
                taker = self.parse_number('0') if (base == 'OMG') else self.parse_number('0.002')
            active = None
            if spot:
                state = self.safe_string(market, 'state')
                active = (state == 'online')
            elif contract:
                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
            result.append({
                'id': id,
                'lowercaseId': lowercaseId,
                'symbol': symbol,
                'base': base,
                'quote': quote,
                'settle': settle,
                'baseId': baseId,
                'lowercaseBaseId': lowercaseBaseId,
                '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,
                    },
                },
                'info': market,
            })
        return result

    def parse_ticker(self, ticker, market=None):
        #
        # 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)
        timestamp = self.safe_integer_2(ticker, 'ts', 'quoteTime')
        bid = None
        bidVolume = None
        ask = None
        askVolume = None
        if 'bid' in ticker:
            if 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 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)

    async def fetch_ticker(self, symbol, params={}):
        """
        fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
        :param str symbol: unified symbol of the market to fetch the ticker for
        :param dict params: extra parameters specific to the huobi api endpoint
        :returns dict: a `ticker structure <https://docs.ccxt.com/en/latest/manual.html#ticker-structure>`
        """
        await self.load_markets()
        market = self.market(symbol)
        request = {}
        fieldName = 'symbol'
        method = 'spotPublicGetMarketDetailMerged'
        if market['linear']:
            method = 'contractPublicGetLinearSwapExMarketDetailMerged'
            fieldName = 'contract_code'
        elif market['inverse']:
            if market['future']:
                method = 'contractPublicGetMarketDetailMerged'
            elif market['swap']:
                method = 'contractPublicGetSwapExMarketDetailMerged'
                fieldName = 'contract_code'
        request[fieldName] = market['id']
        response = await getattr(self, method)(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

    async def fetch_tickers(self, symbols=None, params={}):
        """
        fetches price tickers for multiple markets, statistical calculations with the information calculated over the past 24 hours each market
        see https://huobiapi.github.io/docs/spot/v1/en/#get-latest-tickers-for-all-pairs
        see https://huobiapi.github.io/docs/usdt_swap/v1/en/#general-get-a-batch-of-market-data-overview
        see https://huobiapi.github.io/docs/dm/v1/en/#get-a-batch-of-market-data-overview
        see https://huobiapi.github.io/docs/coin_margined_swap/v1/en/#get-a-batch-of-market-data-overview-v2
        :param [str]|None symbols: unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
        :param dict params: extra parameters specific to the huobi api endpoint
        :returns dict: a dictionary of `ticker structures <https://docs.ccxt.com/en/latest/manual.html#ticker-structure>`
        """
        await 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)
        type = None
        subType = None
        method = 'spotPublicGetMarketTickers'
        type, params = self.handle_market_type_and_params('fetchTickers', market, params)
        subType, params = self.handle_sub_type_and_params('fetchTickers', market, params)
        request = {}
        future = (type == 'future')
        swap = (type == 'swap')
        linear = (subType == 'linear')
        inverse = (subType == 'inverse')
        if future or swap:
            if linear:
                method = 'contractPublicGetLinearSwapExMarketDetailBatchMerged'
                if future:
                    request['business_type'] = 'futures'
            elif inverse:
                if future:
                    method = 'contractPublicGetMarketDetailBatchMerged'
                elif swap:
                    method = 'contractPublicGetSwapExMarketDetailBatchMerged'
        params = self.omit(params, ['type', 'subType'])
        response = await getattr(self, method)(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
        #     }
        #
        # inverse swaps, linear swaps, inverse futures
        #
        #     {
        #         "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"
        #             }
        #         ],
        #         "ts":1637504679376
        #     }
        #
        # linear futures
        #
        #     {
        #         "status":"ok",
        #         "ticks":[
        #             {
        #                 "id":1640745627,
        #                 "ts":1640745627957,
        #                 "ask":[48079.1,20],
        #                 "bid":[47713.8,125],
        #                 "business_type":"futures",
        #                 "contract_code":"BTC-USDT-CW",
        #                 "open":"49011.8",
        #                 "close":"47934",
        #                 "low":"47292.3",
        #                 "high":"49011.8",
        #                 "amount":"17.398",
        #                 "count":1515,
        #                 "vol":"17398",
        #                 "trade_turnover":"840726.5048"
        #             }
        #         ],
        #         "ts":1640745627988
        #     }
        #
        tickers = self.safe_value_2(response, 'data', 'ticks', [])
        timestamp = self.safe_integer(response, 'ts')
        result = {}
        for i in range(0, len(tickers)):
            ticker = self.parse_ticker(tickers[i])
            # the market ids for linear futures are non-standard and differ from all the other endpoints
            # we are doing a linear-matching here
            if future and linear:
                for j in range(0, len(self.symbols)):
                    symbol = self.symbols[j]
                    market = self.market(symbol)
                    contractType = self.safe_string(market['info'], 'contract_type')
                    if (contractType == 'this_week') and (ticker['symbol'] == (market['baseId'] + '-' + market['quoteId'] + '-CW')):
                        ticker['symbol'] = market['symbol']
                        break
                    elif (contractType == 'next_week') and (ticker['symbol'] == (market['baseId'] + '-' + market['quoteId'] + '-NW')):
                        ticker['symbol'] = market['symbol']
                        break
                    elif (contractType == 'this_quarter') and (ticker['symbol'] == (market['baseId'] + '-' + market['quoteId'] + '-CQ')):
                        ticker['symbol'] = market['symbol']
                        break
                    elif (contractType == 'next_quarter') and (ticker['symbol'] == (market['baseId'] + '-' + market['quoteId'] + '-NQ')):
                        ticker['symbol'] = market['symbol']
                        break
            symbol = ticker['symbol']
            ticker['timestamp'] = timestamp
            ticker['datetime'] = self.iso8601(timestamp)
            result[symbol] = ticker
        return self.filter_by_array(result, 'symbol', symbols)

    async def fetch_order_book(self, symbol, limit=None, params={}):
        """
        fetches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
        :param str symbol: unified symbol of the market to fetch the order book for
        :param int|None limit: the maximum amount of order book entries to return
        :param dict params: extra parameters specific to the huobi api endpoint
        :returns dict: A dictionary of `order book structures <https://docs.ccxt.com/en/latest/manual.html#order-book-structure>` indexed by market symbols
        """
        await self.load_markets()
        market = self.market(symbol)
        request = {
            #
            # 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
        }
        fieldName = 'symbol'
        method = 'spotPublicGetMarketDepth'
        if market['linear']:
            method = 'contractPublicGetLinearSwapExMarketDepth'
            fieldName = 'contract_code'
        elif market['inverse']:
            if market['future']:
                method = 'contractPublicGetMarketDepth'
            elif market['swap']:
                method = 'contractPublicGetSwapExMarketDepth'
                fieldName = 'contract_code'
        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[fieldName] = market['id']
        response = await getattr(self, method)(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, market=None):
        #
        # 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_2(trade, 'filled-fees', '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,
            }
        tradeId = self.safe_string_2(trade, 'trade-id', 'tradeId')
        id = self.safe_string_2(trade, 'trade_id', 'id', tradeId)
        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)

    async def fetch_order_trades(self, id, symbol=None, since=None, limit=None, params={}):
        """
        fetch all the trades made from a single order
        :param str id: order id
        :param str|None symbol: unified market symbol
        :param int|None since: the earliest time in ms to fetch trades for
        :param int|None limit: the maximum number of trades to retrieve
        :param dict params: extra parameters specific to the huobi api endpoint
        :returns [dict]: a list of `trade structures <https://docs.ccxt.com/en/latest/manual.html#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)
        method = self.get_supported_mapping(marketType, {
            'spot': 'fetchSpotOrderTrades',
            # 'swap': 'fetchContractOrderTrades',
            # 'future': 'fetchContractOrderTrades',
        })
        return await getattr(self, method)(id, symbol, since, limit, params)

    async def fetch_spot_order_trades(self, id, symbol=None, since=None, limit=None, params={}):
        await self.load_markets()
        request = {
            'order-id': id,
        }
        response = await self.spotPrivateGetV1OrderOrdersOrderIdMatchresults(self.extend(request, params))
        return self.parse_trades(response['data'], None, since, limit)

    async def fetch_my_trades(self, symbol=None, since=None, limit=None, params={}):
        """
        fetch all trades made by the user
        :param str|None symbol: unified market symbol
        :param int|None since: the earliest time in ms to fetch trades for
        :param int|None limit: the maximum number of trades structures to retrieve
        :param dict params: extra parameters specific to the huobi api endpoint
        :returns [dict]: a list of `trade structures <https://docs.ccxt.com/en/latest/manual.html#trade-structure>`
        """
        await self.load_markets()
        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 = {
            # 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
        }
        method = 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
            method = 'spotPrivateGetV1OrderMatchresults'
        else:
            if symbol is None:
                raise ArgumentsRequired(self.id + ' fetchMyTrades() requires a symbol for ' + marketType + ' orders')
            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
            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':
                    method = 'contractPrivatePostLinearSwapApiV3SwapMatchresultsExact'
                elif marginMode == 'cross':
                    method = 'contractPrivatePostLinearSwapApiV3SwapCrossMatchresultsExact'
            elif market['inverse']:
                if marketType == 'future':
                    method = 'contractPrivatePostApiV3ContractMatchresultsExact'
                    request['symbol'] = market['settleId']
                elif marketType == 'swap':
                    method = 'contractPrivatePostSwapApiV3SwapMatchresultsExact'
                else:
                    raise NotSupported(self.id + ' fetchMyTrades() does not support ' + marketType + ' markets')
        response = await getattr(self, method)(self.extend(request, params))
        #
        # 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)

    async def fetch_trades(self, symbol, since=None, limit=1000, params={}):
        """
        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|None since: timestamp in ms of the earliest trade to fetch
        :param int|None limit: the maximum amount of trades to fetch
        :param dict params: extra parameters specific to the huobi api endpoint
        :returns [dict]: a list of `trade structures <https://docs.ccxt.com/en/latest/manual.html?#public-trades>`
        """
        await self.load_markets()
        market = self.market(symbol)
        request = {
            # 'symbol': market['id'],  # spot, future
            # 'contract_code': market['id'],  # swap
        }
        fieldName = 'symbol'
        method = 'spotPublicGetMarketHistoryTrade'
        if market['future']:
            if market['inverse']:
                method = 'contractPublicGetMarketHistoryTrade'
            elif market['linear']:
                method = 'contractPublicGetLinearSwapExMarketHistoryTrade'
                fieldName = 'contract_code'
        elif market['swap']:
            if market['inverse']:
                method = 'contractPublicGetSwapExMarketHistoryTrade'
            elif market['linear']:
                method = 'contractPublicGetLinearSwapExMarketHistoryTrade'
            fieldName = 'contract_code'
        request[fieldName] = market['id']
        if limit is not None:
            request['size'] = limit  # max 2000
        response = await getattr(self, method)(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=None):
        #
        #     {
        #         "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'),
        ]

    async def fetch_ohlcv(self, symbol, timeframe='1m', since=None, limit=None, params={}):
        """
        fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
        :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|None since: timestamp in ms of the earliest candle to fetch
        :param int|None limit: the maximum amount of candles to fetch
        :param dict params: extra parameters specific to the huobi api endpoint
        :returns [[int]]: A list of candles ordered as timestamp, open, high, low, close, volume
        """
        await self.load_markets()
        market = self.market(symbol)
        request = {
            '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 / 1000), spot only
            # 'to': self.seconds(), spot only
        }
        fieldName = 'symbol'
        price = self.safe_string(params, 'price')
        params = self.omit(params, 'price')
        method = 'spotPublicGetMarketHistoryCandles'
        if market['spot']:
            if since is not None:
                request['from'] = int(since / 1000)
            if limit is not None:
                request['size'] = limit  # max 2000
        elif market['future']:
            if market['inverse']:
                if price == 'mark':
                    method = 'contractPublicGetIndexMarketHistoryMarkPriceKline'
                elif price == 'index':
                    method = 'contractPublicGetIndexMarketHistoryIndex'
                elif price == 'premiumIndex':
                    raise BadRequest(self.id + ' ' + market['type'] + ' has no api endpoint for ' + price + ' kline data')
                else:
                    method = 'contractPublicGetMarketHistoryKline'
            elif market['linear']:
                if price == 'mark':
                    method = 'contractPublicGetIndexMarketHistoryLinearSwapMarkPriceKline'
                elif price == 'index':
                    raise BadRequest(self.id + ' ' + market['type'] + ' has no api endpoint for ' + price + ' kline data')
                elif price == 'premiumIndex':
                    method = 'contractPublicGetIndexMarketHistoryLinearSwapPremiumIndexKline'
                else:
                    method = 'contractPublicGetLinearSwapExMarketHistoryKline'
                fieldName = 'contract_code'
        elif market['swap']:
            if market['inverse']:
                if price == 'mark':
                    method = 'contractPublicGetIndexMarketHistorySwapMarkPriceKline'
                elif price == 'index':
                    raise BadRequest(self.id + ' ' + market['type'] + ' has no api endpoint for ' + price + ' kline data')
                elif price == 'premiumIndex':
                    method = 'contractPublicGetIndexMarketHistorySwapPremiumIndexKline'
                else:
                    method = 'contractPublicGetSwapExMarketHistoryKline'
            elif market['linear']:
                if price == 'mark':
                    method = 'contractPublicGetIndexMarketHistoryLinearSwapMarkPriceKline'
                elif price == 'index':
                    raise BadRequest(self.id + ' ' + market['type'] + ' has no api endpoint for ' + price + ' kline data')
                elif price == 'premiumIndex':
                    method = 'contractPublicGetIndexMarketHistoryLinearSwapPremiumIndexKline'
                else:
                    method = 'contractPublicGetLinearSwapExMarketHistoryKline'
            fieldName = 'contract_code'
        if market['contract']:
            if limit is None:
                limit = 2000
            request['size'] = limit
            if price is None:
                duration = self.parse_timeframe(timeframe)
                if since is None:
                    now = self.seconds()
                    request['from'] = now - duration * (limit - 1)
                    request['to'] = now
                else:
                    start = int(since / 1000)
                    request['from'] = start
                    request['to'] = self.sum(start, duration * (limit - 1))
        request[fieldName] = market['id']
        response = await getattr(self, method)(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_value(response, 'data', [])
        return self.parse_ohlcvs(data, market, timeframe, since, limit)

    async def fetch_accounts(self, params={}):
        """
        fetch all the accounts associated with a profile
        :param dict params: extra parameters specific to the huobi api endpoint
        :returns dict: a dictionary of `account structures <https://docs.ccxt.com/en/latest/manual.html#account-structure>` indexed by the account type
        """
        await self.load_markets()
        response = await 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,
        }

    async def fetch_account_id_by_type(self, type, params={}):
        accounts = await self.load_accounts()
        accountId = self.safe_value(params, 'account-id')
        if accountId is not None:
            return accountId
        indexedAccounts = self.index_by(accounts, 'type')
        defaultAccount = self.safe_value(accounts, 0, {})
        account = self.safe_value(indexedAccounts, type, defaultAccount)
        return self.safe_string(account, 'id')

    async def fetch_currencies(self, params={}):
        """
        fetches all available currencies on an exchange
        :param dict params: extra parameters specific to the huobi api endpoint
        :returns dict: an associative dictionary of currencies
        """
        response = await 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_value(response, 'data', [])
        result = {}
        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)
            self.options['networkChainIdsByNames'][code] = {}
            chains = self.safe_value(entry, 'chains', [])
            networks = {}
            instStatus = self.safe_string(entry, 'instStatus')
            currencyActive = instStatus == 'normal'
            minPrecision = None
            minWithdraw = None
            maxWithdraw = None
            deposit = None
            withdraw = None
            for j in range(0, len(chains)):
                chainEntry = chains[j]
                uniqueChainId = self.safe_string(chainEntry, 'chain')  # i.e. usdterc20, trc20usdt ...
                title = self.safe_string(chainEntry, 'displayName')
                self.options['networkChainIdsByNames'][code][title] = uniqueChainId
                self.options['networkNamesByChainIds'][uniqueChainId] = title
                networkCode = self.network_id_to_code(title, code)
                minWithdraw = self.safe_number(chainEntry, 'minWithdrawAmt')
                maxWithdraw = self.safe_number(chainEntry, 'maxWithdrawAmt')
                withdrawStatus = self.safe_string(chainEntry, 'withdrawStatus')
                depositStatus = self.safe_string(chainEntry, 'depositStatus')
                withdrawEnabled = (withdrawStatus == 'allowed')
                depositEnabled = (depositStatus == 'allowed')
                active = withdrawEnabled and depositEnabled
                precision = self.parse_precision(self.safe_string(chainEntry, 'withdrawPrecision'))
                if precision is not None:
                    minPrecision = precision if (minPrecision is None) else Precise.string_min(precision, minPrecision)
                if withdrawEnabled and not withdraw:
                    withdraw = True
                elif not withdrawEnabled:
                    withdraw = False
                if depositEnabled and not deposit:
                    deposit = True
                elif not depositEnabled:
                    deposit = False
                fee = self.safe_number(chainEntry, 'transactFeeWithdraw')
                networks[networkCode] = {
                    'info': chainEntry,
                    'id': uniqueChainId,
                    'network': networkCode,
                    'limits': {
                        'withdraw': {
                            'min': minWithdraw,
                            'max': maxWithdraw,
                        },
                    },
                    'active': active,
                    'deposit': depositEnabled,
                    'withdraw': withdrawEnabled,
                    'fee': fee,
                    'precision': self.parse_number(precision),
                }
            result[code] = {
                'info': entry,
                'code': code,
                'id': currencyId,
                'active': currencyActive,
                'deposit': deposit,
                'withdraw': withdraw,
                'fee': None,
                'name': None,
                'limits': {
                    'amount': {
                        'min': None,
                        'max': None,
                    },
                    'withdraw': {
                        'min': minWithdraw,
                        'max': maxWithdraw,
                    },
                },
                'precision': self.parse_number(minPrecision),
                'networks': networks,
            }
        return result

    def network_id_to_code(self, networkId, currencyCode=None):
        # here network-id is provided as a 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(huobi, self).network_id_to_code(networkTitle)

    def network_code_to_id(self, networkCode, currencyCode=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, {})
        networkTitle = super(huobi, self).network_code_to_id(networkCode)
        return self.safe_value(uniqueNetworkIds, networkTitle, networkTitle)

    async def fetch_balance(self, params={}):
        """
        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 huobi api endpoint
        :returns dict: a `balance structure <https://docs.ccxt.com/en/latest/manual.html?#balance-structure>`
        """
        await self.load_markets()
        type = None
        type, params = self.handle_market_type_and_params('fetchBalance', None, params)
        options = self.safe_value(self.options, 'fetchBalance', {})
        request = {}
        method = None
        spot = (type == 'spot')
        future = (type == 'future')
        swap = (type == 'swap')
        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))
        if spot or margin:
            if margin:
                if isolated:
                    method = 'spotPrivateGetV1MarginAccountsBalance'
                else:
                    method = 'spotPrivateGetV1CrossMarginAccountsBalance'
            else:
                await self.load_accounts()
                accountId = await self.fetch_account_id_by_type(type, params)
                request['account-id'] = accountId
                method = 'spotPrivateGetV1AccountAccountsAccountIdBalance'
        elif linear:
            if isolated:
                method = 'contractPrivatePostLinearSwapApiV1SwapAccountInfo'
            else:
                method = 'contractPrivatePostLinearSwapApiV1SwapCrossAccountInfo'
        elif inverse:
            if future:
                method = 'contractPrivatePostApiV1ContractAccountInfo'
            elif swap:
                method = 'contractPrivatePostSwapApiV1SwapAccountInfo'
        response = await getattr(self, method)(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": 200.000000000000000000,
        #                 "margin_static": 200.000000000000000000,
        #                 "margin_position": 0,
        #                 "margin_frozen": 0,
        #                 "profit_real": 0E-18,
        #                 "profit_unreal": 0,
        #                 "withdraw_available": 2E+2,
        #                 "risk_rate": null,
        #                 "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 = {'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 = {}
                    for i in range(0, len(balances)):
                        balance = balances[i]
                        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 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 = {}
                        accountsByCode[code] = account
                        symbol = market['symbol']
                        result[symbol] = self.safe_balance(accountsByCode)
            else:
                account = self.account()
                account['free'] = self.safe_string(first, 'margin_balance', 'margin_available')
                account['used'] = self.safe_string(first, 'margin_frozen')
                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

    async def fetch_order(self, id, symbol=None, params={}):
        """
        fetches information on an order made by the user
        :param str|None symbol: unified symbol of the market the order was made in
        :param dict params: extra parameters specific to the huobi api endpoint
        :returns dict: An `order structure <https://docs.ccxt.com/en/latest/manual.html#order-structure>`
        """
        await 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 = {
            # 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
        }
        method = None
        if marketType == 'spot':
            clientOrderId = self.safe_string(params, 'clientOrderId')
            method = 'spotPrivateGetV1OrderOrdersOrderId'
            if clientOrderId is not None:
                method = 'spotPrivateGetV1OrderOrdersGetClientOrder'
                # will be filled below in self.extend()
                # they expect clientOrderId instead of client-order-id
                # request['clientOrderId'] = clientOrderId
            else:
                request['order-id'] = id
        else:
            if symbol is None:
                raise ArgumentsRequired(self.id + ' fetchOrder() requires a symbol for ' + marketType + ' orders')
            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':
                    method = 'contractPrivatePostLinearSwapApiV1SwapOrderInfo'
                elif marginMode == 'cross':
                    method = 'contractPrivatePostLinearSwapApiV1SwapCrossOrderInfo'
            elif market['inverse']:
                if marketType == 'future':
                    method = 'contractPrivatePostApiV1ContractOrderInfo'
                    request['symbol'] = market['settleId']
                elif marketType == 'swap':
                    method = 'contractPrivatePostSwapApiV1SwapOrderInfo'
                else:
                    raise NotSupported(self.id + ' fetchOrder() does not support ' + marketType + ' markets')
            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'])
        response = await getattr(self, method)(self.extend(request, params))
        #
        # 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

    async def fetch_spot_orders_by_states(self, states, symbol=None, since=None, limit=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')
        await self.load_markets()
        market = None
        request = {
            # 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)
        if limit is not None:
            request['size'] = limit
        response = await getattr(self, method)(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_value(response, 'data', [])
        return self.parse_orders(data, market, since, limit)

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

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

    async def fetch_contract_orders(self, symbol=None, since=None, limit=None, params={}):
        if symbol is None:
            raise ArgumentsRequired(self.id + ' fetchContractOrders() requires a symbol argument')
        await self.load_markets()
        market = self.market(symbol)
        marketType = None
        marketType, params = self.handle_market_type_and_params('fetchOrders', market, params)
        request = {
            # 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 -----
            'contract': market['id'],
            '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)
            'type': 1,  # 1:All Orders,2:Order in Finished Status
            '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
        }
        if since is not None:
            request['start_time'] = since  # max 90 days back
            # request['end_time'] = since + 172800000  # 48 hours window
        method = None
        if market['linear']:
            marginMode = None
            marginMode, params = self.handle_margin_mode_and_params('fetchContractOrders', params)
            marginMode = 'cross' if (marginMode is None) else marginMode
            method = self.get_supported_mapping(marginMode, {
                'isolated': 'contractPrivatePostLinearSwapApiV3SwapHisorders',
                'cross': 'contractPrivatePostLinearSwapApiV3SwapCrossHisorders',
            })
        elif market['inverse']:
            method = self.get_supported_mapping(marketType, {
                'future': 'contractPrivatePostApiV3ContractHisorders',
                'swap': 'contractPrivatePostSwapApiV3SwapHisorders',
            })
            if marketType == 'future':
                request['symbol'] = market['settleId']
        if limit is not None:
            request['page_size'] = limit
        response = await getattr(self, method)(self.extend(request, params))
        #
        #     {
        #         "status": "ok",
        #         "data": {
        #             "orders": [
        #                 {
        #                     "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)
        #                 }
        #             ],
        #             "total_page": 19,
        #             "current_page": 1,
        #             "total_size": 19
        #         },
        #         "ts": 1604370617322
        #     }
        #
        orders = self.safe_value(response, 'data', [])
        return self.parse_orders(orders, market, since, limit)

    async def fetch_closed_contract_orders(self, symbol=None, since=None, limit=None, params={}):
        request = {
            '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 await self.fetch_contract_orders(symbol, since, limit, self.extend(request, params))

    async def fetch_orders(self, symbol=None, since=None, limit=None, params={}):
        """
        fetches information on multiple orders made by the user
        :param str|None symbol: unified market symbol of the market orders were made in
        :param int|None since: the earliest time in ms to fetch orders for
        :param int|None limit: the maximum number of  orde structures to retrieve
        :param dict params: extra parameters specific to the huobi api endpoint
        :returns [dict]: a list of `order structures <https://docs.ccxt.com/en/latest/manual.html#order-structure>`
        """
        await 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)
        method = self.get_supported_mapping(marketType, {
            'spot': 'fetchSpotOrders',
            'swap': 'fetchContractOrders',
            'future': 'fetchContractOrders',
        })
        if method is None:
            raise NotSupported(self.id + ' fetchOrders() does not support ' + marketType + ' markets yet')
        contract = (marketType == 'swap') or (marketType == 'future')
        if contract and (symbol is None):
            raise ArgumentsRequired(self.id + ' fetchOrders() requires a symbol argument for ' + marketType + ' orders')
        return await getattr(self, method)(symbol, since, limit, params)

    async def fetch_closed_orders(self, symbol=None, since=None, limit=None, params={}):
        """
        fetches information on multiple closed orders made by the user
        :param str|None symbol: unified market symbol of the market orders were made in
        :param int|None since: the earliest time in ms to fetch orders for
        :param int|None limit: the maximum number of  orde structures to retrieve
        :param dict params: extra parameters specific to the huobi api endpoint
        :returns [dict]: a list of `order structures <https://docs.ccxt.com/en/latest/manual.html#order-structure>`
        """
        await self.load_markets()
        market = None
        if symbol is not None:
            market = self.market(symbol)
        marketType = None
        marketType, params = self.handle_market_type_and_params('fetchClosedOrders', market, params)
        method = self.get_supported_mapping(marketType, {
            'spot': 'fetchClosedSpotOrders',
            'swap': 'fetchClosedContractOrders',
            'future': 'fetchClosedContractOrders',
        })
        if method is None:
            raise NotSupported(self.id + ' fetchClosedOrders() does not support ' + marketType + ' markets yet')
        return await getattr(self, method)(symbol, since, limit, params)

    async def fetch_open_orders(self, symbol=None, since=None, limit=None, params={}):
        """
        fetch all unfilled currently open orders
        :param str|None symbol: unified market symbol
        :param int|None since: the earliest time in ms to fetch open orders for
        :param int|None limit: the maximum number of  open orders structures to retrieve
        :param dict params: extra parameters specific to the huobi api endpoint
        :returns [dict]: a list of `order structures <https://docs.ccxt.com/en/latest/manual.html#order-structure>`
        """
        await self.load_markets()
        market = None
        if symbol is not None:
            market = self.market(symbol)
        marketType = None
        marketType, params = self.handle_market_type_and_params('fetchOpenOrders', market, params)
        request = {
            # spot -----------------------------------------------------------
            # 'account-id': account['id'],
            # 'symbol': market['id'],
            # 'side': 'buy',  # buy, sell
            # 'from': 'id',  # order id to begin with
            # 'direct': 'prev',  # prev, next, mandatory if from is defined
            # 'size': 100,  # default 100, max 500
            # futures --------------------------------------------------------
            # 'symbol': market['settleId'],
            # 'page_index': 1,  # default 1
            # 'page_size': limit,  # default 20, max 50
            # 'sort_by': 'created_at',  # created_at, update_time, descending sorting field
            # 'trade_type': 0,  # 0 all, 1 buy long, 2 sell short, 3 buy short, 4 sell long
        }
        method = None
        if marketType == 'spot':
            method = 'spotPrivateGetV1OrderOpenOrders'
            if symbol is not None:
                market = self.market(symbol)
                request['symbol'] = market['id']
            # todo replace with fetchAccountIdByType
            accountId = self.safe_string(params, 'account-id')
            if accountId is None:
                # pick the first account
                await self.load_accounts()
                for i in range(0, len(self.accounts)):
                    account = self.accounts[i]
                    if 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')
        else:
            if symbol is None:
                raise ArgumentsRequired(self.id + ' fetchOpenOrders() requires a symbol for ' + marketType + ' orders')
            market = self.market(symbol)
            request['contract_code'] = market['id']
            if market['linear']:
                marginMode = None
                marginMode, params = self.handle_margin_mode_and_params('fetchOpenOrders', params)
                marginMode = 'cross' if (marginMode is None) else marginMode
                if marginMode == 'isolated':
                    method = 'contractPrivatePostLinearSwapApiV1SwapOpenorders'
                elif marginMode == 'cross':
                    method = 'contractPrivatePostLinearSwapApiV1SwapCrossOpenorders'
            elif market['inverse']:
                if market['future']:
                    method = 'contractPrivatePostApiV1ContractOpenorders'
                    request['symbol'] = market['settleId']
                elif market['swap']:
                    method = 'contractPrivatePostSwapApiV1SwapOpenorders'
            if limit is not None:
                request['page_size'] = limit
        response = await getattr(self, method)(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
        #     }
        #
        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):
        statuses = {
            # 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, market=None):
        #
        # 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
        #     }
        #
        # 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)
        #     }
        #
        id = self.safe_string_2(order, 'id', 'order_id_str')
        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]
        status = self.parse_order_status(self.safe_string_2(order, 'state', 'status'))
        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-order-id')
        cost = None
        amount = None
        if (type is not None) and (type.find('market') >= 0):
            # for market orders amount is in quote currency, meaning it is the cost
            if side == 'sell':
                cost = self.safe_string(order, 'field-cash-amount')
            else:
                cost = self.safe_string(order, '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
        filled = self.safe_string_n(order, ['filled-amount', 'field-amount', 'trade_volume'])  # typo in their API, filled amount
        price = self.safe_string(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,
            }
        stopPrice = self.safe_string(order, 'stop-price')
        average = self.safe_string(order, 'trade_avg_price')
        trades = self.safe_value(order, 'trades')
        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,
            'stopPrice': stopPrice,
            'triggerPrice': stopPrice,
            'average': average,
            'cost': cost,
            'amount': amount,
            'filled': filled,
            'remaining': None,
            'status': status,
            'fee': fee,
            'trades': trades,
        }, market)

    async def create_order(self, symbol, type, side, amount, price=None, params={}):
        """
        create a trade order
        :param str symbol: unified symbol of the market to create an order in
        :param str type: 'market' or 'limit'
        :param str side: 'buy' or 'sell'
        :param float amount: how much of currency you want to trade in units of base currency
        :param float|None price: the price at which the order is to be fullfilled, in units of the quote currency, ignored in market orders
        :param dict params: extra parameters specific to the huobi api endpoint
        :param float|None params['stopPrice']: *spot and margin only* The price at which a trigger order is triggered at
        :param str|None params['operator']: *spot and margin only* gte or lte, trigger price condition
        :param str|None params['offset']: *contract only* 'open', 'close', or 'both', required in hedge mode
        :param bool|None params['postOnly']: *contract only* True or False
        :returns dict: an `order structure <https://docs.ccxt.com/en/latest/manual.html#order-structure>`
        """
        await self.load_markets()
        market = self.market(symbol)
        marketType, query = self.handle_market_type_and_params('createOrder', market, params)
        method = self.get_supported_mapping(marketType, {
            'spot': 'createSpotOrder',
            'swap': 'createContractOrder',
            'future': 'createContractOrder',
        })
        if method is None:
            raise NotSupported(self.id + ' createOrder() does not support ' + marketType + ' markets yet')
        return await getattr(self, method)(symbol, type, side, amount, price, query)

    async def create_spot_order(self, symbol, type, side, amount, price=None, params={}):
        await self.load_markets()
        await self.load_accounts()
        market = self.market(symbol)
        accountId = await self.fetch_account_id_by_type(market['type'])
        request = {
            # 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'], {})
        stopPrice = self.safe_string_2(params, 'stopPrice', 'stop-price')
        if stopPrice is None:
            stopOrderTypes = self.safe_value(options, 'stopOrderTypes', {})
            if orderType in stopOrderTypes:
                raise ArgumentsRequired(self.id + ' createOrder() requires a stopPrice or a stop-price parameter for a stop order')
        else:
            stopOperator = self.safe_string(params, 'operator')
            if stopOperator is None:
                raise ArgumentsRequired(self.id + ' createOrder() requires an operator parameter "gte" or "lte" for a stop order')
            params = self.omit(params, ['stopPrice', 'stop-price'])
            request['stop-price'] = self.price_to_precision(symbol, stopPrice)
            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 = self.safe_value(params, 'postOnly', False)
        if postOnly:
            orderType = 'limit-maker'
        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
        params = self.omit(params, ['clientOrderId', 'client-order-id', 'postOnly'])
        if (orderType == 'market') and (side == 'buy'):
            if self.options['createMarketBuyOrderRequiresPrice']:
                if price is None:
                    raise InvalidOrder(self.id + " market buy order requires price argument to calculate cost(total amount of quote currency to spend for buying, amount * price). To switch off self warning exception and specify cost in the amount argument, set .options['createMarketBuyOrderRequiresPrice'] = False. Make sure you know what you're doing.")
                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)
                    request['amount'] = self.cost_to_precision(symbol, Precise.string_mul(amountString, priceString))
            else:
                request['amount'] = self.cost_to_precision(symbol, amount)
        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)
        response = await self.spotPrivatePostV1OrderOrdersPlace(self.extend(request, params))
        #
        # spot
        #
        #     {"status":"ok","data":"438398393065481"}
        #
        id = self.safe_string(response, 'data')
        return {
            'info': response,
            'id': id,
            'timestamp': None,
            'datetime': None,
            'lastTradeTimestamp': None,
            'status': None,
            'symbol': None,
            'type': None,
            'side': None,
            'price': None,
            'amount': None,
            'filled': None,
            'remaining': None,
            'cost': None,
            'trades': None,
            'fee': None,
            'clientOrderId': None,
            'average': None,
        }

    async def create_contract_order(self, symbol, type, side, amount, price=None, params={}):
        offset = self.safe_string(params, 'offset')
        stopPrice = self.safe_string(params, 'stopPrice')
        if stopPrice is not None:
            raise NotSupported(self.id + ' createOrder() supports tp_trigger_price + tp_order_price for take profit orders and/or sl_trigger_price + sl_order price for stop loss orders, stop orders are supported only with open long orders and open short orders')
        market = self.market(symbol)
        request = {
            # 'symbol': 'BTC',  # optional, case-insensitive, both uppercase and lowercase are supported, "BTC", "ETH", ...
            # 'contract_type': 'this_week',  # optional, self_week, next_week, quarter, next_quarter
            'contract_code': market['id'],  # optional BTC180914
            # 'client_order_id': clientOrderId,  # optional, must be less than 9223372036854775807
            # 'price': self.price_to_precision(symbol, price),  # optional
            'volume': self.amount_to_precision(symbol, amount),
            'direction': side,  # buy, sell
            # 'offset': offset,  # open, close, both
            #
            #     direction buy, offset open = open long
            #     direction sell, offset close = close long
            #     direction sell, offset open = open short
            #     direction buy, offset close = close short
            #
            # 'reduce_only': 0,  # 1 or 0, in hedge mode it is invalid, and in one-way mode its value is 0 when not filled
            'lever_rate': 1,  # required, using leverage greater than 20x requires prior approval of high-leverage agreement
            # 'order_price_type': 'limit',  # required
            #
            #     order_price_type can be:
            #
            #     limit
            #     opponent  # BBO
            #     post_only
            #     optimal_5
            #     optimal_10
            #     optimal_20
            #     ioc
            #     fok
            #     opponent_ioc  # IOC order using the BBO price
            #     optimal_5_ioc
            #     optimal_10_ioc
            #     optimal_20_ioc
            #     opponent_fok  # FOR order using the BBO price
            #     optimal_5_fok
            #     optimal_10_fok
            #     optimal_20_fok
            #
            # 'tp_trigger_price': self.price_to_precision(symbol, triggerPrice),
            # 'tp_order_price': self.price_to_precision(symbol, price),
            # 'tp_order_price_type': 'limit',  # limit，optimal_5，optimal_10，optimal_20
            # 'sl_trigger_price': self.price_to_precision(symbol, stopLossPrice),
            # 'sl_order_price': self.price_to_precision(symbol, price),
            # 'sl_order_price_type': 'limit',  # limit，optimal_5，optimal_10，optimal_20
        }
        stopLossOrderPrice = self.safe_string(params, 'sl_order_price')
        stopLossTriggerPrice = self.safe_string(params, 'sl_trigger_price')
        takeProfitOrderPrice = self.safe_string(params, 'tp_order_price')
        takeProfitTriggerPrice = self.safe_string(params, 'tp_trigger_price')
        isOpenOrder = (offset == 'open')
        isStopOrder = False
        if stopLossTriggerPrice is not None:
            request['sl_trigger_price'] = self.price_to_precision(symbol, stopLossTriggerPrice)
            isStopOrder = True
            if price is not None:
                request['sl_order_price'] = self.price_to_precision(symbol, price)
        if stopLossOrderPrice is not None:
            request['sl_order_price'] = self.price_to_precision(symbol, stopLossOrderPrice)
            isStopOrder = True
        if takeProfitTriggerPrice is not None:
            request['tp_trigger_price'] = self.price_to_precision(symbol, takeProfitTriggerPrice)
            isStopOrder = True
            if price is not None:
                request['tp_order_price'] = self.price_to_precision(symbol, price)
        if takeProfitOrderPrice is not None:
            request['tp_order_price'] = self.price_to_precision(symbol, takeProfitOrderPrice)
            isStopOrder = True
        if isStopOrder and not isOpenOrder:
            raise NotSupported(self.id + ' createOrder() supports tp_trigger_price + tp_order_price for take profit orders and/or sl_trigger_price + sl_order price for stop loss orders, stop orders are supported only with open long orders and open short orders')
        params = self.omit(params, ['sl_order_price', 'sl_trigger_price', 'tp_order_price', 'tp_trigger_price'])
        postOnly = self.safe_value(params, 'postOnly', False)
        if postOnly:
            type = 'post_only'
        if type == 'limit' or type == 'ioc' or type == 'fok' or type == 'post_only':
            request['price'] = self.price_to_precision(symbol, price)
        request['order_price_type'] = type
        broker = self.safe_value(self.options, 'broker', {})
        brokerId = self.safe_string(broker, 'id')
        request['channel_code'] = brokerId
        clientOrderId = self.safe_string_2(params, 'client_order_id', 'clientOrderId')
        if clientOrderId is not None:
            request['client_order_id'] = clientOrderId
            params = self.omit(params, ['client_order_id', 'clientOrderId'])
        method = None
        if market['linear']:
            marginMode = None
            marginMode, params = self.handle_margin_mode_and_params('createOrder', params)
            marginMode = 'cross' if (marginMode is None) else marginMode
            if marginMode == 'isolated':
                method = 'contractPrivatePostLinearSwapApiV1SwapOrder'
            elif marginMode == 'cross':
                method = 'contractPrivatePostLinearSwapApiV1SwapCrossOrder'
        elif market['inverse']:
            if market['swap']:
                method = 'contractPrivatePostSwapApiV1SwapOrder'
            elif market['future']:
                method = 'contractPrivatePostApiV1ContractOrder'
        response = await getattr(self, method)(self.extend(request, params))
        #
        # linear swap cross margin
        #
        #     {
        #         "status":"ok",
        #         "data":{
        #             "order_id":924660854912552960,
        #             "order_id_str":"924660854912552960"
        #         },
        #         "ts":1640497927185
        #     }
        #
        data = self.safe_value(response, 'data', {})
        return self.parse_order(data, market)

    async def cancel_order(self, id, symbol=None, params={}):
        """
        cancels an open order
        :param str id: order id
        :param str|None symbol: unified symbol of the market the order was made in
        :param dict params: extra parameters specific to the huobi api endpoint
        :returns dict: An `order structure <https://docs.ccxt.com/en/latest/manual.html#order-structure>`
        """
        await 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 = {
            # 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
        }
        method = None
        if marketType == 'spot':
            clientOrderId = self.safe_string_2(params, 'client-order-id', 'clientOrderId')
            method = 'spotPrivatePostV1OrderOrdersOrderIdSubmitcancel'
            if clientOrderId is None:
                request['order-id'] = id
            else:
                request['client-order-id'] = clientOrderId
                method = 'spotPrivatePostV1OrderOrdersSubmitCancelClientOrder'
                params = self.omit(params, ['client-order-id', 'clientOrderId'])
        else:
            if symbol is None:
                raise ArgumentsRequired(self.id + ' cancelOrder() requires a symbol for ' + marketType + ' orders')
            request['contract_code'] = market['id']
            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':
                    method = 'contractPrivatePostLinearSwapApiV1SwapCancel'
                elif marginMode == 'cross':
                    method = 'contractPrivatePostLinearSwapApiV1SwapCrossCancel'
            elif market['inverse']:
                if market['future']:
                    method = 'contractPrivatePostApiV1ContractCancel'
                    request['symbol'] = market['settleId']
                elif market['swap']:
                    method = 'contractPrivatePostSwapApiV1SwapCancel'
            else:
                raise NotSupported(self.id + ' cancelOrder() does not support ' + marketType + ' markets')
            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'])
        response = await getattr(self, method)(self.extend(request, params))
        #
        # spot
        #
        #     {
        #         'status': 'ok',
        #         'data': '10138899000',
        #     }
        #
        # linear swap cross margin
        #
        #     {
        #         "status":"ok",
        #         "data":{
        #             "errors":[],
        #             "successes":"924660854912552960"
        #         },
        #         "ts":1640504486089
        #     }
        #
        return self.extend(self.parse_order(response, market), {
            'id': id,
            'status': 'canceled',
        })

    async def cancel_orders(self, ids, symbol=None, params={}):
        """
        cancel multiple orders
        :param [str] ids: order ids
        :param str|None symbol: unified market symbol, default is None
        :param dict params: extra parameters specific to the huobi api endpoint
        :returns dict: an list of `order structures <https://docs.ccxt.com/en/latest/manual.html#order-structure>`
        """
        await self.load_markets()
        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 = {
            # spot -----------------------------------------------------------
            # 'order-ids': ids.jsoin(','),  # 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'],
        }
        method = 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'] = ','.join(ids)
            else:
                if isinstance(clientOrderIds, str):
                    request['client-order-ids'] = clientOrderIds
                else:
                    request['client-order-ids'] = ','.join(clientOrderIds)
                params = self.omit(params, ['client-order-id', 'client-order-ids', 'clientOrderId', 'clientOrderIds'])
            method = 'spotPrivatePostV1OrderOrdersBatchcancel'
        else:
            if symbol is None:
                raise ArgumentsRequired(self.id + ' cancelOrders() requires a symbol for ' + marketType + ' orders')
            market = self.market(symbol)
            request['contract_code'] = market['id']
            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':
                    method = 'contractPrivatePostLinearSwapApiV1SwapCancel'
                elif marginMode == 'cross':
                    method = 'contractPrivatePostLinearSwapApiV1SwapCrossCancel'
            elif market['inverse']:
                if market['future']:
                    method = 'contractPrivatePostApiV1ContractCancel'
                    request['symbol'] = market['settleId']
                elif market['swap']:
                    method = 'contractPrivatePostSwapApiV1SwapCancel'
                else:
                    raise NotSupported(self.id + ' cancelOrders() does not support ' + marketType + ' markets')
            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'])
        response = await getattr(self, method)(self.extend(request, params))
        #
        # 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"
        #                 }
        #             ]
        #         }
        #     }
        #
        # contracts
        #
        #     {
        #         "status": "ok",
        #         "data": {
        #             "errors": [
        #                 {
        #                     "order_id": "769206471845261312",
        #                     "err_code": 1061,
        #                     "err_msg": "This order doesnt exist."
        #                 }
        #             ],
        #             "successes": "773120304138219520"
        #         },
        #         "ts": 1604367997451
        #     }
        #
        return response

    async def cancel_all_orders(self, symbol=None, params={}):
        """
        cancel all open orders
        :param str|None 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 huobi api endpoint
        :returns [dict]: a list of `order structures <https://docs.ccxt.com/en/latest/manual.html#order-structure>`
        """
        await 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 = {
            # 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
        }
        method = None
        if marketType == 'spot':
            if symbol is not None:
                market = self.market(symbol)
                request['symbol'] = market['id']
            method = 'spotPrivatePostV1OrderOrdersBatchCancelOpenOrders'
        else:
            if symbol is None:
                raise ArgumentsRequired(self.id + ' cancelAllOrders() requires a symbol for ' + marketType + ' orders')
            market = self.market(symbol)
            request['contract_code'] = market['id']
            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':
                    method = 'contractPrivatePostLinearSwapApiV1SwapCancelallall'
                elif marginMode == 'cross':
                    method = 'contractPrivatePostLinearSwapApiV1SwapCrossCancelall'
            elif market['inverse']:
                if marketType == 'future':
                    method = 'contractPrivatePostApiV1ContractCancelall'
                    request['symbol'] = market['settleId']
                elif marketType == 'swap':
                    method = 'contractPrivatePostSwapApiV1SwapCancelall'
                else:
                    raise NotSupported(self.id + ' cancelAllOrders() does not support ' + marketType + ' markets')
        response = await getattr(self, method)(self.extend(request, params))
        #
        #     {
        #         code: 200,
        #         data: {
        #             "success-count": 2,
        #             "failed-count": 0,
        #             "next-id": 5454600
        #         }
        #     }
        #
        return response

    def parse_deposit_address(self, depositAddress, 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, code),
            'note': note,
            'info': depositAddress,
        }

    async def fetch_deposit_addresses_by_network(self, code, params={}):
        """
        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 huobi api endpoint
        :returns dict: a dictionary of `address structures <https://docs.ccxt.com/en/latest/manual.html#address-structure>` indexed by the network
        """
        await self.load_markets()
        currency = self.currency(code)
        request = {
            'currency': currency['id'],
        }
        response = await 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')

    async def fetch_deposit_address(self, code, params={}):
        """
        fetch the deposit address for a currency associated with self account
        :param str code: unified currency code
        :param dict params: extra parameters specific to the huobi api endpoint
        :returns dict: an `address structure <https://docs.ccxt.com/en/latest/manual.html#address-structure>`
        """
        await self.load_markets()
        currency = self.currency(code)
        networkCode, paramsOmited = self.handle_network_code_and_params(params)
        indexedAddresses = await self.fetch_deposit_addresses_by_network(code, paramsOmited)
        selectedNetworkCode = self.select_network_code_from_unified_networks(currency['code'], networkCode, indexedAddresses)
        return indexedAddresses[selectedNetworkCode]

    async def fetch_withdraw_addresses(self, code, note=None, networkCode=None, params={}):
        await self.load_markets()
        currency = self.currency(code)
        request = {
            'currency': currency['id'],
        }
        response = await 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)
        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

    async def fetch_deposits(self, code=None, since=None, limit=None, params={}):
        """
        fetch all deposits made to an account
        :param str|None code: unified currency code
        :param int|None since: the earliest time in ms to fetch deposits for
        :param int|None limit: the maximum number of deposits structures to retrieve
        :param dict params: extra parameters specific to the huobi api endpoint
        :returns [dict]: a list of `transaction structures <https://docs.ccxt.com/en/latest/manual.html#transaction-structure>`
        """
        if limit is None or limit > 100:
            limit = 100
        await self.load_markets()
        currency = None
        if code is not None:
            currency = self.currency(code)
        request = {
            '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 = await 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)

    async def fetch_withdrawals(self, code=None, since=None, limit=None, params={}):
        """
        fetch all withdrawals made from an account
        :param str|None code: unified currency code
        :param int|None since: the earliest time in ms to fetch withdrawals for
        :param int|None limit: the maximum number of withdrawals structures to retrieve
        :param dict params: extra parameters specific to the huobi api endpoint
        :returns [dict]: a list of `transaction structures <https://docs.ccxt.com/en/latest/manual.html#transaction-structure>`
        """
        if limit is None or limit > 100:
            limit = 100
        await self.load_markets()
        currency = None
        if code is not None:
            currency = self.currency(code)
        request = {
            '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 = await 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, currency=None):
        #
        # 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')
        return {
            'info': transaction,
            'id': self.safe_string_2(transaction, 'id', 'data'),
            'txid': self.safe_string(transaction, 'tx-hash'),
            'timestamp': timestamp,
            'datetime': self.iso8601(timestamp),
            'network': self.network_id_to_code(networkId, code),
            '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'),
            'fee': {
                'currency': code,
                'cost': self.parse_number(feeCost),
                'rate': None,
            },
        }

    def parse_transaction_status(self, status):
        statuses = {
            # 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',
        }
        return self.safe_string(statuses, status, status)

    async def withdraw(self, code, amount, address, tag=None, params={}):
        """
        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|None tag:
        :param dict params: extra parameters specific to the huobi api endpoint
        :returns dict: a `transaction structure <https://docs.ccxt.com/en/latest/manual.html#transaction-structure>`
        """
        tag, params = self.handle_withdraw_tag_and_params(tag, params)
        await self.load_markets()
        self.check_address(address)
        currency = self.currency(code)
        request = {
            '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_value(withdrawOptions, 'includeFee', False):
            fee = self.safe_number(params, 'fee')
            if fee is None:
                currencies = await self.fetch_currencies()
                self.currencies = 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 = await self.spotPrivatePostV1DwWithdrawApiCreate(self.extend(request, params))
        #
        #     {
        #         "status": "ok",
        #         "data": "99562054"
        #     }
        #
        return self.parse_transaction(response, currency)

    def parse_transfer(self, transfer, currency=None):
        #
        # 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,
        }

    async def transfer(self, code, amount, fromAccount, toAccount, params={}):
        """
        transfer currency internally between wallets on the same account
        see https://huobiapi.github.io/docs/dm/v1/en/#transfer-margin-between-spot-account-and-future-account
        see https://huobiapi.github.io/docs/spot/v1/en/#transfer-fund-between-spot-account-and-future-contract-account
        see https://huobiapi.github.io/docs/usdt_swap/v1/en/#general-transfer-margin-between-spot-account-and-usdt-margined-contracts-account
        see https://huobiapi.github.io/docs/spot/v1/en/#transfer-asset-from-spot-trading-account-to-cross-margin-account-cross
        see https://huobiapi.github.io/docs/spot/v1/en/#transfer-asset-from-spot-trading-account-to-isolated-margin-account-isolated
        see https://huobiapi.github.io/docs/spot/v1/en/#transfer-asset-from-cross-margin-account-to-spot-trading-account-cross
        see 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 huobi api endpoint
        :param str|None params['symbol']: used for isolated margin transfer
        :param str|None params['subType']: 'linear' or 'inverse', only used when transfering to/from swap accounts
        :returns dict: a `transfer structure <https://docs.ccxt.com/en/latest/manual.html#transfer-structure>`
        """
        await self.load_markets()
        currency = self.currency(code)
        request = {
            'currency': currency['id'],
            'amount': float(self.currency_to_precision(code, amount)),
        }
        subType = None
        subType, params = self.handle_sub_type_and_params('transfer', None, params)
        method = None
        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')
        if fromOrToFuturesAccount:
            type = fromAccountId + '-to-' + toAccountId
            type = self.safe_string(params, 'type', type)
            request['type'] = type
            method = 'spotPrivatePostV1FuturesTransfer'
        elif fromSpot and toCross:
            method = 'privatePostCrossMarginTransferIn'
        elif fromCross and toSpot:
            method = 'privatePostCrossMarginTransferOut'
        elif fromSpot and toIsolated:
            request['symbol'] = toAccountId
            method = 'privatePostDwTransferInMargin'
        elif fromIsolated and toSpot:
            request['symbol'] = fromAccountId
            method = 'privatePostDwTransferOutMargin'
        else:
            method = 'v2PrivatePostAccountTransfer'
            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 = await getattr(self, method)(self.extend(request, params))
        #
        #    {
        #        code: '200',
        #        data: '660150061',
        #        message: 'Succeed',
        #        success: True,
        #        'print-log': True
        #    }
        #
        return self.parse_transfer(response, currency)

    async def fetch_borrow_rates_per_symbol(self, params={}):
        """
        fetch borrow rates for currencies within individual markets
        :param dict params: extra parameters specific to the huobi api endpoint
        :returns dict: a dictionary of `borrow rate structures <https://docs.ccxt.com/en/latest/manual.html#borrow-rate-structure>` indexed by market symbol
        """
        await self.load_markets()
        response = await 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"
        #                    }
        #                ]
        #            },
        #            ...
        #        ]
        #    }
        #
        timestamp = self.milliseconds()
        data = self.safe_value(response, 'data', [])
        rates = {
            'info': response,
        }
        for i in range(0, len(data)):
            rate = data[i]
            currencies = self.safe_value(rate, 'currencies', [])
            symbolRates = {}
            for j in range(0, len(currencies)):
                currency = currencies[j]
                currencyId = self.safe_string(currency, 'currency')
                code = self.safe_currency_code(currencyId, 'currency')
                symbolRates[code] = {
                    'currency': code,
                    'rate': self.safe_number(currency, 'actual-rate'),
                    'span': 86400000,
                    'timestamp': timestamp,
                    'datetime': self.iso8601(timestamp),
                }
            marketId = self.safe_string(rate, 'symbol')
            symbol = self.safe_symbol(marketId)
            rates[symbol] = symbolRates
        return rates

    async def fetch_borrow_rates(self, params={}):
        """
        fetch the borrow interest rates of all currencies
        :param dict params: extra parameters specific to the huobi api endpoint
        :returns dict: a list of `borrow rate structures <https://docs.ccxt.com/en/latest/manual.html#borrow-rate-structure>`
        """
        await self.load_markets()
        response = await 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"
        #                 }
        #             ]
        #         },
        #         ...
        #     ]
        # }
        timestamp = self.milliseconds()
        data = self.safe_value(response, 'data', [])
        rates = {}
        for i in range(0, len(data)):
            market = data[i]
            currencies = self.safe_value(market, 'currencies', [])
            for j in range(0, len(currencies)):
                currency = currencies[j]
                currencyId = self.safe_string(currency, 'currency')
                code = self.safe_currency_code(currencyId, 'currency')
                rates[code] = {
                    'currency': code,
                    'rate': self.safe_number(currency, 'actual-rate'),
                    'span': 86400000,
                    'timestamp': timestamp,
                    'datetime': self.iso8601(timestamp),
                    'info': None,
                }
        return rates

    async def fetch_funding_rate_history(self, symbol=None, since=None, limit=None, params={}):
        """
        fetches historical funding rate prices
        :param str|None symbol: unified symbol of the market to fetch the funding rate history for
        :param int|None since: not used by huobi, but filtered internally by ccxt
        :param int|None limit: not used by huobi, but filtered internally by ccxt
        :param dict params: extra parameters specific to the huobi api endpoint
        :returns [dict]: a list of `funding rate structures <https://docs.ccxt.com/en/latest/manual.html?#funding-rate-history-structure>`
        """
        if symbol is None:
            raise ArgumentsRequired(self.id + ' fetchFundingRateHistory() requires a symbol argument')
        await self.load_markets()
        market = self.market(symbol)
        request = {
            'contract_code': market['id'],
        }
        method = None
        if market['inverse']:
            method = 'contractPublicGetSwapApiV1SwapHistoricalFundingRate'
        elif market['linear']:
            method = 'contractPublicGetLinearSwapApiV1SwapHistoricalFundingRate'
        else:
            raise NotSupported(self.id + ' fetchFundingRateHistory() supports inverse and linear swaps only')
        response = await getattr(self, method)(self.extend(request, params))
        #
        # {
        #     "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')
        result = self.safe_value(data, 'data', [])
        rates = []
        for i in range(0, len(result)):
            entry = result[i]
            marketId = self.safe_string(entry, 'contract_code')
            symbol = self.safe_symbol(marketId)
            timestamp = self.safe_integer(entry, 'funding_time')
            rates.append({
                'info': entry,
                'symbol': symbol,
                '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=None):
        #
        # {
        #      "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')
        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,
        }

    async def fetch_funding_rate(self, symbol, params={}):
        """
        fetch the current funding rate
        :param str symbol: unified market symbol
        :param dict params: extra parameters specific to the huobi api endpoint
        :returns dict: a `funding rate structure <https://docs.ccxt.com/en/latest/manual.html#funding-rate-structure>`
        """
        await self.load_markets()
        market = self.market(symbol)
        method = None
        if market['inverse']:
            method = 'contractPublicGetSwapApiV1SwapFundingRate'
        elif market['linear']:
            method = 'contractPublicGetLinearSwapApiV1SwapFundingRate'
        else:
            raise NotSupported(self.id + ' fetchFundingRate() supports inverse and linear swaps only')
        request = {
            'contract_code': market['id'],
        }
        response = await getattr(self, method)(self.extend(request, params))
        #
        # {
        #     "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)

    async def fetch_funding_rates(self, symbols=None, params={}):
        """
        fetch the funding rate for multiple markets
        :param [str]|None symbols: list of unified market symbols
        :param dict params: extra parameters specific to the huobi api endpoint
        :returns dict: a dictionary of `funding rates structures <https://docs.ccxt.com/en/latest/manual.html#funding-rates-structure>`, indexe by market symbols
        """
        await self.load_markets()
        symbols = self.market_symbols(symbols)
        options = self.safe_value(self.options, 'fetchFundingRates', {})
        defaultSubType = self.safe_string(self.options, 'defaultSubType', 'inverse')
        subType = self.safe_string(options, 'subType', defaultSubType)
        subType = self.safe_string(params, 'subType', subType)
        request = {
            # 'contract_code': market['id'],
        }
        method = self.get_supported_mapping(subType, {
            'linear': 'contractPublicGetLinearSwapApiV1SwapBatchFundingRate',
            'inverse': 'contractPublicGetSwapApiV1SwapBatchFundingRate',
        })
        params = self.omit(params, 'subType')
        response = await getattr(self, method)(self.extend(request, params))
        #
        #     {
        #         "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', [])
        result = self.parse_funding_rates(data)
        return self.filter_by_array(result, 'symbol', symbols)

    async def fetch_borrow_interest(self, code=None, symbol=None, since=None, limit=None, params={}):
        """
        fetch the interest owed by the user for borrowing currency for margin trading
        :param str|None code: unified currency code
        :param str|None symbol: unified market symbol when fetch interest in isolated markets
        :param int|None since: the earliest time in ms to fetch borrrow interest for
        :param int|None limit: the maximum number of structures to retrieve
        :param dict params: extra parameters specific to the huobi api endpoint
        :returns [dict]: a list of `borrow interest structures <https://docs.ccxt.com/en/latest/manual.html#borrow-interest-structure>`
        """
        await self.load_markets()
        marginMode = None
        marginMode, params = self.handle_margin_mode_and_params('fetchBorrowInterest', params)
        marginMode = 'cross' if (marginMode is None) else marginMode
        request = {}
        if since is not None:
            request['start-date'] = self.yyyymmdd(since)
        if limit is not None:
            request['size'] = limit
        market = None
        method = None
        if marginMode == 'isolated':
            method = 'privateGetMarginLoanOrders'
            if symbol is not None:
                market = self.market(symbol)
                request['symbol'] = market['id']
        else:  # Cross
            method = 'privateGetCrossMarginLoanOrders'
            if code is not None:
                currency = self.currency(code)
                request['currency'] = currency['id']
        response = await getattr(self, method)(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, market=None):
        # 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_number(info, 'accrued-at')
        return {
            'account': symbol if (marginMode == 'isolated') else 'cross',  # deprecated
            'symbol': symbol,
            'marginMode': marginMode,
            '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'),
            'timestamp': timestamp,  # Interest accrued time
            'datetime': self.iso8601(timestamp),
            'info': info,
        }

    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.milliseconds(), 'T')
                request = {
                    'SignatureMethod': 'HmacSHA256',
                    'SignatureVersion': '2',
                    'AccessKeyId': self.apiKey,
                    'Timestamp': timestamp,
                }
                if method != 'POST':
                    request = self.extend(request, query)
                request = self.keysort(request)
                auth = self.urlencode(request)
                # 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(hostname, 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()
                timestamp = self.ymdhms(self.milliseconds(), 'T')
                request = {
                    'SignatureMethod': 'HmacSHA256',
                    'SignatureVersion': '2',
                    'AccessKeyId': self.apiKey,
                    'Timestamp': timestamp,
                }
                if method != 'POST':
                    request = self.extend(request, query)
                request = self.keysort(request)
                auth = self.urlencode(request)
                # 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, reason, url, method, headers, body, response, requestHeaders, requestBody):
        if response is None:
            return  # 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 = 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)

    async def fetch_funding_history(self, symbol=None, since=None, limit=None, params={}):
        """
        fetch the history of funding payments paid and received on self account
        see https://huobiapi.github.io/docs/usdt_swap/v1/en/#general-query-account-financial-records-via-multiple-fields-new   # linear swaps
        see https://huobiapi.github.io/docs/dm/v1/en/#query-financial-records-via-multiple-fields-new                          # coin-m futures
        see https://huobiapi.github.io/docs/coin_margined_swap/v1/en/#query-financial-records-via-multiple-fields-new          # coin-m swaps
        :param str|None symbol: unified market symbol
        :param int|None since: the earliest time in ms to fetch funding history for
        :param int|None limit: the maximum number of funding history structures to retrieve
        :param dict params: extra parameters specific to the huobi api endpoint
        :returns dict: a `funding history structure <https://docs.ccxt.com/en/latest/manual.html#funding-history-structure>`
        """
        await self.load_markets()
        market = self.market(symbol)
        marketType, query = self.handle_market_type_and_params('fetchFundingHistory', market, params)
        method = None
        request = {
            'type': '30,31',
        }
        if since is not None:
            request['start_date'] = since
        if marketType == 'swap':
            request['contract'] = market['id']
            if market['linear']:
                method = 'contractPrivatePostLinearSwapApiV3SwapFinancialRecordExact'
                #
                #    {
                #        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']
            else:
                method = 'contractPrivatePostSwapApiV3SwapFinancialRecordExact'
                #
                #     {
                #         "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
                #     }
                #
        else:
            method = 'contractPrivatePostApiV3ContractFinancialRecordExact'
            request['symbol'] = market['id']
        response = await getattr(self, method)(self.extend(request, query))
        data = self.safe_value(response, 'data', [])
        return self.parse_incomes(data, market, since, limit)

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

    def parse_income(self, income, 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, 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 {
            'info': position,
            'id': None,
            'symbol': symbol,
            'contracts': self.parse_number(contracts),
            'contractSize': contractSize,
            'entryPrice': entryPrice,
            'collateral': self.parse_number(collateral),
            'side': side,
            'unrealizedProfit': unrealizedProfit,
            'leverage': self.parse_number(leverage),
            'percentage': self.parse_number(percentage),
            'marginMode': marginMode,
            'notional': self.parse_number(notional),
            'markPrice': 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,
        }

    async def fetch_positions(self, symbols=None, params={}):
        """
        fetch all open positions
        :param [str]|None symbols: list of unified market symbols
        :param dict params: extra parameters specific to the huobi api endpoint
        :returns [dict]: a list of `position structure <https://docs.ccxt.com/en/latest/manual.html#position-structure>`
        """
        await self.load_markets()
        symbols = self.market_symbols(symbols)
        market = None
        if symbols is not None:
            first = self.safe_string(symbols, 0)
            market = self.market(first)
        marginMode = None
        marginMode, params = self.handle_margin_mode_and_params('fetchPositions', params)
        marginMode = 'cross' if (marginMode is None) else marginMode
        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'
        method = None
        if subType == 'linear':
            method = self.get_supported_mapping(marginMode, {
                'isolated': 'contractPrivatePostLinearSwapApiV1SwapPositionInfo',
                'cross': 'contractPrivatePostLinearSwapApiV1SwapCrossPositionInfo',
            })
            #
            #     {
            #       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:
            method = self.get_supported_mapping(marketType, {
                'future': 'contractPrivatePostApiV1ContractPositionInfo',
                'swap': 'contractPrivatePostSwapApiV1SwapPositionInfo',
            })
            #
            # 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'
            #     }
            #
        response = await getattr(self, method)(params)
        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(result, 'symbol', symbols, False)

    async def fetch_position(self, symbol, params={}):
        """
        fetch data on a single open contract trade position
        :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 huobi api endpoint
        :returns dict: a `position structure <https://docs.ccxt.com/en/latest/manual.html#position-structure>`
        """
        await 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)
        method = None
        if market['linear']:
            method = self.get_supported_mapping(marginMode, {
                'isolated': 'contractPrivatePostLinearSwapApiV1SwapAccountPositionInfo',
                'cross': 'contractPrivatePostLinearSwapApiV1SwapCrossAccountPositionInfo',
            })
            #
            # 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:
            method = self.get_supported_mapping(marketType, {
                'future': 'contractPrivatePostApiV1ContractAccountPositionInfo',
                'swap': 'contractPrivatePostSwapApiV1SwapAccountPositionInfo',
            })
            #
            # 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"
            #     }
            #
        request = {}
        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 = await getattr(self, method)(self.extend(request, query))
        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))
        return self.extend(parsed, {
            'timestamp': timestamp,
            'datetime': self.iso8601(timestamp),
        })

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

    async def fetch_ledger(self, code=None, since=None, limit=None, params={}):
        """
        fetch the history of changes, actions done by the user or operations that altered balance of the user
        :param str|None code: unified currency code, default is None
        :param int|None since: timestamp in ms of the earliest ledger entry, default is None
        :param int|None limit: max number of ledger entrys to return, default is None
        :param dict params: extra parameters specific to the huobi api endpoint
        :returns dict: a `ledger structure <https://docs.ccxt.com/en/latest/manual.html#ledger-structure>`
        """
        await self.load_markets()
        accountId = await self.fetch_account_id_by_type('spot', params)
        request = {
            '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 ID in self 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
        response = await 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)

    async def fetch_leverage_tiers(self, symbols=None, params={}):
        """
        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 huobi api endpoint
        :returns dict: a dictionary of `leverage tiers structures <https://docs.ccxt.com/en/latest/manual.html#leverage-tiers-structure>`, indexed by market symbols
        """
        await self.load_markets()
        response = await 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_value(response, 'data')
        return self.parse_leverage_tiers(data, symbols, 'contract_code')

    async def fetch_market_leverage_tiers(self, symbol, params={}):
        """
        retrieve information on the maximum leverage, and maintenance margin for trades of varying trade sizes for a single market
        :param str symbol: unified market symbol
        :param dict params: extra parameters specific to the huobi api endpoint
        :returns dict: a `leverage tiers structure <https://docs.ccxt.com/en/latest/manual.html#leverage-tiers-structure>`
        """
        await self.load_markets()
        request = {}
        if symbol is not None:
            market = self.market(symbol)
            if not market['contract']:
                raise BadRequest(self.id + ' fetchMarketLeverageTiers() symbol supports contract markets only')
            request['contract_code'] = market['id']
        response = await self.contractPublicGetLinearSwapApiV1SwapAdjustfactor(self.extend(request, 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_value(response, 'data')
        tiers = self.parse_leverage_tiers(data, [symbol], 'contract_code')
        return self.safe_value(tiers, symbol)

    def parse_leverage_tiers(self, response, symbols=None, marketIdKey=None):
        result = {}
        for i in range(0, len(response)):
            item = response[i]
            list = self.safe_value(item, 'list', [])
            tiers = []
            currency = self.safe_string(item, 'trade_partition')
            id = self.safe_string(item, marketIdKey)
            symbol = self.safe_symbol(id)
            if self.in_array(symbol, symbols):
                for j in range(0, len(list)):
                    obj = list[j]
                    leverage = self.safe_string(obj, 'lever_rate')
                    ladders = self.safe_value(obj, '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'),
                            'currency': self.safe_currency_code(currency),
                            '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,
                        })
                result[symbol] = tiers
        return result

    async def fetch_open_interest_history(self, symbol, timeframe='1h', since=None, limit=None, params={}):
        """
        Retrieves the open interest history of a currency
        see https://huobiapi.github.io/docs/dm/v1/en/#query-information-on-open-interest
        see https://huobiapi.github.io/docs/coin_margined_swap/v1/en/#query-information-on-open-interest
        see 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|None since: Not used by huobi api, but response parsed by CCXT
        :param int|None 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|None params['pair']: eg BTC-USDT *Only for USDT-M*
        :returns dict: an array of `open interest structures <https://docs.ccxt.com/en/latest/manual.html#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')
        await self.load_markets()
        timeframes = {
            '1h': '60min',
            '4h': '4hour',
            '12h': '12hour',
            '1d': '1day',
        }
        market = self.market(symbol)
        amountType = self.safe_number_2(params, 'amount_type', 'amountType')
        if amountType is None:
            raise ArgumentsRequired(self.id + ' fetchOpenInterestHistory requires parameter params.amountType to be either 1(cont), or 2(cryptocurrency)')
        request = {
            'period': timeframes[timeframe],
            'amount_type': amountType,
        }
        method = None
        if market['future']:
            request['contract_type'] = self.safe_string(market['info'], 'contract_type')
            request['symbol'] = market['baseId']  # currency code on coin-m futures
            method = 'contractPublicGetApiV1ContractHisOpenInterest'  # coin-m futures
        elif market['linear']:
            request['contract_type'] = 'swap'
            request['contract_code'] = market['id']
            request['contract_code'] = market['id']
            method = 'contractPublicGetLinearSwapApiV1SwapHisOpenInterest'  # USDT-M
        else:
            request['contract_code'] = market['id']
            method = 'contractPublicGetSwapApiV1SwapHisOpenInterest'  # coin-m swaps
        if limit is not None:
            request['size'] = limit
        response = await getattr(self, method)(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_value(data, 'tick')
        return self.parse_open_interests(tick, market, since, limit)

    async def fetch_open_interest(self, symbol, params={}):
        """
        Retrieves the open interest of a currency
        see https://huobiapi.github.io/docs/dm/v1/en/#get-contract-open-interest-information
        see https://huobiapi.github.io/docs/coin_margined_swap/v1/en/#get-swap-open-interest-information
        see 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/en/latest/manual.html#interest-history-structure:
        """
        await 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 = {
            'contract_code': market['id'],
        }
        method = None
        if market['future']:
            request['contract_type'] = self.safe_string(market['info'], 'contract_type')
            request['symbol'] = market['baseId']
            method = 'contractPublicGetApiV1ContractOpenInterest'  # COIN-M futures
        elif market['linear']:
            request['contract_type'] = 'swap'
            method = 'contractPublicGetLinearSwapApiV1SwapOpenInterest'  # USDT-M
        else:
            method = 'contractPublicGetSwapApiV1SwapOpenInterest'  # COIN-M swaps
        response = await getattr(self, method)(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')
        return self.extend(openInterest, {
            'timestamp': timestamp,
            'datetime': self.iso8601(timestamp),
        })

    def parse_open_interest(self, interest, 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')
        return {
            'symbol': self.safe_string(market, 'symbol'),
            'baseVolume': amount,  # deprecated
            'quoteVolume': value,  # deprecated
            'openInterestAmount': amount,
            'openInterestValue': value,
            'timestamp': timestamp,
            'datetime': self.iso8601(timestamp),
            'info': interest,
        }

    async def borrow_margin(self, code, amount, symbol=None, params={}):
        """
        create a loan to borrow margin
        see https://huobiapi.github.io/docs/spot/v1/en/#request-a-margin-loan-isolated
        see 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 str|None symbol: unified market symbol, required for isolated margin
        :param dict params: extra parameters specific to the huobi api endpoint
        :returns dict: a `margin loan structure <https://docs.ccxt.com/en/latest/manual.html#margin-loan-structure>`
        """
        await self.load_markets()
        currency = self.currency(code)
        request = {
            'currency': currency['id'],
            'amount': self.currency_to_precision(code, amount),
        }
        marginMode = None
        marginMode, params = self.handle_margin_mode_and_params('borrowMargin', params)
        marginMode = 'cross' if (marginMode is None) else marginMode
        method = None
        if marginMode == 'isolated':
            if symbol is None:
                raise ArgumentsRequired(self.id + ' borrowMargin() requires a symbol argument for isolated margin')
            market = self.market(symbol)
            request['symbol'] = market['id']
            method = 'privatePostMarginOrders'
        elif marginMode == 'cross':
            method = 'privatePostCrossMarginOrders'
        response = await getattr(self, method)(self.extend(request, params))
        #
        # Cross
        #
        #     {
        #         "status": "ok",
        #         "data": null
        #     }
        #
        # Isolated
        #
        #     {
        #         "data": 1000
        #     }
        #
        transaction = self.parse_margin_loan(response, currency)
        return self.extend(transaction, {
            'amount': amount,
            'symbol': symbol,
        })

    async def repay_margin(self, code, amount, symbol=None, params={}):
        """
        repay borrowed margin and interest
        see 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 str|None symbol: unified market symbol
        :param dict params: extra parameters specific to the huobi api endpoint
        :returns dict: a `margin loan structure <https://docs.ccxt.com/en/latest/manual.html#margin-loan-structure>`
        """
        await self.load_markets()
        currency = self.currency(code)
        marginMode = None
        marginMode, params = self.handle_margin_mode_and_params('repayMargin', params)
        marginMode = 'cross' if (marginMode is None) else marginMode
        marginAccounts = self.safe_value(self.options, 'marginAccounts', {})
        accountType = self.get_supported_mapping(marginMode, marginAccounts)
        accountId = await self.fetch_account_id_by_type(accountType, params)
        request = {
            'currency': currency['id'],
            'amount': self.currency_to_precision(code, amount),
            'accountId': accountId,
        }
        response = await 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 parse_margin_loan(self, info, 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_integer_2(info, 'repayId', 'data'),
            'currency': self.safe_currency_code(None, currency),
            'amount': None,
            'symbol': None,
            'timestamp': timestamp,
            'datetime': self.iso8601(timestamp),
            'info': info,
        }

    async def fetch_settlement_history(self, symbol=None, since=None, limit=None, params={}):
        """
        Fetches historical settlement records
        :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: A list of settlement history objects
        """
        code = self.safe_string(params, 'code')
        until = self.safe_integer_2(params, 'until', 'till')
        params = self.omit(params, ['until', 'till'])
        market = None if (symbol is None) else self.market(symbol)
        type, query = self.handle_market_type_and_params('fetchSettlementHistory', market, params)
        if type == 'future':
            if symbol is None and code is None:
                raise ArgumentsRequired(self.id + ' requires a symbol argument or params["code"] for fetchSettlementHistory future')
        elif symbol is None:
            raise ArgumentsRequired(self.id + ' requires a symbol argument for fetchSettlementHistory swap')
        request = {}
        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
        method = 'contractPublicGetApiV1ContractSettlementRecords'
        if market['swap']:
            if market['linear']:
                method = 'contractPublicGetLinearSwapApiV1SwapSettlementRecords'
            else:
                method = 'contractPublicGetSwapApiV1SwapSettlementRecords'
        response = await getattr(self, method)(self.extend(request, query))
        #
        # 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')

    async def fetch_deposit_withdraw_fees(self, codes=None, params={}):
        """
        fetch deposit and withdraw fees
        see 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 huobi api endpoint
        :returns [dict]: a list of `fees structures <https://docs.ccxt.com/en/latest/manual.html#fee-structure>`
        """
        await self.load_markets()
        response = await 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_value(response, 'data')
        return self.parse_deposit_withdraw_fees(data, codes, 'currency')

    def parse_deposit_withdraw_fee(self, fee, 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 = {
                    '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),
        }
