<?php

namespace ccxt;

// 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

use Exception; // a common import
use ccxt\abstract\htx as Exchange;

class htx extends Exchange {

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

    public function fetch_status($params = array ()) {
        /**
         * the latest known information on the availability of the exchange API
         *
         * @see https://huobiapi.github.io/docs/spot/v1/en/#get-system-$status
         * @see https://huobiapi.github.io/docs/dm/v1/en/#get-system-$status
         * @see https://huobiapi.github.io/docs/coin_margined_swap/v1/en/#get-system-$status
         * @see https://huobiapi.github.io/docs/usdt_swap/v1/en/#get-system-$status
         * @see https://huobiapi.github.io/docs/usdt_swap/v1/en/#query-whether-the-system-is-available  // contractPublicGetHeartbeat
         *
         * @param {array} [$params] extra parameters specific to the exchange API endpoint
         * @return {array} a ~@link https://docs.ccxt.com/#/?id=exchange-$status-structure $status structure~
         */
        $this->load_markets();
        $marketType = null;
        list($marketType, $params) = $this->handle_market_type_and_params('fetchStatus', null, $params);
        $enabledForContracts = $this->handle_option('fetchStatus', 'enableForContracts', false); // temp fix for => https://status-linear-swap.huobigroup.com/api/v2/summary.json
        $response = null;
        if ($marketType !== 'spot' && $enabledForContracts) {
            $subType = $this->safe_string($params, 'subType', $this->options['defaultSubType']);
            if ($marketType === 'swap') {
                if ($subType === 'linear') {
                    $response = $this->statusPublicSwapLinearGetApiV2SummaryJson ();
                } elseif ($subType === 'inverse') {
                    $response = $this->statusPublicSwapInverseGetApiV2SummaryJson ();
                }
            } elseif ($marketType === 'future') {
                if ($subType === 'linear') {
                    $response = $this->statusPublicFutureLinearGetApiV2SummaryJson ();
                } elseif ($subType === 'inverse') {
                    $response = $this->statusPublicFutureInverseGetApiV2SummaryJson ();
                }
            } elseif ($marketType === 'contract') {
                $response = $this->contractPublicGetHeartbeat ();
            }
        } elseif ($marketType === 'spot') {
            $response = $this->statusPublicSpotGetApiV2SummaryJson ();
        }
        //
        // statusPublicSpotGetApiV2SummaryJson, statusPublicSwapInverseGetApiV2SummaryJson, statusPublicFutureLinearGetApiV2SummaryJson, statusPublicFutureInverseGetApiV2SummaryJson
        //
        //      {
        //          "page" => array(
        //              "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" => array(
        //                  array(
        //                      "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" => array(
        //                          "82k5jxg7ltxd" // list of related components
        //                      )
        //                  ),
        //              ),
        //              "incidents" => array( // 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" => array(
        //                          {
        //                              "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" => array(
        //                                  {
        //                                      "code" => "nctwm9tghxh6",
        //                                      "name" => "Market data",
        //                                      "old_status" => "operational",
        //                                      "new_status" => "degraded_performance"
        //                                  }
        //                              ),
        //                              "deliver_notifications" => true,
        //                              "custom_tweet" => null,
        //                              "tweet_id" => null
        //                          }
        //                      ),
        //                      "components" => array(
        //                          array(
        //                              "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":array( // 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" => array(
        //                          {
        //                              "id" => "8whgr3rlbld8",
        //                              "status" => "scheduled",
        //                              "body" => "We will be undergoing scheduled maintenance during this 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" => array(
        //                                  {
        //                                      "code" => "h028tnzw1n5l",
        //                                      "name" => "Deposit And Withdraw - Deposit",
        //                                      "old_status" => "operational",
        //                                      "new_status" => "operational"
        //                                  }
        //                              ),
        //                              "deliver_notifications" => true,
        //                              "custom_tweet" => null,
        //                              "tweet_id" => null
        //                          }
        //                      ),
        //                      "components" => array(
        //                          {
        //                              "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" => array(
        //              "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 = null;
        $updated = null;
        $url = null;
        if ($marketType === 'contract') {
            $statusRaw = $this->safe_string($response, 'status');
            if ($statusRaw === null) {
                $status = null;
            } else {
                $status = ($statusRaw === 'ok') ? 'ok' : 'maintenance'; // 'ok', 'error'
            }
            $updated = $this->safe_string($response, 'ts');
        } else {
            $statusData = $this->safe_value($response, 'status', array());
            $statusRaw = $this->safe_string($statusData, 'indicator');
            $status = ($statusRaw === 'none') ? 'ok' : 'maintenance'; // none, minor, major, critical, maintenance
            $pageData = $this->safe_value($response, 'page', array());
            $datetime = $this->safe_string($pageData, 'updated_at');
            $updated = $this->parse8601($datetime);
            $url = $this->safe_string($pageData, 'url');
        }
        return array(
            'status' => $status,
            'updated' => $updated,
            'eta' => null,
            'url' => $url,
            'info' => $response,
        );
    }

    public function fetch_time($params = array ()): ?int {
        /**
         * fetches the current integer timestamp in milliseconds from the exchange server
         *
         * @see https://huobiapi.github.io/docs/spot/v1/en/#get-current-timestamp
         * @see https://huobiapi.github.io/docs/coin_margined_swap/v1/en/#get-current-system-timestamp
         *
         * @param {array} [$params] extra parameters specific to the exchange API endpoint
         * @return {int} the current integer timestamp in milliseconds from the exchange server
         */
        $options = $this->safe_value($this->options, 'fetchTime', array());
        $defaultType = $this->safe_string($this->options, 'defaultType', 'spot');
        $type = $this->safe_string($options, 'type', $defaultType);
        $type = $this->safe_string($params, 'type', $type);
        $response = null;
        if (($type === 'future') || ($type === 'swap')) {
            $response = $this->contractPublicGetApiV1Timestamp ($params);
        } else {
            $response = $this->spotPublicGetV1CommonTimestamp ($params);
        }
        //
        // spot
        //
        //     array("status":"ok","data":1637504261099)
        //
        // future, swap
        //
        //     array("status":"ok","ts":1637504164707)
        //
        return $this->safe_integer_2($response, 'data', 'ts');
    }

    public function parse_trading_fee(array $fee, ?array $market = null): array {
        //
        //     {
        //         "symbol":"btcusdt",
        //         "actualMakerRate":"0.002",
        //         "actualTakerRate":"0.002",
        //         "takerFeeRate":"0.002",
        //         "makerFeeRate":"0.002"
        //     }
        //
        $marketId = $this->safe_string($fee, 'symbol');
        return array(
            'info' => $fee,
            'symbol' => $this->safe_symbol($marketId, $market),
            'maker' => $this->safe_number($fee, 'actualMakerRate'),
            'taker' => $this->safe_number($fee, 'actualTakerRate'),
            'percentage' => null,
            'tierBased' => null,
        );
    }

    public function fetch_trading_fee(string $symbol, $params = array ()): array {
        /**
         * fetch the trading fees for a $market
         *
         * @see https://huobiapi.github.io/docs/spot/v1/en/#get-current-fee-rate-applied-to-the-user
         *
         * @param {string} $symbol unified $market $symbol
         * @param {array} [$params] extra parameters specific to the exchange API endpoint
         * @return {array} a ~@link https://docs.ccxt.com/#/?id=fee-structure fee structure~
         */
        $this->load_markets();
        $market = $this->market($symbol);
        $request = array(
            'symbols' => $market['id'], // trading symbols comma-separated
        );
        $response = $this->spotPrivateGetV2ReferenceTransactFeeRate ($this->extend($request, $params));
        //
        //     {
        //         "code":200,
        //         "data":array(
        //             {
        //                 "symbol":"btcusdt",
        //                 "actualMakerRate":"0.002",
        //                 "actualTakerRate":"0.002",
        //                 "takerFeeRate":"0.002",
        //                 "makerFeeRate":"0.002"
        //             }
        //         ),
        //         "success":true
        //     }
        //
        $data = $this->safe_value($response, 'data', array());
        $first = $this->safe_value($data, 0, array());
        return $this->parse_trading_fee($first, $market);
    }

    public function fetch_trading_limits(?array $symbols = null, $params = array ()) {
        // this 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 = array( 'ETH/BTC', 'LTC/BTC' ) in args it will only load those
        $this->load_markets();
        if ($symbols === null) {
            $symbols = $this->symbols;
        }
        $result = array();
        for ($i = 0; $i < count($symbols); $i++) {
            $symbol = $symbols[$i];
            $result[$symbol] = $this->fetch_trading_limits_by_id($this->market_id($symbol), $params);
        }
        return $result;
    }

    public function fetch_trading_limits_by_id(string $id, $params = array ()) {
        /**
         * @ignore
         *
         * @see https://huobiapi.github.io/docs/spot/v1/en/#get-current-fee-rate-applied-to-the-user
         *
         * @param {string} $id market $id
         * @param {array} [$params] extra parameters specific to the exchange API endpoint
         * @return {array} the limits object of a market structure
         */
        $request = array(
            'symbol' => $id,
        );
        $response = $this->spotPublicGetV1CommonExchange ($this->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 $this->parse_trading_limits($this->safe_value($response, 'data', array()));
    }

    public function parse_trading_limits($limits, ?string $symbol = null, $params = array ()) {
        //
        //   {                                "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 array(
            'info' => $limits,
            'limits' => array(
                'amount' => array(
                    'min' => $this->safe_number($limits, 'limit-order-must-greater-than'),
                    'max' => $this->safe_number($limits, 'limit-order-must-less-than'),
                ),
            ),
        );
    }

    public function cost_to_precision($symbol, $cost) {
        return $this->decimal_to_precision($cost, TRUNCATE, $this->markets[$symbol]['precision']['cost'], $this->precisionMode);
    }

    public function fetch_markets($params = array ()): array {
        /**
         * retrieves data on all markets for huobi
         *
         * @see https://huobiapi.github.io/docs/spot/v1/en/#get-all-supported-trading-symbol-v1-deprecated
         * @see https://huobiapi.github.io/docs/dm/v1/en/#get-contract-info
         * @see https://huobiapi.github.io/docs/coin_margined_swap/v1/en/#query-swap-info
         * @see https://huobiapi.github.io/docs/usdt_swap/v1/en/#general-query-swap-info
         *
         * @param {array} [$params] extra parameters specific to the exchange API endpoint
         * @return {array[]} an array of objects representing market data
         */
        if ($this->options['adjustForTimeDifference']) {
            $this->load_time_difference();
        }
        $types = null;
        list($types, $params) = $this->handle_option_and_params($params, 'fetchMarkets', 'types', array());
        $allMarkets = array();
        $promises = array();
        $keys = is_array($types) ? array_keys($types) : array();
        for ($i = 0; $i < count($keys); $i++) {
            $key = $keys[$i];
            if ($this->safe_bool($types, $key)) {
                if ($key === 'spot') {
                    $promises[] = $this->fetch_markets_by_type_and_sub_type('spot', null, $params);
                } elseif ($key === 'linear') {
                    $promises[] = $this->fetch_markets_by_type_and_sub_type(null, 'linear', $params);
                } elseif ($key === 'inverse') {
                    $promises[] = $this->fetch_markets_by_type_and_sub_type('swap', 'inverse', $params);
                    $promises[] = $this->fetch_markets_by_type_and_sub_type('future', 'inverse', $params);
                }
            }
        }
        $promises = $promises;
        for ($i = 0; $i < count($promises); $i++) {
            $allMarkets = $this->array_concat($allMarkets, $promises[$i]);
        }
        return $allMarkets;
    }

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

    public function try_get_symbol_from_future_markets(string $symbolOrMarketId) {
        if (is_array($this->markets) && array_key_exists($symbolOrMarketId, $this->markets)) {
            return $symbolOrMarketId;
        }
        // only on "future" $market type (inverse & linear), $market-id differs between "fetchMarkets" and "fetchTicker"
        // so we have to create a mapping
        // - $market-id from fetchMarkts =>    `BTC-USDT-240419` (linear future) or `BTC240412` (inverse future)
        // - $market-id from fetchTciker[s] => `BTC-USDT-CW`     (linear future) or `BTC_CW`    (inverse future)
        if (!(is_array($this->options) && array_key_exists('futureMarketIdsForSymbols', $this->options))) {
            $this->options['futureMarketIdsForSymbols'] = array();
        }
        $futureMarketIdsForSymbols = $this->safe_dict($this->options, 'futureMarketIdsForSymbols', array());
        if (is_array($futureMarketIdsForSymbols) && array_key_exists($symbolOrMarketId, $futureMarketIdsForSymbols)) {
            return $futureMarketIdsForSymbols[$symbolOrMarketId];
        }
        $futureMarkets = $this->filter_by($this->markets, 'future', true);
        $futuresCharsMaps = array(
            'this_week' => 'CW',
            'next_week' => 'NW',
            'quarter' => 'CQ',
            'next_quarter' => 'NQ',
        );
        for ($i = 0; $i < count($futureMarkets); $i++) {
            $market = $futureMarkets[$i];
            $info = $this->safe_value($market, 'info', array());
            $contractType = $this->safe_string($info, 'contract_type');
            $contractSuffix = $futuresCharsMaps[$contractType];
            // see comment on formats a bit above
            $constructedId = $market['linear'] ? $market['base'] . '-' . $market['quote'] . '-' . $contractSuffix : $market['base'] . '_' . $contractSuffix;
            if ($constructedId === $symbolOrMarketId) {
                $symbol = $market['symbol'];
                $this->options['futureMarketIdsForSymbols'][$symbolOrMarketId] = $symbol;
                return $symbol;
            }
        }
        // if not found, just save it to avoid unnecessary future iterations
        $this->options['futureMarketIdsForSymbols'][$symbolOrMarketId] = $symbolOrMarketId;
        return $symbolOrMarketId;
    }

    public function parse_ticker(array $ticker, ?array $market = null): array {
        //
        // fetchTicker
        //
        //     {
        //         "amount" => 26228.672978342216,
        //         "open" => 9078.95,
        //         "close" => 9146.86,
        //         "high" => 9155.41,
        //         "id" => 209988544334,
        //         "count" => 265846,
        //         "low" => 8988.0,
        //         "version" => 209988544334,
        //         "ask" => array( 9146.87, 0.156134 ),
        //         "vol" => 2.3822168242201668E8,
        //         "bid" => array( 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 = $this->safe_string_2($ticker, 'symbol', 'contract_code');
        $symbol = $this->safe_symbol($marketId, $market);
        $symbol = $this->try_get_symbol_from_future_markets($symbol);
        $timestamp = $this->safe_integer_2($ticker, 'ts', 'quoteTime');
        $bid = null;
        $bidVolume = null;
        $ask = null;
        $askVolume = null;
        if (is_array($ticker) && array_key_exists('bid', $ticker)) {
            if ($ticker['bid'] !== null && gettype($ticker['bid']) === 'array' && array_keys($ticker['bid']) === array_keys(array_keys($ticker['bid']))) {
                $bid = $this->safe_string($ticker['bid'], 0);
                $bidVolume = $this->safe_string($ticker['bid'], 1);
            } else {
                $bid = $this->safe_string($ticker, 'bid');
                $bidVolume = $this->safe_string($ticker, 'bidSize');
            }
        }
        if (is_array($ticker) && array_key_exists('ask', $ticker)) {
            if ($ticker['ask'] !== null && gettype($ticker['ask']) === 'array' && array_keys($ticker['ask']) === array_keys(array_keys($ticker['ask']))) {
                $ask = $this->safe_string($ticker['ask'], 0);
                $askVolume = $this->safe_string($ticker['ask'], 1);
            } else {
                $ask = $this->safe_string($ticker, 'ask');
                $askVolume = $this->safe_string($ticker, 'askSize');
            }
        }
        $open = $this->safe_string($ticker, 'open');
        $close = $this->safe_string($ticker, 'close');
        $baseVolume = $this->safe_string($ticker, 'amount');
        $quoteVolume = $this->safe_string($ticker, 'vol');
        return $this->safe_ticker(array(
            'symbol' => $symbol,
            'timestamp' => $timestamp,
            'datetime' => $this->iso8601($timestamp),
            'high' => $this->safe_string($ticker, 'high'),
            'low' => $this->safe_string($ticker, 'low'),
            'bid' => $bid,
            'bidVolume' => $bidVolume,
            'ask' => $ask,
            'askVolume' => $askVolume,
            'vwap' => null,
            'open' => $open,
            'close' => $close,
            'last' => $close,
            'previousClose' => null,
            'change' => null,
            'percentage' => null,
            'average' => null,
            'baseVolume' => $baseVolume,
            'quoteVolume' => $quoteVolume,
            'info' => $ticker,
        ), $market);
    }

    public function fetch_ticker(string $symbol, $params = array ()): array {
        /**
         * fetches a price $ticker, a statistical calculation with the information calculated over the past 24 hours for a specific $market
         *
         * @see https://huobiapi.github.io/docs/spot/v1/en/#get-latest-aggregated-$ticker
         * @see https://huobiapi.github.io/docs/dm/v1/en/#get-$market-data-overview
         * @see https://huobiapi.github.io/docs/coin_margined_swap/v1/en/#get-$market-data-overview
         * @see https://huobiapi.github.io/docs/usdt_swap/v1/en/#general-get-$market-data-overview
         *
         * @param {string} $symbol unified $symbol of the $market to fetch the $ticker for
         * @param {array} [$params] extra parameters specific to the exchange API endpoint
         * @return {array} a ~@link https://docs.ccxt.com/#/?id=$ticker-structure $ticker structure~
         */
        $this->load_markets();
        $market = $this->market($symbol);
        $request = array();
        $response = null;
        if ($market['linear']) {
            $request['contract_code'] = $market['id'];
            $response = $this->contractPublicGetLinearSwapExMarketDetailMerged ($this->extend($request, $params));
        } elseif ($market['inverse']) {
            if ($market['future']) {
                $request['symbol'] = $market['id'];
                $response = $this->contractPublicGetMarketDetailMerged ($this->extend($request, $params));
            } elseif ($market['swap']) {
                $request['contract_code'] = $market['id'];
                $response = $this->contractPublicGetSwapExMarketDetailMerged ($this->extend($request, $params));
            }
        } else {
            $request['symbol'] = $market['id'];
            $response = $this->spotPublicGetMarketDetailMerged ($this->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" => array( 9146.87, 0.156134 ),
        //             "vol" => 2.3822168242201668E8,
        //             "bid" => array( 9146.86, 0.080758 ),
        //         }
        //     }
        //
        // future, swap
        //
        //     {
        //         "ch":"market.BTC211126.detail.merged",
        //         "status":"ok",
        //         "tick":array(
        //             "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 = $this->safe_value($response, 'tick', array());
        $ticker = $this->parse_ticker($tick, $market);
        $timestamp = $this->safe_integer($response, 'ts');
        $ticker['timestamp'] = $timestamp;
        $ticker['datetime'] = $this->iso8601($timestamp);
        return $ticker;
    }

    public function fetch_tickers(?array $symbols = null, $params = array ()): array {
        /**
         * fetches price $tickers for multiple markets, statistical information calculated over the past 24 hours for 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 {string[]} [$symbols] unified $symbols of the markets to fetch the ticker for, all $market $tickers are returned if not assigned
         * @param {array} [$params] extra parameters specific to the exchange API endpoint
         * @return {array} a dictionary of ~@link https://docs.ccxt.com/#/?id=ticker-structure ticker structures~
         */
        $this->load_markets();
        $symbols = $this->market_symbols($symbols);
        $first = $this->safe_string($symbols, 0);
        $market = null;
        if ($first !== null) {
            $market = $this->market($first);
        }
        $isSubTypeRequested = (is_array($params) && array_key_exists('subType', $params)) || (is_array($params) && array_key_exists('business_type', $params));
        $type = null;
        $subType = null;
        list($type, $params) = $this->handle_market_type_and_params('fetchTickers', $market, $params);
        list($subType, $params) = $this->handle_sub_type_and_params('fetchTickers', $market, $params);
        $request = array();
        $isSpot = ($type === 'spot');
        $future = ($type === 'future');
        $swap = ($type === 'swap');
        $linear = ($subType === 'linear');
        $inverse = ($subType === 'inverse');
        $response = null;
        if (!$isSpot || $isSubTypeRequested) {
            if ($linear) {
                // independently of $type, supports calling all $linear $symbols i.e. fetchTickers(null, array($subType:'linear'))
                if ($future) {
                    $request['business_type'] = 'futures';
                } elseif ($swap) {
                    $request['business_type'] = 'swap';
                } else {
                    $request['business_type'] = 'all';
                }
                $response = $this->contractPublicGetLinearSwapExMarketDetailBatchMerged ($this->extend($request, $params));
            } elseif ($inverse) {
                if ($future) {
                    $response = $this->contractPublicGetMarketDetailBatchMerged ($this->extend($request, $params));
                } elseif ($swap) {
                    $response = $this->contractPublicGetSwapExMarketDetailBatchMerged ($this->extend($request, $params));
                } else {
                    throw new NotSupported($this->id . ' fetchTickers() you have to set $params["type"] to either "swap" or "future" for $inverse contracts');
                }
            } else {
                throw new NotSupported($this->id . ' fetchTickers() you have to set $params["subType"] to either "linear" or "inverse" for contracts');
            }
        } else {
            $response = $this->spotPublicGetMarketTickers ($this->extend($request, $params));
        }
        //
        // spot
        //
        //     {
        //         "data":array(
        //             array(
        //                 "symbol":"hbcbtc",
        //                 "open":5.313E-5,
        //                 "high":5.34E-5,
        //                 "low":5.112E-5,
        //                 "close":5.175E-5,
        //                 "amount":1183.87,
        //                 "vol":0.0618599229,
        //                 "count":205,
        //                 "bid":5.126E-5,
        //                 "bidSize":5.25,
        //                 "ask":5.214E-5,
        //                 "askSize":150.0
        //             ),
        //         ),
        //         "status":"ok",
        //         "ts":1639547261293
        //     }
        //
        // $linear $swap, $linear $future, $inverse $swap, $inverse $future
        //
        //     {
        //         "status":"ok",
        //         "ticks":[
        //             {
        //                 "id":1637504679,
        //                 "ts":1637504679372,
        //                 "ask":[0.10644,100],
        //                 "bid":[0.10624,26],
        //                 "symbol":"TRX_CW",
        //                 "open":"0.10233",
        //                 "close":"0.10644",
        //                 "low":"0.1017",
        //                 "high":"0.10725",
        //                 "amount":"2340267.415144052378486261756692535687481566",
        //                 "count":882,
        //                 "vol":"24706",
        //                 "trade_turnover":"840726.5048", // only in $linear futures
        //                 "business_type":"futures", // only in $linear futures
        //                 "contract_code":"BTC-USDT-CW", // only in $linear futures, instead of 'symbol'
        //             }
        //         ],
        //         "ts":1637504679376
        //     }
        //
        $rawTickers = $this->safe_list_2($response, 'data', 'ticks', array());
        $tickers = $this->parse_tickers($rawTickers, $symbols, $params);
        return $this->filter_by_array_tickers($tickers, 'symbol', $symbols);
    }

    public function fetch_last_prices(?array $symbols = null, $params = array ()) {
        /**
         * fetches the last price for multiple markets
         *
         * @see https://www.htx.com/en-us/opend/newApiPages/?id=8cb81024-77b5-11ed-9966-0242ac110003 linear swap & linear future
         * @see https://www.htx.com/en-us/opend/newApiPages/?id=28c2e8fc-77ae-11ed-9966-0242ac110003 inverse future
         * @see https://www.htx.com/en-us/opend/newApiPages/?id=5d517ef5-77b6-11ed-9966-0242ac110003 inverse swap
         *
         * @param {string[]} [$symbols] unified $symbols of the markets to fetch the last prices
         * @param {array} [$params] extra parameters specific to the exchange API endpoint
         * @return {array} a dictionary of lastprices structures
         */
        $this->load_markets();
        $symbols = $this->market_symbols($symbols);
        $market = $this->get_market_from_symbols($symbols);
        $type = null;
        $subType = null;
        list($subType, $params) = $this->handle_sub_type_and_params('fetchLastPrices', $market, $params);
        list($type, $params) = $this->handle_market_type_and_params('fetchLastPrices', $market, $params);
        $response = null;
        if ((($type === 'swap') || ($type === 'future')) && ($subType === 'linear')) {
            $response = $this->contractPublicGetLinearSwapExMarketTrade ($params);
            //
            //     {
            //         "ch" => "market.*.trade.detail",
            //         "status" => "ok",
            //         "tick" => array(
            //           "data" => array(
            //             array(
            //               "amount" => "4",
            //               "quantity" => "40",
            //               "trade_turnover" => "22.176",
            //               "ts" => 1703697705028,
            //               "id" => 1000003558478170000,
            //               "price" => "0.5544",
            //               "direction" => "buy",
            //               "contract_code" => "MANA-USDT",
            //               "business_type" => "swap",
            //               "trade_partition" => "USDT"
            //             ),
            //           ),
            //           "id" => 1703697740147,
            //           "ts" => 1703697740147
            //         ),
            //         "ts" => 1703697740147
            //     }
            //
        } elseif (($type === 'swap') && ($subType === 'inverse')) {
            $response = $this->contractPublicGetSwapExMarketTrade ($params);
            //
            //     {
            //         "ch" => "market.*.trade.detail",
            //         "status" => "ok",
            //         "tick" => array(
            //           "data" => array(
            //             array(
            //               "amount" => "6",
            //               "quantity" => "94.5000945000945000945000945000945000945",
            //               "ts" => 1703698704594,
            //               "id" => 1000001187811060000,
            //               "price" => "0.63492",
            //               "direction" => "buy",
            //               "contract_code" => "XRP-USD"
            //             ),
            //           ),
            //           "id" => 1703698706589,
            //           "ts" => 1703698706589
            //         ),
            //         "ts" => 1703698706589
            //     }
            //
        } elseif (($type === 'future') && ($subType === 'inverse')) {
            $response = $this->contractPublicGetMarketTrade ($params);
            //
            //     {
            //         "ch" => "market.*.trade.detail",
            //         "status" => "ok",
            //         "tick" => array(
            //           "data" => array(
            //             array(
            //               "amount" => "20",
            //               "quantity" => "44.4444444444444444444444444444444444444",
            //               "ts" => 1686134498885,
            //               "id" => 2323000000174820000,
            //               "price" => "4.5",
            //               "direction" => "sell",
            //               "symbol" => "DORA_CW"
            //             ),
            //           ),
            //           "id" => 1703698855142,
            //           "ts" => 1703698855142
            //         ),
            //         "ts" => 1703698855142
            //     }
            //
        } else {
            throw new NotSupported($this->id . ' fetchLastPrices() does not support ' . $type . ' markets yet');
        }
        $tick = $this->safe_value($response, 'tick', array());
        $data = $this->safe_list($tick, 'data', array());
        return $this->parse_last_prices($data, $symbols);
    }

    public function parse_last_price($entry, ?array $market = null) {
        // example responses are documented in fetchLastPrices
        $marketId = $this->safe_string_2($entry, 'symbol', 'contract_code');
        $market = $this->safe_market($marketId, $market);
        $price = $this->safe_number($entry, 'price');
        $direction = $this->safe_string($entry, 'direction'); // "buy" or "sell"
        // group timestamp should not be assigned to the individual trades' times
        return array(
            'symbol' => $market['symbol'],
            'timestamp' => null,
            'datetime' => null,
            'price' => $price,
            'side' => $direction,
            'info' => $entry,
        );
    }

    public function fetch_order_book(string $symbol, ?int $limit = null, $params = array ()): array {
        /**
         * fetches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
         *
         * @see https://huobiapi.github.io/docs/spot/v1/en/#get-$market-depth
         * @see https://huobiapi.github.io/docs/dm/v1/en/#get-$market-depth
         * @see https://huobiapi.github.io/docs/coin_margined_swap/v1/en/#get-$market-depth
         * @see https://huobiapi.github.io/docs/usdt_swap/v1/en/#general-get-$market-depth
         *
         * @param {string} $symbol unified $symbol of the $market to fetch the order book for
         * @param {int} [$limit] the maximum amount of order book entries to return
         * @param {array} [$params] extra parameters specific to the exchange API endpoint
         * @return {array} A dictionary of ~@link https://docs.ccxt.com/#/?id=order-book-structure order book structures~ indexed by $market symbols
         */
        $this->load_markets();
        $market = $this->market($symbol);
        $request = array(
            //
            // from the API docs
            //
            //     to get depth data within step 150, use step0, step1, step2, step3, step4, step5, step14, step15（merged depth data 0-5,14-15, when step is 0，depth data will not be merged
            //     to get depth data within step 20, use step6, step7, step8, step9, step10, step11, step12, step13(merged depth data 7-13), when step is 6, depth data will not be merged
            //
            'type' => 'step0',
            // 'symbol' => $market['id'], // spot, future
            // 'contract_code' => $market['id'], // swap
        );
        $response = null;
        if ($market['linear']) {
            $request['contract_code'] = $market['id'];
            $response = $this->contractPublicGetLinearSwapExMarketDepth ($this->extend($request, $params));
        } elseif ($market['inverse']) {
            if ($market['future']) {
                $request['symbol'] = $market['id'];
                $response = $this->contractPublicGetMarketDepth ($this->extend($request, $params));
            } elseif ($market['swap']) {
                $request['contract_code'] = $market['id'];
                $response = $this->contractPublicGetSwapExMarketDepth ($this->extend($request, $params));
            }
        } else {
            if ($limit !== null) {
                // Valid depths are 5, 10, 20 or empty https://huobiapi.github.io/docs/spot/v1/en/#get-$market-depth
                if (($limit !== 5) && ($limit !== 10) && ($limit !== 20) && ($limit !== 150)) {
                    throw new BadRequest($this->id . ' fetchOrderBook() $limit argument must be null, 5, 10, 20, or 150, default is 150');
                }
                // only set the depth if it is not 150
                // 150 is the implicit default on the exchange side for step0 and no orderbook aggregation
                // it is not accepted by the exchange if you set it explicitly
                if ($limit !== 150) {
                    $request['depth'] = $limit;
                }
            }
            $request['symbol'] = $market['id'];
            $response = $this->spotPublicGetMarketDepth ($this->extend($request, $params));
        }
        //
        // spot, future, swap
        //
        //     {
        //         "status" => "ok",
        //         "ch" => "market.btcusdt.depth.step0",
        //         "ts" => 1583474832790,
        //         "tick" => {
        //             "bids" => array(
        //                 array( 9100.290000000000000000, 0.200000000000000000 ),
        //                 array( 9099.820000000000000000, 0.200000000000000000 ),
        //                 array( 9099.610000000000000000, 0.205000000000000000 ),
        //             ),
        //             "asks" => array(
        //                 array( 9100.640000000000000000, 0.005904000000000000 ),
        //                 array( 9101.010000000000000000, 0.287311000000000000 ),
        //                 array( 9101.030000000000000000, 0.012121000000000000 ),
        //             ),
        //             "ch":"market.BTC-USD.depth.step0",
        //             "ts":1583474832008,
        //             "id":1637554816,
        //             "mrid":121654491624,
        //             "version":104999698781
        //         }
        //     }
        //
        if (is_array($response) && array_key_exists('tick', $response)) {
            if (!$response['tick']) {
                throw new BadSymbol($this->id . ' fetchOrderBook() returned empty $response => ' . $this->json($response));
            }
            $tick = $this->safe_value($response, 'tick');
            $timestamp = $this->safe_integer($tick, 'ts', $this->safe_integer($response, 'ts'));
            $result = $this->parse_order_book($tick, $symbol, $timestamp);
            $result['nonce'] = $this->safe_integer($tick, 'version');
            return $result;
        }
        throw new ExchangeError($this->id . ' fetchOrderBook() returned unrecognized $response => ' . $this->json($response));
    }

    public function parse_trade(array $trade, ?array $market = null): array {
        //
        // 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 = $this->safe_string_2($trade, 'contract_code', 'symbol');
        $market = $this->safe_market($marketId, $market);
        $symbol = $market['symbol'];
        $timestamp = $this->safe_integer_2($trade, 'ts', 'created-at');
        $timestamp = $this->safe_integer_2($trade, 'created_at', 'create_date', $timestamp);
        $order = $this->safe_string_2($trade, 'order-id', 'order_id');
        $side = $this->safe_string($trade, 'direction');
        $type = $this->safe_string($trade, 'type');
        if ($type !== null) {
            $typeParts = explode('-', $type);
            $side = $typeParts[0];
            $type = $typeParts[1];
        }
        $takerOrMaker = $this->safe_string_lower($trade, 'role');
        $priceString = $this->safe_string_2($trade, 'price', 'trade_price');
        $amountString = $this->safe_string_2($trade, 'filled-amount', 'amount');
        $amountString = $this->safe_string($trade, 'trade_volume', $amountString);
        $costString = $this->safe_string($trade, 'trade_turnover');
        $fee = null;
        $feeCost = $this->safe_string($trade, 'filled-fees');
        if ($feeCost === null) {
            $feeCost = Precise::string_neg($this->safe_string($trade, 'trade_fee'));
        }
        $feeCurrencyId = $this->safe_string_2($trade, 'fee-currency', 'fee_asset');
        $feeCurrency = $this->safe_currency_code($feeCurrencyId);
        $filledPoints = $this->safe_string($trade, 'filled-points');
        if ($filledPoints !== null) {
            if (($feeCost === null) || Precise::string_equals($feeCost, '0')) {
                $feeDeductCurrency = $this->safe_string($trade, 'fee-deduct-currency');
                if ($feeDeductCurrency !== null) {
                    $feeCost = $filledPoints;
                    $feeCurrency = $this->safe_currency_code($feeDeductCurrency);
                }
            }
        }
        if ($feeCost !== null) {
            $fee = array(
                'cost' => $feeCost,
                'currency' => $feeCurrency,
            );
        }
        // htx's multi-$market $trade-$id is a bit complex to parse accordingly.
        // - for `$id` which contains hyphen, it would be the unique $id, eg. xxxxxx-1, xxxxxx-2 (this happens mostly for contract markets)
        // - otherwise the least priority is given to the `$id` key
        $id = null;
        $safeId = $this->safe_string($trade, 'id');
        if ($safeId !== null && mb_strpos($safeId, '-') !== false) {
            $id = $safeId;
        } else {
            $id = $this->safe_string_n($trade, array( 'trade_id', 'trade-id', 'id' ));
        }
        return $this->safe_trade(array(
            'id' => $id,
            'info' => $trade,
            'order' => $order,
            'timestamp' => $timestamp,
            'datetime' => $this->iso8601($timestamp),
            'symbol' => $symbol,
            'type' => $type,
            'side' => $side,
            'takerOrMaker' => $takerOrMaker,
            'price' => $priceString,
            'amount' => $amountString,
            'cost' => $costString,
            'fee' => $fee,
        ), $market);
    }

    public function fetch_order_trades(string $id, ?string $symbol = null, ?int $since = null, ?int $limit = null, $params = array ()) {
        /**
         * fetch all the trades made from a single order
         *
         * @see https://huobiapi.github.io/docs/spot/v1/en/#get-the-match-result-of-an-order
         *
         * @param {string} $id order $id
         * @param {string} $symbol unified $market $symbol
         * @param {int} [$since] the earliest time in ms to fetch trades for
         * @param {int} [$limit] the maximum number of trades to retrieve
         * @param {array} [$params] extra parameters specific to the exchange API endpoint
         * @return {array[]} a list of ~@link https://docs.ccxt.com/#/?$id=trade-structure trade structures~
         */
        $market = null;
        if ($symbol !== null) {
            $market = $this->market($symbol);
        }
        $marketType = null;
        list($marketType, $params) = $this->handle_market_type_and_params('fetchOrderTrades', $market, $params);
        if ($marketType !== 'spot') {
            throw new NotSupported($this->id . ' fetchOrderTrades() is only supported for spot markets');
        }
        return $this->fetch_spot_order_trades($id, $symbol, $since, $limit, $params);
    }

    public function fetch_spot_order_trades(string $id, ?string $symbol = null, ?int $since = null, ?int $limit = null, $params = array ()) {
        /**
         * @ignore
         * fetch all the trades made from a single order
         *
         * @see https://huobiapi.github.io/docs/spot/v1/en/#get-the-match-result-of-an-order
         *
         * @param {string} $id order $id
         * @param {string} $symbol unified market $symbol
         * @param {int} [$since] the earliest time in ms to fetch trades for
         * @param {int} [$limit] the maximum number of trades to retrieve
         * @param {array} [$params] extra parameters specific to the exchange API endpoint
         * @return {array[]} a list of ~@link https://docs.ccxt.com/#/?$id=trade-structure trade structures~
         */
        $this->load_markets();
        $request = array(
            'order-id' => $id,
        );
        $response = $this->spotPrivateGetV1OrderOrdersOrderIdMatchresults ($this->extend($request, $params));
        return $this->parse_trades($response['data'], null, $since, $limit);
    }

    public function fetch_my_trades(?string $symbol = null, ?int $since = null, ?int $limit = null, $params = array ()) {
        /**
         *
         * @see https://huobiapi.github.io/docs/usdt_swap/v1/en/#isolated-get-history-match-results-via-multiple-fields-new
         * @see https://huobiapi.github.io/docs/usdt_swap/v1/en/#cross-get-history-match-results-via-multiple-fields-new
         * @see https://huobiapi.github.io/docs/spot/v1/en/#search-match-results
         *
         * fetch all $trades made by the user
         * @param {string} $symbol unified $market $symbol
         * @param {int} [$since] the earliest time in ms to fetch $trades for
         * @param {int} [$limit] the maximum number of $trades structures to retrieve
         * @param {array} [$params] extra parameters specific to the exchange API endpoint
         * @param {int} [$params->until] the latest time in ms to fetch $trades for
         * @param {boolean} [$params->paginate] default false, when true will automatically $paginate by calling this endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-$params)
         * @return {Trade[]} a list of ~@link https://docs.ccxt.com/#/?id=trade-structure trade structures~
         */
        $this->load_markets();
        $paginate = false;
        list($paginate, $params) = $this->handle_option_and_params($params, 'fetchMyTrades', 'paginate');
        if ($paginate) {
            return $this->fetch_paginated_call_dynamic('fetchMyTrades', $symbol, $since, $limit, $params);
        }
        $market = null;
        if ($symbol !== null) {
            $market = $this->market($symbol);
        }
        $marketType = null;
        list($marketType, $params) = $this->handle_market_type_and_params('fetchMyTrades', $market, $params);
        $request = array(
            // 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' => $this->milliseconds(), // max 48 hours within 120 days
            // 'from' => 'id', // tring false N/A Search internal id to begin with if search next page, then this should be the last id (not trade-id) of last page; if search previous page, then this 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' => $this->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 this should be the last id (not trade-id) of last page; if search previous page, then this should be the first id (not trade-id) of last page
            // 'direct' => 'prev', // next, prev
            // 'size' => $limit, // default 20, max 50
        );
        $response = null;
        if ($marketType === 'spot') {
            if ($symbol !== null) {
                $market = $this->market($symbol);
                $request['symbol'] = $market['id'];
            }
            if ($limit !== null) {
                $request['size'] = $limit; // default 100, max 500
            }
            if ($since !== null) {
                $request['start-time'] = $since; // a date within 120 days from today
                // $request['end-time'] = $this->sum($since, 172800000); // 48 hours window
            }
            list($request, $params) = $this->handle_until_option('end-time', $request, $params);
            $response = $this->spotPrivateGetV1OrderMatchresults ($this->extend($request, $params));
        } else {
            if ($symbol === null) {
                throw new ArgumentsRequired($this->id . ' fetchMyTrades() requires a $symbol argument');
            }
            $request['contract'] = $market['id'];
            $request['trade_type'] = 0; // 0 all, 1 open long, 2 open short, 3 close short, 4 close long, 5 liquidate long positions, 6 liquidate short positions
            if ($since !== null) {
                $request['start_time'] = $since; // a date within 120 days from today
                // $request['end_time'] = $this->sum($request['start_time'], 172800000); // 48 hours window
            }
            list($request, $params) = $this->handle_until_option('end_time', $request, $params);
            if ($limit !== null) {
                $request['page_size'] = $limit; // default 100, max 500
            }
            if ($market['linear']) {
                $marginMode = null;
                list($marginMode, $params) = $this->handle_margin_mode_and_params('fetchMyTrades', $params);
                $marginMode = ($marginMode === null) ? 'cross' : $marginMode;
                if ($marginMode === 'isolated') {
                    $response = $this->contractPrivatePostLinearSwapApiV3SwapMatchresultsExact ($this->extend($request, $params));
                } elseif ($marginMode === 'cross') {
                    $response = $this->contractPrivatePostLinearSwapApiV3SwapCrossMatchresultsExact ($this->extend($request, $params));
                }
            } elseif ($market['inverse']) {
                if ($marketType === 'future') {
                    $request['symbol'] = $market['settleId'];
                    $response = $this->contractPrivatePostApiV3ContractMatchresultsExact ($this->extend($request, $params));
                } elseif ($marketType === 'swap') {
                    $response = $this->contractPrivatePostSwapApiV3SwapMatchresultsExact ($this->extend($request, $params));
                } else {
                    throw new NotSupported($this->id . ' fetchMyTrades() does not support ' . $marketType . ' markets');
                }
            }
        }
        //
        // spot
        //
        //     {
        //         "status" => "ok",
        //         "data" => array(
        //             {
        //                 "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" => array(
        //                 array(
        //                     "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 = $this->safe_value($response, 'data');
        if (gettype($trades) !== 'array' || array_keys($trades) !== array_keys(array_keys($trades))) {
            $trades = $this->safe_value($trades, 'trades');
        }
        return $this->parse_trades($trades, $market, $since, $limit);
    }

    public function fetch_trades(string $symbol, ?int $since = null, ?int $limit = 1000, $params = array ()): array {
        /**
         *
         * @see https://huobiapi.github.io/docs/spot/v1/en/#get-the-most-recent-$trades
         * @see https://huobiapi.github.io/docs/dm/v1/en/#query-a-batch-of-$trade-records-of-a-contract
         * @see https://huobiapi.github.io/docs/coin_margined_swap/v1/en/#query-a-batch-of-$trade-records-of-a-contract
         * @see https://huobiapi.github.io/docs/usdt_swap/v1/en/#general-query-a-batch-of-$trade-records-of-a-contract
         *
         * get the list of most recent $trades for a particular $symbol
         * @param {string} $symbol unified $symbol of the $market to fetch $trades for
         * @param {int} [$since] timestamp in ms of the earliest $trade to fetch
         * @param {int} [$limit] the maximum amount of $trades to fetch
         * @param {array} [$params] extra parameters specific to the exchange API endpoint
         * @return {Trade[]} a list of ~@link https://docs.ccxt.com/#/?id=public-$trades $trade structures~
         */
        $this->load_markets();
        $market = $this->market($symbol);
        $request = array(
            // 'symbol' => $market['id'], // spot, future
            // 'contract_code' => $market['id'], // swap
        );
        if ($limit !== null) {
            $request['size'] = min ($limit, 2000); // max 2000
        }
        $response = null;
        if ($market['future']) {
            if ($market['inverse']) {
                $request['symbol'] = $market['id'];
                $response = $this->contractPublicGetMarketHistoryTrade ($this->extend($request, $params));
            } elseif ($market['linear']) {
                $request['contract_code'] = $market['id'];
                $response = $this->contractPublicGetLinearSwapExMarketHistoryTrade ($this->extend($request, $params));
            }
        } elseif ($market['swap']) {
            $request['contract_code'] = $market['id'];
            if ($market['inverse']) {
                $response = $this->contractPublicGetSwapExMarketHistoryTrade ($this->extend($request, $params));
            } elseif ($market['linear']) {
                $response = $this->contractPublicGetLinearSwapExMarketHistoryTrade ($this->extend($request, $params));
            }
        } else {
            $request['symbol'] = $market['id'];
            $response = $this->spotPublicGetMarketHistoryTrade ($this->extend($request, $params));
        }
        //
        //     {
        //         "status" => "ok",
        //         "ch" => "market.btcusdt.trade.detail",
        //         "ts" => 1583497692365,
        //         "data" => array(
        //             {
        //                 "id" => 105005170342,
        //                 "ts" => 1583497692182,
        //                 "data" => array(
        //                     array(
        //                         "amount" => 0.010411000000000000,
        //                         "trade-id" => 102090736910,
        //                         "ts" => 1583497692182,
        //                         "id" => 10500517034273194594947,
        //                         "price" => 9096.050000000000000000,
        //                         "direction" => "sell"
        //                     }
        //                 )
        //             ),
        //             // ...
        //         )
        //     }
        //
        $data = $this->safe_value($response, 'data', array());
        $result = array();
        for ($i = 0; $i < count($data); $i++) {
            $trades = $this->safe_value($data[$i], 'data', array());
            for ($j = 0; $j < count($trades); $j++) {
                $trade = $this->parse_trade($trades[$j], $market);
                $result[] = $trade;
            }
        }
        $result = $this->sort_by($result, 'timestamp');
        return $this->filter_by_symbol_since_limit($result, $market['symbol'], $since, $limit);
    }

    public function parse_ohlcv($ohlcv, ?array $market = null): array {
        //
        //     {
        //         "amount":1.2082,
        //         "open":0.025096,
        //         "close":0.025095,
        //         "high":0.025096,
        //         "id":1591515300,
        //         "count":6,
        //         "low":0.025095,
        //         "vol":0.0303205097
        //     }
        //
        return array(
            $this->safe_timestamp($ohlcv, 'id'),
            $this->safe_number($ohlcv, 'open'),
            $this->safe_number($ohlcv, 'high'),
            $this->safe_number($ohlcv, 'low'),
            $this->safe_number($ohlcv, 'close'),
            $this->safe_number($ohlcv, 'amount'),
        );
    }

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

    public function fetch_accounts($params = array ()): array {
        /**
         * fetch all the accounts associated with a profile
         *
         * @see https://huobiapi.github.io/docs/spot/v1/en/#get-all-accounts-of-the-current-user
         *
         * @param {array} [$params] extra parameters specific to the exchange API endpoint
         * @return {array} a dictionary of ~@link https://docs.ccxt.com/#/?id=account-structure account structures~ indexed by the account type
         */
        $this->load_markets();
        $response = $this->spotPrivateGetV1AccountAccounts ($params);
        //
        //     {
        //         "status":"ok",
        //         "data":array(
        //             array("id":5202591,"type":"point","subtype":"","state":"working"),
        //             array("id":1528640,"type":"spot","subtype":"","state":"working"),
        //         )
        //     }
        //
        $data = $this->safe_value($response, 'data');
        return $this->parse_accounts($data);
    }

    public function parse_account($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 = $this->safe_string($account, 'type');
        $accountsById = $this->safe_value($this->options, 'accountsById', array());
        $type = $this->safe_value($accountsById, $typeId, $typeId);
        return array(
            'info' => $account,
            'id' => $this->safe_string($account, 'id'),
            'type' => $type,
            'code' => null,
        );
    }

    public function fetch_account_id_by_type(string $type, ?string $marginMode = null, ?string $symbol = null, $params = array ()) {
        /**
         * fetch all the $accounts by a $type and marginModeassociated with a profile
         *
         * @see https://huobiapi.github.io/docs/spot/v1/en/#get-all-$accounts-of-the-current-user
         *
         * @param {string} $type 'spot', 'swap' or 'future
         * @param {string} [$marginMode] 'cross' or 'isolated'
         * @param {string} [$symbol] unified ccxt market $symbol
         * @param {array} [$params] extra parameters specific to the exchange API endpoint
         * @return {array} a dictionary of ~@link https://docs.ccxt.com/#/?id=$account-structure $account structures~ indexed by the $account $type
         */
        $accounts = $this->load_accounts();
        $accountId = $this->safe_value_2($params, 'accountId', 'account-id');
        if ($accountId !== null) {
            return $accountId;
        }
        if ($type === 'spot') {
            if ($marginMode === 'cross') {
                $type = 'super-margin';
            } elseif ($marginMode === 'isolated') {
                $type = 'margin';
            }
        }
        $marketId = null;
        if ($symbol !== null) {
            $marketId = $this->market_id($symbol);
        }
        for ($i = 0; $i < count($accounts); $i++) {
            $account = $accounts[$i];
            $info = $this->safe_value($account, 'info');
            $subtype = $this->safe_string($info, 'subtype', null);
            $typeFromAccount = $this->safe_string($account, 'type');
            if ($type === 'margin') {
                if ($subtype === $marketId) {
                    return $this->safe_string($account, 'id');
                }
            } elseif ($type === $typeFromAccount) {
                return $this->safe_string($account, 'id');
            }
        }
        $defaultAccount = $this->safe_value($accounts, 0, array());
        return $this->safe_string($defaultAccount, 'id');
    }

    public function fetch_currencies($params = array ()): ?array {
        /**
         * fetches all available currencies on an exchange
         *
         * @see https://huobiapi.github.io/docs/spot/v1/en/#apiv2-currency-amp-$chains
         *
         * @param {array} [$params] extra parameters specific to the exchange API endpoint
         * @return {array} an associative dictionary of currencies
         */
        $response = $this->spotPublicGetV2ReferenceCurrencies ($params);
        //
        //    {
        //        "code" => 200,
        //        "data" => array(
        //            {
        //                "currency" => "sxp",
        //                "assetType" => "1",
        //                "chains" => array(
        //                    {
        //                        "chain" => "sxp",
        //                        "displayName" => "ERC20",
        //                        "baseChain" => "ETH",
        //                        "baseChainProtocol" => "ERC20",
        //                        "isDynamic" => true,
        //                        "numOfConfirmations" => "12",
        //                        "numOfFastConfirmations" => "12",
        //                        "depositStatus" => "allowed",
        //                        "minDepositAmt" => "0.23",
        //                        "withdrawStatus" => "allowed",
        //                        "minWithdrawAmt" => "0.23",
        //                        "withdrawPrecision" => "8",
        //                        "maxWithdrawAmt" => "227000.000000000000000000",
        //                        "withdrawQuotaPerDay" => "227000.000000000000000000",
        //                        "withdrawQuotaPerYear" => null,
        //                        "withdrawQuotaTotal" => null,
        //                        "withdrawFeeType" => "fixed",
        //                        "transactFeeWithdraw" => "11.1654",
        //                        "addrWithTag" => false,
        //                        "addrDepositTag" => false
        //                    }
        //                ),
        //                "instStatus" => "normal"
        //            }
        //        )
        //    }
        //
        $data = $this->safe_list($response, 'data', array());
        $result = array();
        $this->options['networkChainIdsByNames'] = array();
        $this->options['networkNamesByChainIds'] = array();
        for ($i = 0; $i < count($data); $i++) {
            $entry = $data[$i];
            $currencyId = $this->safe_string($entry, 'currency');
            $code = $this->safe_currency_code($currencyId);
            $assetType = $this->safe_string($entry, 'assetType');
            $type = $assetType === '1' ? 'crypto' : 'fiat';
            $this->options['networkChainIdsByNames'][$code] = array();
            $chains = $this->safe_list($entry, 'chains', array());
            $networks = array();
            for ($j = 0; $j < count($chains); $j++) {
                $chainEntry = $chains[$j];
                $uniqueChainId = $this->safe_string($chainEntry, 'chain'); // $i->e. usdterc20, trc20usdt ...
                $title = $this->safe_string_2($chainEntry, 'baseChain', 'displayName'); // baseChain and baseChainProtocol are together existent or inexistent in entries, but baseChain is preferred. when they are both inexistent, then we use generic displayName
                $this->options['networkChainIdsByNames'][$code][$title] = $uniqueChainId;
                $this->options['networkNamesByChainIds'][$uniqueChainId] = $title;
                $networkCode = $this->network_id_to_code($uniqueChainId);
                $networks[$networkCode] = array(
                    'info' => $chainEntry,
                    'id' => $uniqueChainId,
                    'network' => $networkCode,
                    'limits' => array(
                        'deposit' => array(
                            'min' => $this->safe_number($chainEntry, 'minDepositAmt'),
                            'max' => null,
                        ),
                        'withdraw' => array(
                            'min' => $this->safe_number($chainEntry, 'minWithdrawAmt'),
                            'max' => $this->safe_number($chainEntry, 'maxWithdrawAmt'),
                        ),
                    ),
                    'active' => null,
                    'deposit' => $this->safe_string($chainEntry, 'depositStatus') === 'allowed',
                    'withdraw' => $this->safe_string($chainEntry, 'withdrawStatus') === 'allowed',
                    'fee' => $this->safe_number($chainEntry, 'transactFeeWithdraw'),
                    'precision' => $this->parse_number($this->parse_precision($this->safe_string($chainEntry, 'withdrawPrecision'))),
                );
            }
            $result[$code] = $this->safe_currency_structure(array(
                'info' => $entry,
                'code' => $code,
                'id' => $currencyId,
                'active' => $this->safe_string($entry, 'instStatus') === 'normal',
                'deposit' => null,
                'withdraw' => null,
                'fee' => null,
                'name' => null,
                'type' => $type,
                'limits' => array(
                    'amount' => array(
                        'min' => null,
                        'max' => null,
                    ),
                    'withdraw' => array(
                        'min' => null,
                        'max' => null,
                    ),
                    'deposit' => array(
                        'min' => null,
                        'max' => null,
                    ),
                ),
                'precision' => null,
                'networks' => $networks,
            ));
        }
        return $result;
    }

    public function network_id_to_code(?string $networkId = null, ?string $currencyCode = null) {
        // here network-id is provided pair of currency & chain (i.e. trc20usdt)
        $keys = is_array($this->options['networkNamesByChainIds']) ? array_keys($this->options['networkNamesByChainIds']) : array();
        $keysLength = count($keys);
        if ($keysLength === 0) {
            throw new ExchangeError($this->id . ' networkIdToCode() - markets need to be loaded at first');
        }
        $networkTitle = $this->safe_value($this->options['networkNamesByChainIds'], $networkId, $networkId);
        return parent::network_id_to_code($networkTitle);
    }

    public function network_code_to_id(string $networkCode, ?string $currencyCode = null) {
        if ($currencyCode === null) {
            throw new ArgumentsRequired($this->id . ' networkCodeToId() requires a $currencyCode argument');
        }
        $keys = is_array($this->options['networkChainIdsByNames']) ? array_keys($this->options['networkChainIdsByNames']) : array();
        $keysLength = count($keys);
        if ($keysLength === 0) {
            throw new ExchangeError($this->id . ' networkCodeToId() - markets need to be loaded at first');
        }
        $uniqueNetworkIds = $this->safe_value($this->options['networkChainIdsByNames'], $currencyCode, array());
        if (is_array($uniqueNetworkIds) && array_key_exists($networkCode, $uniqueNetworkIds)) {
            return $uniqueNetworkIds[$networkCode];
        } else {
            $networkTitle = parent::network_code_to_id($networkCode);
            return $this->safe_value($uniqueNetworkIds, $networkTitle, $networkTitle);
        }
    }

    public function fetch_balance($params = array ()): array {
        /**
         *
         * @see https://huobiapi.github.io/docs/spot/v1/en/#get-$account-$balance-of-a-specific-$account
         * @see https://www.htx.com/en-us/opend/newApiPages/?id=7ec4b429-7773-11ed-9966-0242ac110003
         * @see https://www.htx.com/en-us/opend/newApiPages/?id=10000074-77b7-11ed-9966-0242ac110003
         * @see https://huobiapi.github.io/docs/dm/v1/en/#query-asset-valuation
         * @see https://huobiapi.github.io/docs/coin_margined_swap/v1/en/#query-user-s-$account-information
         * @see https://huobiapi.github.io/docs/usdt_swap/v1/en/#$isolated-query-user-s-$account-information
         * @see https://huobiapi.github.io/docs/usdt_swap/v1/en/#$cross-query-user-39-s-$account-information
         *
         * query for $balance and get the amount of funds available for trading or funds locked in orders
         * @param {array} [$params] extra parameters specific to the exchange API endpoint
         * @param {bool} [$params->unified] provide this parameter if you have a recent $account with unified $cross+$isolated $margin $account
         * @return {array} a ~@link https://docs.ccxt.com/#/?id=$balance-structure $balance structure~
         */
        $this->load_markets();
        $type = null;
        list($type, $params) = $this->handle_market_type_and_params('fetchBalance', null, $params);
        $options = $this->safe_value($this->options, 'fetchBalance', array());
        $isUnifiedAccount = $this->safe_value_2($params, 'isUnifiedAccount', 'unified', false);
        $params = $this->omit($params, array( 'isUnifiedAccount', 'unified' ));
        $request = array();
        $spot = ($type === 'spot');
        $future = ($type === 'future');
        $defaultSubType = $this->safe_string_2($this->options, 'defaultSubType', 'subType', 'linear');
        $subType = $this->safe_string_2($options, 'defaultSubType', 'subType', $defaultSubType);
        $subType = $this->safe_string_2($params, 'defaultSubType', 'subType', $subType);
        $inverse = ($subType === 'inverse');
        $linear = ($subType === 'linear');
        $marginMode = null;
        list($marginMode, $params) = $this->handle_margin_mode_and_params('fetchBalance', $params);
        $params = $this->omit($params, array( 'defaultSubType', 'subType' ));
        $isolated = ($marginMode === 'isolated');
        $cross = ($marginMode === 'cross');
        $margin = ($type === 'margin') || ($spot && ($cross || $isolated));
        $response = null;
        if ($spot || $margin) {
            if ($margin) {
                if ($isolated) {
                    $response = $this->spotPrivateGetV1MarginAccountsBalance ($this->extend($request, $params));
                } else {
                    $response = $this->spotPrivateGetV1CrossMarginAccountsBalance ($this->extend($request, $params));
                }
            } else {
                $this->load_accounts();
                $accountId = $this->fetch_account_id_by_type($type, null, null, $params);
                $request['account-id'] = $accountId;
                $response = $this->spotPrivateGetV1AccountAccountsAccountIdBalance ($this->extend($request, $params));
            }
        } elseif ($isUnifiedAccount) {
            $response = $this->contractPrivateGetLinearSwapApiV3UnifiedAccountInfo ($this->extend($request, $params));
        } elseif ($linear) {
            if ($isolated) {
                $response = $this->contractPrivatePostLinearSwapApiV1SwapAccountInfo ($this->extend($request, $params));
            } else {
                $response = $this->contractPrivatePostLinearSwapApiV1SwapCrossAccountInfo ($this->extend($request, $params));
            }
        } elseif ($inverse) {
            if ($future) {
                $response = $this->contractPrivatePostApiV1ContractAccountInfo ($this->extend($request, $params));
            } else {
                $response = $this->contractPrivatePostSwapApiV1SwapAccountInfo ($this->extend($request, $params));
            }
        }
        //
        // $spot
        //
        //     {
        //         "status" => "ok",
        //         "data" => array(
        //             "id" => 1528640,
        //             "type" => "spot",
        //             "state" => "working",
        //             "list" => array(
        //                 array( "currency" => "lun", "type" => "trade", "balance" => "0", "seq-num" => "0" ),
        //                 array( "currency" => "lun", "type" => "frozen", "balance" => "0", "seq-num" => "0" ),
        //                 array( "currency" => "ht", "type" => "frozen", "balance" => "0", "seq-num" => "145" ),
        //             )
        //         ),
        //         "ts":1637644827566
        //     }
        //
        // $cross $margin
        //
        //     {
        //         "status" => "ok",
        //         "data" => array(
        //             "id" => 51015302,
        //             "type" => "cross-$margin",
        //             "state" => "working",
        //             "risk-rate" => "2",
        //             "acct-$balance-sum" => "100",
        //             "debt-$balance-sum" => "0",
        //             "list" => array(
        //                 array( "currency" => "usdt", "type" => "trade", "balance" => "100" ),
        //                 array( "currency" => "usdt", "type" => "frozen", "balance" => "0" ),
        //                 array( "currency" => "usdt", "type" => "loan-available", "balance" => "200" ),
        //                 array( "currency" => "usdt", "type" => "transfer-out-available", "balance" => "-1" ),
        //                 array( "currency" => "ht", "type" => "loan-available", "balance" => "36.60724091" ),
        //                 array( "currency" => "ht", "type" => "transfer-out-available", "balance" => "-1" ),
        //                 array( "currency" => "btc", "type" => "trade", "balance" => "1168.533000000000000000" ),
        //                 array( "currency" => "btc", "type" => "frozen", "balance" => "0.000000000000000000" ),
        //                 array( "currency" => "btc", "type" => "loan", "balance" => "-2.433000000000000000" ),
        //                 array( "currency" => "btc", "type" => "interest", "balance" => "-0.000533000000000000" ),
        //                 array( "currency" => "btc", "type" => "transfer-out-available", "balance" => "1163.872174670000000000" ),
        //                 array( "currency" => "btc", "type" => "loan-available", "balance" => "8161.876538350676000000" )
        //             )
        //         ),
        //         "code" => 200
        //     }
        //
        // $isolated $margin
        //
        //     {
        //         "data" => array(
        //             {
        //                 "id" => 18264,
        //                 "type" => "margin",
        //                 "state" => "working",
        //                 "symbol" => "btcusdt",
        //                 "fl-price" => "0",
        //                 "fl-$type" => "safe",
        //                 "risk-rate" => "475.952571086994250554",
        //                 "list" => array(
        //                     array( "currency" => "btc","type" => "trade","balance" => "1168.533000000000000000" ),
        //                     array( "currency" => "btc","type" => "frozen","balance" => "0.000000000000000000" ),
        //                     array( "currency" => "btc","type" => "loan","balance" => "-2.433000000000000000" ),
        //                     array( "currency" => "btc","type" => "interest","balance" => "-0.000533000000000000" ),
        //                     array( "currency" => "btc","type" => "transfer-out-available", "balance" => "1163.872174670000000000" ),
        //                     array( "currency" => "btc","type" => "loan-available", "balance" => "8161.876538350676000000" )
        //                 )
        //             }
        //         )
        //     }
        //
        // $future, swap $isolated
        //
        //     {
        //         "status" => "ok",
        //         "data" => array(
        //             array(
        //                 "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" => array(
        //             {
        //                 "futures_contract_detail" => array(
        //                     array(
        //                         "symbol" => "ETH",
        //                         "contract_code" => "ETH-USDT-220325",
        //                         "margin_position" => 0,
        //                         "margin_frozen" => 0,
        //                         "margin_available" => 200.000000000000000000,
        //                         "profit_unreal" => 0E-18,
        //                         "liquidation_price" => null,
        //                         "lever_rate" => 5,
        //                         "adjust_factor" => 0.060000000000000000,
        //                         "contract_type" => "quarter",
        //                         "pair" => "ETH-USDT",
        //                         "business_type" => "futures"
        //                     ),
        //                 ),
        //                 "margin_mode" => "cross",
        //                 "margin_account" => "USDT",
        //                 "margin_asset" => "USDT",
        //                 "margin_balance" => 49.874186030200000000,
        //                 "money_in" => 50,
        //                 "money_out" => 0,
        //                 "margin_static" => 49.872786030200000000,
        //                 "margin_position" => 6.180000000000000000,
        //                 "margin_frozen" => 6.000000000000000000,
        //                 "profit_unreal" => 0.001400000000000000,
        //                 "withdraw_available" => 37.6927860302,
        //                 "risk_rate" => 271.984050521072796934,
        //                 "new_risk_rate" => 0.001858676950514399,
        //                 "contract_detail" => array(
        //                     array(
        //                         "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 = array( 'info' => $response );
        $data = $this->safe_value($response, 'data');
        if ($spot || $margin) {
            if ($isolated) {
                for ($i = 0; $i < count($data); $i++) {
                    $entry = $data[$i];
                    $symbol = $this->safe_symbol($this->safe_string($entry, 'symbol'));
                    $balances = $this->safe_value($entry, 'list');
                    $subResult = array();
                    for ($j = 0; $j < count($balances); $j++) {
                        $balance = $balances[$j];
                        $currencyId = $this->safe_string($balance, 'currency');
                        $code = $this->safe_currency_code($currencyId);
                        $subResult[$code] = $this->parse_margin_balance_helper($balance, $code, $subResult);
                    }
                    $result[$symbol] = $this->safe_balance($subResult);
                }
            } else {
                $balances = $this->safe_value($data, 'list', array());
                for ($i = 0; $i < count($balances); $i++) {
                    $balance = $balances[$i];
                    $currencyId = $this->safe_string($balance, 'currency');
                    $code = $this->safe_currency_code($currencyId);
                    $result[$code] = $this->parse_margin_balance_helper($balance, $code, $result);
                }
                $result = $this->safe_balance($result);
            }
        } elseif ($isUnifiedAccount) {
            for ($i = 0; $i < count($data); $i++) {
                $entry = $data[$i];
                $marginAsset = $this->safe_string($entry, 'margin_asset');
                $currencyCode = $this->safe_currency_code($marginAsset);
                if ($isolated) {
                    $isolated_swap = $this->safe_value($entry, 'isolated_swap', array());
                    for ($j = 0; $j < count($isolated_swap); $j++) {
                        $balance = $isolated_swap[$j];
                        $marketId = $this->safe_string($balance, 'contract_code');
                        $subBalance = array(
                            'code' => $currencyCode,
                            'free' => $this->safe_number($balance, 'margin_available'),
                        );
                        $symbol = $this->safe_symbol($marketId);
                        $result[$symbol] = $subBalance;
                        $result = $this->safe_balance($result);
                    }
                } else {
                    $account = $this->account();
                    $account['free'] = $this->safe_string($entry, 'margin_static');
                    $account['used'] = $this->safe_string($entry, 'margin_frozen');
                    $result[$currencyCode] = $account;
                    $result = $this->safe_balance($result);
                }
            }
        } elseif ($linear) {
            $first = $this->safe_value($data, 0, array());
            if ($isolated) {
                for ($i = 0; $i < count($data); $i++) {
                    $balance = $data[$i];
                    $marketId = $this->safe_string_2($balance, 'contract_code', 'margin_account');
                    $market = $this->safe_market($marketId);
                    $currencyId = $this->safe_string($balance, 'margin_asset');
                    $currency = $this->safe_currency($currencyId);
                    $code = $this->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 !== null) {
                        $account = $this->account();
                        $account['free'] = $this->safe_string($balance, 'margin_balance');
                        $account['used'] = $this->safe_string($balance, 'margin_frozen');
                        $accountsByCode = array();
                        $accountsByCode[$code] = $account;
                        $symbol = $market['symbol'];
                        $result[$symbol] = $this->safe_balance($accountsByCode);
                    }
                }
            } else {
                $account = $this->account();
                $account['free'] = $this->safe_string($first, 'withdraw_available');
                $account['total'] = $this->safe_string($first, 'margin_balance');
                $currencyId = $this->safe_string_2($first, 'margin_asset', 'symbol');
                $code = $this->safe_currency_code($currencyId);
                $result[$code] = $account;
                $result = $this->safe_balance($result);
            }
        } elseif ($inverse) {
            for ($i = 0; $i < count($data); $i++) {
                $balance = $data[$i];
                $currencyId = $this->safe_string($balance, 'symbol');
                $code = $this->safe_currency_code($currencyId);
                $account = $this->account();
                $account['free'] = $this->safe_string($balance, 'margin_available');
                $account['used'] = $this->safe_string($balance, 'margin_frozen');
                $result[$code] = $account;
            }
            $result = $this->safe_balance($result);
        }
        return $result;
    }

    public function fetch_order(string $id, ?string $symbol = null, $params = array ()) {
        /**
         * fetches information on an $order made by the user
         *
         * @see https://huobiapi.github.io/docs/spot/v1/en/#get-the-$order-detail-of-an-$order-based-on-client-$order-$id
         * @see https://huobiapi.github.io/docs/spot/v1/en/#get-the-$order-detail-of-an-$order
         * @see https://huobiapi.github.io/docs/usdt_swap/v1/en/#isolated-get-information-of-an-$order
         * @see https://huobiapi.github.io/docs/usdt_swap/v1/en/#cross-get-information-of-$order
         * @see https://huobiapi.github.io/docs/dm/v1/en/#get-information-of-an-$order
         * @see https://huobiapi.github.io/docs/coin_margined_swap/v1/en/#get-information-of-an-$order
         *
         * @param {string} $id $order $id
         * @param {string} $symbol unified $symbol of the $market the $order was made in
         * @param {array} [$params] extra parameters specific to the exchange API endpoint
         * @return {array} An ~@link https://docs.ccxt.com/#/?$id=$order-structure $order structure~
         */
        $this->load_markets();
        $market = null;
        if ($symbol !== null) {
            $market = $this->market($symbol);
        }
        $marketType = null;
        list($marketType, $params) = $this->handle_market_type_and_params('fetchOrder', $market, $params);
        $request = array(
            // 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, this_week, next_week, quarter, next_ quarter
        );
        $response = null;
        if ($marketType === 'spot') {
            $clientOrderId = $this->safe_string($params, 'clientOrderId');
            if ($clientOrderId !== null) {
                // will be filled below in extend ()
                // they expect $clientOrderId instead of client-$order-$id
                // $request['clientOrderId'] = $clientOrderId;
                $response = $this->spotPrivateGetV1OrderOrdersGetClientOrder ($this->extend($request, $params));
            } else {
                $request['order-id'] = $id;
                $response = $this->spotPrivateGetV1OrderOrdersOrderId ($this->extend($request, $params));
            }
        } else {
            if ($symbol === null) {
                throw new ArgumentsRequired($this->id . ' fetchOrder() requires a $symbol argument');
            }
            $clientOrderId = $this->safe_string_2($params, 'client_order_id', 'clientOrderId');
            if ($clientOrderId === null) {
                $request['order_id'] = $id;
            } else {
                $request['client_order_id'] = $clientOrderId;
                $params = $this->omit($params, array( 'client_order_id', 'clientOrderId' ));
            }
            $request['contract_code'] = $market['id'];
            if ($market['linear']) {
                $marginMode = null;
                list($marginMode, $params) = $this->handle_margin_mode_and_params('fetchOrder', $params);
                $marginMode = ($marginMode === null) ? 'cross' : $marginMode;
                if ($marginMode === 'isolated') {
                    $response = $this->contractPrivatePostLinearSwapApiV1SwapOrderInfo ($this->extend($request, $params));
                } elseif ($marginMode === 'cross') {
                    $response = $this->contractPrivatePostLinearSwapApiV1SwapCrossOrderInfo ($this->extend($request, $params));
                }
            } elseif ($market['inverse']) {
                if ($marketType === 'future') {
                    $request['symbol'] = $market['settleId'];
                    $response = $this->contractPrivatePostApiV1ContractOrderInfo ($this->extend($request, $params));
                } elseif ($marketType === 'swap') {
                    $response = $this->contractPrivatePostSwapApiV1SwapOrderInfo ($this->extend($request, $params));
                } else {
                    throw new NotSupported($this->id . ' fetchOrder() does not support ' . $marketType . ' markets');
                }
            }
        }
        //
        // spot
        //
        //     {
        //         "status":"ok",
        //         "data":{
        //             "id":438398393065481,
        //             "symbol":"ethusdt",
        //             "account-$id":1528640,
        //             "client-$order-$id":"AA03022abc2163433e-006b-480e-9ad1-d4781478c5e7",
        //             "amount":"0.100000000000000000",
        //             "price":"3000.000000000000000000",
        //             "created-at":1640549994642,
        //             "type":"buy-limit",
        //             "field-amount":"0.0",
        //             "field-cash-amount":"0.0",
        //             "field-fees":"0.0",
        //             "finished-at":0,
        //             "source":"spot-api",
        //             "state":"submitted",
        //             "canceled-at":0
        //         }
        //     }
        //
        // linear swap cross margin
        //
        //     {
        //         "status":"ok",
        //         "data":array(
        //             {
        //                 "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" => array(
        //                 array(
        //                     "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 = $this->safe_value($response, 'data');
        if (gettype($order) === 'array' && array_keys($order) === array_keys(array_keys($order))) {
            $order = $this->safe_value($order, 0);
        }
        return $this->parse_order($order);
    }

    public function parse_margin_balance_helper($balance, $code, $result) {
        $account = null;
        if (is_array($result) && array_key_exists($code, $result)) {
            $account = $result[$code];
        } else {
            $account = $this->account();
        }
        if ($balance['type'] === 'trade') {
            $account['free'] = $this->safe_string($balance, 'balance');
        }
        if ($balance['type'] === 'frozen') {
            $account['used'] = $this->safe_string($balance, 'balance');
        }
        return $account;
    }

    public function fetch_spot_orders_by_states($states, ?string $symbol = null, ?int $since = null, ?int $limit = null, $params = array ()) {
        $method = $this->safe_string($this->options, 'fetchOrdersByStatesMethod', 'spot_private_get_v1_order_orders'); // spot_private_get_v1_order_history
        if ($method === 'spot_private_get_v1_order_orders') {
            if ($symbol === null) {
                throw new ArgumentsRequired($this->id . ' fetchOrders() requires a $symbol argument');
            }
        }
        $this->load_markets();
        $market = null;
        $request = array(
            // 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' => $this->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' => $this->milliseconds(),
            // 'direct' => 'next', // next, prev, used with from
            // 'size' => 100, // max 100
        );
        if ($symbol !== null) {
            $market = $this->market($symbol);
            $request['symbol'] = $market['id'];
        }
        if ($since !== null) {
            $request['start-time'] = $since; // a window of 48 hours within 180 days
            $request['end-time'] = $this->sum($since, 48 * 60 * 60 * 1000);
        }
        list($request, $params) = $this->handle_until_option('end-time', $request, $params);
        if ($limit !== null) {
            $request['size'] = $limit;
        }
        $response = null;
        if ($method === 'spot_private_get_v1_order_orders') {
            $response = $this->spotPrivateGetV1OrderOrders ($this->extend($request, $params));
        } else {
            $response = $this->spotPrivateGetV1OrderHistory ($this->extend($request, $params));
        }
        //
        // spot_private_get_v1_order_orders GET /v1/order/orders
        //
        //     {
        //         "status" => "ok",
        //         "data" => array(
        //             {
        //                 "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 = $this->safe_list($response, 'data', array());
        return $this->parse_orders($data, $market, $since, $limit);
    }

    public function fetch_spot_orders(?string $symbol = null, ?int $since = null, ?int $limit = null, $params = array ()) {
        return $this->fetch_spot_orders_by_states('pre-submitted,submitted,partial-filled,filled,partial-canceled,canceled', $symbol, $since, $limit, $params);
    }

    public function fetch_closed_spot_orders(?string $symbol = null, ?int $since = null, ?int $limit = null, $params = array ()) {
        return $this->fetch_spot_orders_by_states('filled,partial-canceled,canceled', $symbol, $since, $limit, $params);
    }

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

    public function fetch_closed_contract_orders(?string $symbol = null, ?int $since = null, ?int $limit = null, $params = array ()) {
        $request = array(
            '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 $this->fetch_contract_orders($symbol, $since, $limit, $this->extend($request, $params));
    }

    public function fetch_orders(?string $symbol = null, ?int $since = null, ?int $limit = null, $params = array ()): array {
        /**
         *
         * @see https://huobiapi.github.io/docs/spot/v1/en/#search-past-orders
         * @see https://huobiapi.github.io/docs/spot/v1/en/#search-historical-orders-within-48-hours
         * @see https://huobiapi.github.io/docs/usdt_swap/v1/en/#isolated-get-history-orders-new
         * @see https://huobiapi.github.io/docs/usdt_swap/v1/en/#cross-get-history-orders-new
         * @see https://huobiapi.github.io/docs/coin_margined_swap/v1/en/#get-history-orders-new
         * @see https://huobiapi.github.io/docs/coin_margined_swap/v1/en/#query-history-orders-via-multiple-fields-new
         *
         * fetches information on multiple orders made by the user
         * @param {string} $symbol unified $market $symbol of the $market orders were made in
         * @param {int} [$since] the earliest time in ms to fetch orders for
         * @param {int} [$limit] the maximum number of order structures to retrieve
         * @param {array} [$params] extra parameters specific to the exchange API endpoint
         * @param {bool} [$params->trigger] *$contract only* if the orders are trigger trigger orders or not
         * @param {bool} [$params->stopLossTakeProfit] *$contract only* if the orders are stop-loss or take-profit orders
         * @param {int} [$params->until] the latest time in ms to fetch entries for
         * @param {boolean} [$params->trailing] *$contract only* set to true if you want to fetch trailing stop orders
         * @return {Order[]} a list of ~@link https://docs.ccxt.com/#/?id=order-structure order structures~
         */
        $this->load_markets();
        $market = null;
        if ($symbol !== null) {
            $market = $this->market($symbol);
        }
        $marketType = null;
        list($marketType, $params) = $this->handle_market_type_and_params('fetchOrders', $market, $params);
        $contract = ($marketType === 'swap') || ($marketType === 'future');
        if ($contract && ($symbol === null)) {
            throw new ArgumentsRequired($this->id . ' fetchOrders() requires a $symbol argument for ' . $marketType . ' orders');
        }
        if ($contract) {
            return $this->fetch_contract_orders($symbol, $since, $limit, $params);
        } else {
            return $this->fetch_spot_orders($symbol, $since, $limit, $params);
        }
    }

    public function fetch_closed_orders(?string $symbol = null, ?int $since = null, ?int $limit = null, $params = array ()): array {
        /**
         *
         * @see https://huobiapi.github.io/docs/spot/v1/en/#search-past-orders
         * @see https://huobiapi.github.io/docs/spot/v1/en/#search-historical-orders-within-48-hours
         * @see https://huobiapi.github.io/docs/usdt_swap/v1/en/#isolated-get-history-orders-new
         * @see https://huobiapi.github.io/docs/usdt_swap/v1/en/#cross-get-history-orders-new
         * @see https://huobiapi.github.io/docs/coin_margined_swap/v1/en/#get-history-orders-new
         * @see https://huobiapi.github.io/docs/coin_margined_swap/v1/en/#query-history-orders-via-multiple-fields-new
         *
         * fetches information on multiple closed orders made by the user
         * @param {string} $symbol unified $market $symbol of the $market orders were made in
         * @param {int} [$since] the earliest time in ms to fetch orders for
         * @param {int} [$limit] the maximum number of order structures to retrieve
         * @param {array} [$params] extra parameters specific to the exchange API endpoint
         * @param {int} [$params->until] the latest time in ms to fetch entries for
         * @param {boolean} [$params->paginate] default false, when true will automatically $paginate by calling this endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-$params)
         * @return {Order[]} a list of ~@link https://docs.ccxt.com/#/?id=order-structure order structures~
         */
        $this->load_markets();
        $paginate = false;
        list($paginate, $params) = $this->handle_option_and_params($params, 'fetchClosedOrders', 'paginate');
        if ($paginate) {
            return $this->fetch_paginated_call_dynamic('fetchClosedOrders', $symbol, $since, $limit, $params, 100);
        }
        $market = null;
        if ($symbol !== null) {
            $market = $this->market($symbol);
        }
        $marketType = null;
        list($marketType, $params) = $this->handle_market_type_and_params('fetchClosedOrders', $market, $params);
        if ($marketType === 'spot') {
            return $this->fetch_closed_spot_orders($symbol, $since, $limit, $params);
        } else {
            return $this->fetch_closed_contract_orders($symbol, $since, $limit, $params);
        }
    }

    public function fetch_open_orders(?string $symbol = null, ?int $since = null, ?int $limit = null, $params = array ()): array {
        /**
         *
         * @see https://huobiapi.github.io/docs/spot/v1/en/#get-all-open-$orders
         * @see https://huobiapi.github.io/docs/usdt_swap/v1/en/#isolated-current-unfilled-order-acquisition
         * @see https://huobiapi.github.io/docs/usdt_swap/v1/en/#cross-current-unfilled-order-acquisition
         *
         * fetch all unfilled currently open $orders
         * @param {string} $symbol unified $market $symbol
         * @param {int} [$since] the earliest time in ms to fetch open $orders for
         * @param {int} [$limit] the maximum number of open order structures to retrieve
         * @param {array} [$params] extra parameters specific to the exchange API endpoint
         * @param {bool} [$params->trigger] *contract only* if the $orders are $trigger trigger $orders or not
         * @param {bool} [$params->stopLossTakeProfit] *contract only* if the $orders are stop-loss or take-profit $orders
         * @param {boolean} [$params->trailing] *contract only* set to true if you want to fetch $trailing stop $orders
         * @return {Order[]} a list of ~@link https://docs.ccxt.com/#/?id=order-structure order structures~
         */
        $this->load_markets();
        $market = null;
        if ($symbol !== null) {
            $market = $this->market($symbol);
        }
        $request = array();
        $marketType = null;
        list($marketType, $params) = $this->handle_market_type_and_params('fetchOpenOrders', $market, $params);
        $subType = null;
        list($subType, $params) = $this->handle_sub_type_and_params('fetchOpenOrders', $market, $params, 'linear');
        $response = null;
        if ($marketType === 'spot') {
            if ($symbol !== null) {
                $request['symbol'] = $market['id'];
            }
            // todo replace with fetchAccountIdByType
            $accountId = $this->safe_string($params, 'account-id');
            if ($accountId === null) {
                // pick the first $account
                $this->load_accounts();
                for ($i = 0; $i < count($this->accounts); $i++) {
                    $account = $this->accounts[$i];
                    if ($this->safe_string($account, 'type') === 'spot') {
                        $accountId = $this->safe_string($account, 'id');
                        if ($accountId !== null) {
                            break;
                        }
                    }
                }
            }
            $request['account-id'] = $accountId;
            if ($limit !== null) {
                $request['size'] = $limit;
            }
            $params = $this->omit($params, 'account-id');
            $response = $this->spotPrivateGetV1OrderOpenOrders ($this->extend($request, $params));
        } else {
            if ($symbol !== null) {
                // throw new ArgumentsRequired($this->id . ' fetchOpenOrders() requires a $symbol argument');
                $request['contract_code'] = $market['id'];
            }
            if ($limit !== null) {
                $request['page_size'] = $limit;
            }
            $trigger = $this->safe_bool_2($params, 'stop', 'trigger');
            $stopLossTakeProfit = $this->safe_value($params, 'stopLossTakeProfit');
            $trailing = $this->safe_bool($params, 'trailing', false);
            $params = $this->omit($params, array( 'stop', 'stopLossTakeProfit', 'trailing', 'trigger' ));
            if ($subType === 'linear') {
                $marginMode = null;
                list($marginMode, $params) = $this->handle_margin_mode_and_params('fetchOpenOrders', $params);
                $marginMode = ($marginMode === null) ? 'cross' : $marginMode;
                if ($marginMode === 'isolated') {
                    if ($trigger) {
                        $response = $this->contractPrivatePostLinearSwapApiV1SwapTriggerOpenorders ($this->extend($request, $params));
                    } elseif ($stopLossTakeProfit) {
                        $response = $this->contractPrivatePostLinearSwapApiV1SwapTpslOpenorders ($this->extend($request, $params));
                    } elseif ($trailing) {
                        $response = $this->contractPrivatePostLinearSwapApiV1SwapTrackOpenorders ($this->extend($request, $params));
                    } else {
                        $response = $this->contractPrivatePostLinearSwapApiV1SwapOpenorders ($this->extend($request, $params));
                    }
                } elseif ($marginMode === 'cross') {
                    if ($trigger) {
                        $response = $this->contractPrivatePostLinearSwapApiV1SwapCrossTriggerOpenorders ($this->extend($request, $params));
                    } elseif ($stopLossTakeProfit) {
                        $response = $this->contractPrivatePostLinearSwapApiV1SwapCrossTpslOpenorders ($this->extend($request, $params));
                    } elseif ($trailing) {
                        $response = $this->contractPrivatePostLinearSwapApiV1SwapCrossTrackOpenorders ($this->extend($request, $params));
                    } else {
                        $response = $this->contractPrivatePostLinearSwapApiV1SwapCrossOpenorders ($this->extend($request, $params));
                    }
                }
            } elseif ($subType === 'inverse') {
                if ($marketType === 'swap') {
                    if ($trigger) {
                        $response = $this->contractPrivatePostSwapApiV1SwapTriggerOpenorders ($this->extend($request, $params));
                    } elseif ($stopLossTakeProfit) {
                        $response = $this->contractPrivatePostSwapApiV1SwapTpslOpenorders ($this->extend($request, $params));
                    } elseif ($trailing) {
                        $response = $this->contractPrivatePostSwapApiV1SwapTrackOpenorders ($this->extend($request, $params));
                    } else {
                        $response = $this->contractPrivatePostSwapApiV1SwapOpenorders ($this->extend($request, $params));
                    }
                } elseif ($marketType === 'future') {
                    $request['symbol'] = $this->safe_string($market, 'settleId', 'usdt');
                    if ($trigger) {
                        $response = $this->contractPrivatePostApiV1ContractTriggerOpenorders ($this->extend($request, $params));
                    } elseif ($stopLossTakeProfit) {
                        $response = $this->contractPrivatePostApiV1ContractTpslOpenorders ($this->extend($request, $params));
                    } elseif ($trailing) {
                        $response = $this->contractPrivatePostApiV1ContractTrackOpenorders ($this->extend($request, $params));
                    } else {
                        $response = $this->contractPrivatePostApiV1ContractOpenorders ($this->extend($request, $params));
                    }
                }
            }
        }
        //
        // spot
        //
        //     {
        //         "status":"ok",
        //         "data":array(
        //             {
        //                 "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" => array(
        //                 array(
        //                     "symbol" => "ADA",
        //                     "contract_code" => "ADA201225",
        //                     "contract_type" => "quarter",
        //                     "volume" => 1,
        //                     "price" => 0.0925,
        //                     "order_price_type" => "post_only",
        //                     "order_type" => 1,
        //                     "direction" => "buy",
        //                     "offset" => "close",
        //                     "lever_rate" => 20,
        //                     "order_id" => 773131315209248768,
        //                     "client_order_id" => null,
        //                     "created_at" => 1604370469629,
        //                     "trade_volume" => 0,
        //                     "trade_turnover" => 0,
        //                     "fee" => 0,
        //                     "trade_avg_price" => null,
        //                     "margin_frozen" => 0,
        //                     "profit" => 0,
        //                     "status" => 3,
        //                     "order_source" => "web",
        //                     "order_id_str" => "773131315209248768",
        //                     "fee_asset" => "ADA",
        //                     "liquidation_type" => null,
        //                     "canceled_at" => null,
        //                     "is_tpsl" => 0,
        //                     "update_time" => 1606975980467,
        //                     "real_profit" => 0
        //                 }
        //             ),
        //             "total_page" => 1,
        //             "current_page" => 1,
        //             "total_size" => 1
        //         ),
        //         "ts" => 1604370488518
        //     }
        //
        // $trigger
        //
        //     {
        //         "status" => "ok",
        //         "data" => {
        //             "orders" => array(
        //                 array(
        //                     "contract_type" => "swap",
        //                     "business_type" => "swap",
        //                     "pair" => "BTC-USDT",
        //                     "symbol" => "BTC",
        //                     "contract_code" => "BTC-USDT",
        //                     "trigger_type" => "le",
        //                     "volume" => 1.000000000000000000,
        //                     "order_type" => 1,
        //                     "direction" => "buy",
        //                     "offset" => "open",
        //                     "lever_rate" => 1,
        //                     "order_id" => 1103670703588327424,
        //                     "order_id_str" => "1103670703588327424",
        //                     "order_source" => "web",
        //                     "trigger_price" => 25000.000000000000000000,
        //                     "order_price" => 24000.000000000000000000,
        //                     "created_at" => 1683177200945,
        //                     "order_price_type" => "limit",
        //                     "status" => 2,
        //                     "margin_mode" => "cross",
        //                     "margin_account" => "USDT",
        //                     "trade_partition" => "USDT",
        //                     "reduce_only" => 0
        //                 }
        //             ),
        //             "total_page" => 1,
        //             "current_page" => 1,
        //             "total_size" => 1
        //         ),
        //         "ts" => 1683177805320
        //     }
        //
        // stop-loss and take-profit
        //
        //     {
        //         "status" => "ok",
        //         "data" => {
        //             "orders" => array(
        //                 array(
        //                     "contract_type" => "swap",
        //                     "business_type" => "swap",
        //                     "pair" => "BTC-USDT",
        //                     "symbol" => "BTC",
        //                     "contract_code" => "BTC-USDT",
        //                     "margin_mode" => "cross",
        //                     "margin_account" => "USDT",
        //                     "volume" => 1.000000000000000000,
        //                     "order_type" => 1,
        //                     "direction" => "sell",
        //                     "order_id" => 1103680386844839936,
        //                     "order_id_str" => "1103680386844839936",
        //                     "order_source" => "web",
        //                     "trigger_type" => "le",
        //                     "trigger_price" => 25000.000000000000000000,
        //                     "order_price" => 0E-18,
        //                     "created_at" => 1683179509613,
        //                     "order_price_type" => "market",
        //                     "status" => 2,
        //                     "tpsl_order_type" => "sl",
        //                     "source_order_id" => null,
        //                     "relation_tpsl_order_id" => "-1",
        //                     "trade_partition" => "USDT"
        //                 }
        //             ),
        //             "total_page" => 1,
        //             "current_page" => 1,
        //             "total_size" => 1
        //         ),
        //         "ts" => 1683179527011
        //     }
        //
        // $trailing
        //
        //     {
        //         "status" => "ok",
        //         "data" => array(
        //             "orders" => array(
        //                 array(
        //                     "contract_type" => "swap",
        //                     "business_type" => "swap",
        //                     "pair" => "BTC-USDT",
        //                     "symbol" => "BTC",
        //                     "contract_code" => "BTC-USDT",
        //                     "volume" => 1.000000000000000000,
        //                     "order_type" => 1,
        //                     "direction" => "sell",
        //                     "offset" => "close",
        //                     "lever_rate" => 1,
        //                     "order_id" => 1192021437253877761,
        //                     "order_id_str" => "1192021437253877761",
        //                     "order_source" => "api",
        //                     "created_at" => 1704241657328,
        //                     "order_price_type" => "formula_price",
        //                     "status" => 2,
        //                     "callback_rate" => 0.050000000000000000,
        //                     "active_price" => 50000.000000000000000000,
        //                     "is_active" => 0,
        //                     "margin_mode" => "cross",
        //                     "margin_account" => "USDT",
        //                     "trade_partition" => "USDT",
        //                     "reduce_only" => 1
        //                 ),
        //             ),
        //             "total_page" => 1,
        //             "current_page" => 1,
        //             "total_size" => 2
        //         ),
        //         "ts" => 1704242440106
        //     }
        //
        $orders = $this->safe_value($response, 'data');
        if (gettype($orders) !== 'array' || array_keys($orders) !== array_keys(array_keys($orders))) {
            $orders = $this->safe_value($orders, 'orders', array());
        }
        return $this->parse_orders($orders, $market, $since, $limit);
    }

    public function parse_order_status(?string $status) {
        $statuses = array(
            // 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 $this->safe_string($statuses, $status, $status);
    }

    public function parse_order(array $order, ?array $market = null): array {
        //
        // 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" => array(
        //             {
        //                 "trade_id" => 131560927,
        //                 "trade_price" => 13059.800000000000000000,
        //                 "trade_volume" => 1.000000000000000000,
        //                 "trade_turnover" => 13.059800000000000000,
        //                 "trade_fee" => -0.005223920000000000,
        //                 "created_at" => 1603703614715,
        //                 "role" => "taker",
        //                 "fee_asset" => "USDT",
        //                 "profit" => 0,
        //                 "real_profit" => 0,
        //                 "id" => "131560927-770334322963152896-1"
        //             }
        //         ),
        //         "total_page" => 1,
        //         "current_page" => 1,
        //         "total_size" => 1,
        //         "liquidation_type" => "0",
        //         "fee_asset" => "USDT",
        //         "fee" => -0.005223920000000000,
        //         "order_id" => 770334322963152896,
        //         "order_id_str" => "770334322963152896",
        //         "client_order_id" => 57012021045,
        //         "order_type" => "1",
        //         "status" => 6,
        //         "trade_avg_price" => 13059.800000000000000000,
        //         "trade_turnover" => 13.059800000000000000,
        //         "trade_volume" => 1.000000000000000000,
        //         "margin_asset" => "USDT",
        //         "margin_mode" => "isolated",
        //         "margin_account" => "BTC-USDT",
        //         "real_profit" => 0,
        //         "is_tpsl" => 0
        //     }
        //
        // future and swap => fetchOrders
        //
        //     {
        //         "order_id" => 773131315209248768,
        //         "contract_code" => "ADA201225",
        //         "symbol" => "ADA",
        //         "lever_rate" => 20,
        //         "direction" => "buy",
        //         "offset" => "close",
        //         "volume" => 1,
        //         "price" => 0.0925,
        //         "create_date" => 1604370469629,
        //         "update_time" => 1603704221118,
        //         "order_source" => "web",
        //         "order_price_type" => 6,
        //         "order_type" => 1,
        //         "margin_frozen" => 0,
        //         "profit" => 0,
        //         "contract_type" => "quarter",
        //         "trade_volume" => 0,
        //         "trade_turnover" => 0,
        //         "fee" => 0,
        //         "trade_avg_price" => 0,
        //         "status" => 3,
        //         "order_id_str" => "773131315209248768",
        //         "fee_asset" => "ADA",
        //         "liquidation_type" => "0",
        //         "is_tpsl" => 0,
        //         "real_profit" => 0
        //         "margin_asset" => "USDT",
        //         "margin_mode" => "cross",
        //         "margin_account" => "USDT",
        //         "trade_partition" => "USDT", // only in isolated & cross of linear
        //         "reduce_only" => "1", // only in isolated & cross of linear
        //         "contract_type" => "quarter", // only in cross-margin (inverse & linear)
        //         "pair" => "BTC-USDT", // only in cross-margin (inverse & linear)
        //         "business_type" => "futures" // only in cross-margin (inverse & linear)
        //     }
        //
        // trigger => fetchOpenOrders
        //
        //     {
        //         "contract_type" => "swap",
        //         "business_type" => "swap",
        //         "pair" => "BTC-USDT",
        //         "symbol" => "BTC",
        //         "contract_code" => "BTC-USDT",
        //         "trigger_type" => "le",
        //         "volume" => 1.000000000000000000,
        //         "order_type" => 1,
        //         "direction" => "buy",
        //         "offset" => "open",
        //         "lever_rate" => 1,
        //         "order_id" => 1103670703588327424,
        //         "order_id_str" => "1103670703588327424",
        //         "order_source" => "web",
        //         "trigger_price" => 25000.000000000000000000,
        //         "order_price" => 24000.000000000000000000,
        //         "created_at" => 1683177200945,
        //         "order_price_type" => "limit",
        //         "status" => 2,
        //         "margin_mode" => "cross",
        //         "margin_account" => "USDT",
        //         "trade_partition" => "USDT",
        //         "reduce_only" => 0
        //     }
        //
        // stop-loss and take-profit => fetchOpenOrders
        //
        //     {
        //         "contract_type" => "swap",
        //         "business_type" => "swap",
        //         "pair" => "BTC-USDT",
        //         "symbol" => "BTC",
        //         "contract_code" => "BTC-USDT",
        //         "margin_mode" => "cross",
        //         "margin_account" => "USDT",
        //         "volume" => 1.000000000000000000,
        //         "order_type" => 1,
        //         "direction" => "sell",
        //         "order_id" => 1103680386844839936,
        //         "order_id_str" => "1103680386844839936",
        //         "order_source" => "web",
        //         "trigger_type" => "le",
        //         "trigger_price" => 25000.000000000000000000,
        //         "order_price" => 0E-18,
        //         "created_at" => 1683179509613,
        //         "order_price_type" => "market",
        //         "status" => 2,
        //         "tpsl_order_type" => "sl",
        //         "source_order_id" => null,
        //         "relation_tpsl_order_id" => "-1",
        //         "trade_partition" => "USDT"
        //     }
        //
        // trailing => fetchOpenOrders
        //
        //     {
        //         "contract_type" => "swap",
        //         "business_type" => "swap",
        //         "pair" => "BTC-USDT",
        //         "symbol" => "BTC",
        //         "contract_code" => "BTC-USDT",
        //         "volume" => 1.000000000000000000,
        //         "order_type" => 1,
        //         "direction" => "sell",
        //         "offset" => "close",
        //         "lever_rate" => 1,
        //         "order_id" => 1192021437253877761,
        //         "order_id_str" => "1192021437253877761",
        //         "order_source" => "api",
        //         "created_at" => 1704241657328,
        //         "order_price_type" => "formula_price",
        //         "status" => 2,
        //         "callback_rate" => 0.050000000000000000,
        //         "active_price" => 50000.000000000000000000,
        //         "is_active" => 0,
        //         "margin_mode" => "cross",
        //         "margin_account" => "USDT",
        //         "trade_partition" => "USDT",
        //         "reduce_only" => 1
        //     }
        //
        // trigger => fetchOrders
        //
        //     {
        //         "contract_type" => "swap",
        //         "business_type" => "swap",
        //         "pair" => "BTC-USDT",
        //         "symbol" => "BTC",
        //         "contract_code" => "BTC-USDT",
        //         "trigger_type" => "le",
        //         "volume" => 1.000000000000000000,
        //         "order_type" => 1,
        //         "direction" => "buy",
        //         "offset" => "open",
        //         "lever_rate" => 1,
        //         "order_id" => 1103670703588327424,
        //         "order_id_str" => "1103670703588327424",
        //         "relation_order_id" => "-1",
        //         "order_price_type" => "limit",
        //         "status" => 6,
        //         "order_source" => "web",
        //         "trigger_price" => 25000.000000000000000000,
        //         "triggered_price" => null,
        //         "order_price" => 24000.000000000000000000,
        //         "created_at" => 1683177200945,
        //         "triggered_at" => null,
        //         "order_insert_at" => 0,
        //         "canceled_at" => 1683179075234,
        //         "fail_code" => null,
        //         "fail_reason" => null,
        //         "margin_mode" => "cross",
        //         "margin_account" => "USDT",
        //         "update_time" => 1683179075958,
        //         "trade_partition" => "USDT",
        //         "reduce_only" => 0
        //     }
        //
        // stop-loss and take-profit => fetchOrders
        //
        //     {
        //         "contract_type" => "swap",
        //         "business_type" => "swap",
        //         "pair" => "BTC-USDT",
        //         "symbol" => "BTC",
        //         "contract_code" => "BTC-USDT",
        //         "margin_mode" => "cross",
        //         "margin_account" => "USDT",
        //         "volume" => 1.000000000000000000,
        //         "order_type" => 1,
        //         "tpsl_order_type" => "sl",
        //         "direction" => "sell",
        //         "order_id" => 1103680386844839936,
        //         "order_id_str" => "1103680386844839936",
        //         "order_source" => "web",
        //         "trigger_type" => "le",
        //         "trigger_price" => 25000.000000000000000000,
        //         "created_at" => 1683179509613,
        //         "order_price_type" => "market",
        //         "status" => 11,
        //         "source_order_id" => null,
        //         "relation_tpsl_order_id" => "-1",
        //         "canceled_at" => 0,
        //         "fail_code" => null,
        //         "fail_reason" => null,
        //         "triggered_price" => null,
        //         "relation_order_id" => "-1",
        //         "update_time" => 1683179968231,
        //         "order_price" => 0E-18,
        //         "trade_partition" => "USDT"
        //     }
        //
        // spot => createOrders
        //
        //     array(
        //         array(
        //             "order-$id" => 936847569789079,
        //             "client-$order-$id" => "AA03022abc3a55e82c-0087-4fc2-beac-112fdebb1ee9"
        //         ),
        //         {
        //             "client-$order-$id" => "AA03022abcdb3baefb-3cfa-4891-8009-082b3d46ca82",
        //             "err-code" => "account-frozen-balance-insufficient-error",
        //             "err-msg" => "trade account balance is not enough, left => `89`"
        //         }
        //     )
        //
        // swap and future => createOrders
        //
        //     array(
        //         array(
        //             "index" => 2,
        //             "err_code" => 1047,
        //             "err_msg" => "Insufficient margin available."
        //         ),
        //         {
        //             "order_id" => 1172923090632953857,
        //             "index" => 1,
        //             "order_id_str" => "1172923090632953857"
        //         }
        //     )
        //
        $rejectedCreateOrders = $this->safe_string_2($order, 'err_code', 'err-code');
        $status = $this->parse_order_status($this->safe_string_2($order, 'state', 'status'));
        if ($rejectedCreateOrders !== null) {
            $status = 'rejected';
        }
        $id = $this->safe_string_n($order, array( 'id', 'order_id_str', 'order-id' ));
        $side = $this->safe_string($order, 'direction');
        $type = $this->safe_string($order, 'order_price_type');
        if (is_array($order) && array_key_exists('type', $order)) {
            $orderType = explode('-', $order['type']);
            $side = $orderType[0];
            $type = $orderType[1];
        }
        $marketId = $this->safe_string_2($order, 'contract_code', 'symbol');
        $market = $this->safe_market($marketId, $market);
        $timestamp = $this->safe_integer_n($order, array( 'created_at', 'created-at', 'create_date' ));
        $clientOrderId = $this->safe_string_2($order, 'client_order_id', 'client-or' . 'der-id'); // transpiler regex trick for php issue
        $cost = null;
        $amount = null;
        if (($type !== null) && (mb_strpos($type, 'market') !== false)) {
            $cost = $this->safe_string($order, 'field-cash-amount');
        } else {
            $amount = $this->safe_string_2($order, 'volume', 'amount');
            $cost = $this->safe_string_n($order, array( 'filled-cash-amount', 'field-cash-amount', 'trade_turnover' )); // same typo here
        }
        $filled = $this->safe_string_n($order, array( 'filled-amount', 'field-amount', 'trade_volume' )); // typo in their API, $filled $amount
        $price = $this->safe_string_2($order, 'price', 'order_price');
        $feeCost = $this->safe_string_2($order, 'filled-fees', 'field-fees'); // typo in their API, $filled feeSide
        $feeCost = $this->safe_string($order, 'fee', $feeCost);
        $fee = null;
        if ($feeCost !== null) {
            $feeCurrency = null;
            $feeCurrencyId = $this->safe_string($order, 'fee_asset');
            if ($feeCurrencyId !== null) {
                $feeCurrency = $this->safe_currency_code($feeCurrencyId);
            } else {
                $feeCurrency = ($side === 'sell') ? $market['quote'] : $market['base'];
            }
            $fee = array(
                'cost' => $feeCost,
                'currency' => $feeCurrency,
            );
        }
        $average = $this->safe_string($order, 'trade_avg_price');
        $trades = $this->safe_value($order, 'trades');
        $reduceOnlyInteger = $this->safe_integer($order, 'reduce_only');
        $reduceOnly = null;
        if ($reduceOnlyInteger !== null) {
            $reduceOnly = ($reduceOnlyInteger === 0) ? false : true;
        }
        return $this->safe_order(array(
            'info' => $order,
            'id' => $id,
            'clientOrderId' => $clientOrderId,
            'timestamp' => $timestamp,
            'datetime' => $this->iso8601($timestamp),
            'lastTradeTimestamp' => null,
            'symbol' => $market['symbol'],
            'type' => $type,
            'timeInForce' => null,
            'postOnly' => null,
            'side' => $side,
            'price' => $price,
            'triggerPrice' => $this->safe_string_2($order, 'stop-price', 'trigger_price'),
            'average' => $average,
            'cost' => $cost,
            'amount' => $amount,
            'filled' => $filled,
            'remaining' => null,
            'status' => $status,
            'reduceOnly' => $reduceOnly,
            'fee' => $fee,
            'trades' => $trades,
        ), $market);
    }

    public function create_market_buy_order_with_cost(string $symbol, float $cost, $params = array ()) {
        /**
         * create a $market buy order by providing the $symbol and $cost
         *
         * @see https://www.htx.com/en-us/opend/newApiPages/?id=7ec4ee16-7773-11ed-9966-0242ac110003
         *
         * @param {string} $symbol unified $symbol of the $market to create an order in
         * @param {float} $cost how much you want to trade in units of the quote currency
         * @param {array} [$params] extra parameters specific to the exchange API endpoint
         * @return {array} an ~@link https://docs.ccxt.com/#/?id=order-structure order structure~
         */
        $this->load_markets();
        $market = $this->market($symbol);
        if (!$market['spot']) {
            throw new NotSupported($this->id . ' createMarketBuyOrderWithCost() supports spot orders only');
        }
        $params['createMarketBuyOrderRequiresPrice'] = false;
        return $this->create_order($symbol, 'market', 'buy', $cost, null, $params);
    }

    public function create_trailing_percent_order(string $symbol, string $type, string $side, float $amount, ?float $price = null, ?float $trailingPercent = null, ?float $trailingTriggerPrice = null, $params = array ()): array {
        /**
         * create a trailing order by providing the $symbol, $type, $side, $amount, $price and $trailingPercent
         * @param {string} $symbol unified $symbol of the market to create an order in
         * @param {string} $type 'market' or 'limit'
         * @param {string} $side 'buy' or 'sell'
         * @param {float} $amount how much you want to trade in units of the base currency, or number of contracts
         * @param {float} [$price] the $price for the order to be filled at, in units of the quote currency, ignored in market orders
         * @param {float} $trailingPercent the percent to trail away from the current market $price
         * @param {float} $trailingTriggerPrice the $price to activate a trailing order, default uses the $price argument
         * @param {array} [$params] extra parameters specific to the exchange API endpoint
         * @return {array} an ~@link https://docs.ccxt.com/#/?id=order-structure order structure~
         */
        if ($trailingPercent === null) {
            throw new ArgumentsRequired($this->id . ' createTrailingPercentOrder() requires a $trailingPercent argument');
        }
        if ($trailingTriggerPrice === null) {
            throw new ArgumentsRequired($this->id . ' createTrailingPercentOrder() requires a $trailingTriggerPrice argument');
        }
        $params['trailingPercent'] = $trailingPercent;
        $params['trailingTriggerPrice'] = $trailingTriggerPrice;
        return $this->create_order($symbol, $type, $side, $amount, $price, $params);
    }

    public function create_spot_order_request(string $symbol, string $type, string $side, float $amount, ?float $price = null, $params = array ()) {
        /**
         * @ignore
         * helper function to build $request
         * @param {string} $symbol unified $symbol of the $market to create an order in
         * @param {string} $type 'market' or 'limit'
         * @param {string} $side 'buy' or 'sell'
         * @param {float} $amount how much you want to trade in units of the base currency
         * @param {float} [$price] the $price at which the order is to be fulfilled, in units of the quote currency, ignored in $market orders
         * @param {array} [$params] extra parameters specific to the exchange API endpoint
         * @param {string} [$params->timeInForce] supports 'IOC' and 'FOK'
         * @param {float} [$params->cost] the quote quantity that can be used alternative for the $amount for $market buy orders
         * @return {array} $request to be sent to the exchange
         */
        $this->load_markets();
        $this->load_accounts();
        $market = $this->market($symbol);
        $marginMode = null;
        list($marginMode, $params) = $this->handle_margin_mode_and_params('createOrder', $params);
        $accountId = $this->fetch_account_id_by_type($market['type'], $marginMode, $symbol);
        $request = array(
            // 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' => $this->amount_to_precision($symbol, $amount), // for buy $market orders it's the order $cost
            // 'price' => $this->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' => $this->price_to_precision($symbol, stopPrice), // trigger $price for stop limit orders
            // 'operator' => 'gte', // gte, lte, trigger $price condition
        );
        $orderType = str_replace('buy-', '', $type);
        $orderType = str_replace('sell-', '', $orderType);
        $options = $this->safe_value($this->options, $market['type'], array());
        $triggerPrice = $this->safe_string_n($params, array( 'triggerPrice', 'stopPrice', 'stop-price' ));
        if ($triggerPrice === null) {
            $stopOrderTypes = $this->safe_value($options, 'stopOrderTypes', array());
            if (is_array($stopOrderTypes) && array_key_exists($orderType, $stopOrderTypes)) {
                throw new ArgumentsRequired($this->id . ' createOrder() requires a $triggerPrice for a trigger order');
            }
        } else {
            $defaultOperator = ($side === 'sell') ? 'lte' : 'gte';
            $stopOperator = $this->safe_string($params, 'operator', $defaultOperator);
            $request['stop-price'] = $this->price_to_precision($symbol, $triggerPrice);
            $request['operator'] = $stopOperator;
            if (($orderType === 'limit') || ($orderType === 'limit-fok')) {
                $orderType = 'stop-' . $orderType;
            } elseif (($orderType !== 'stop-limit') && ($orderType !== 'stop-limit-fok')) {
                throw new NotSupported($this->id . ' createOrder() does not support ' . $type . ' orders');
            }
        }
        $postOnly = null;
        list($postOnly, $params) = $this->handle_post_only($orderType === 'market', $orderType === 'limit-maker', $params);
        if ($postOnly) {
            $orderType = 'limit-maker';
        }
        $timeInForce = $this->safe_string($params, 'timeInForce', 'GTC');
        if ($timeInForce === 'FOK') {
            $orderType = $orderType . '-fok';
        } elseif ($timeInForce === 'IOC') {
            $orderType = 'ioc';
        }
        $request['type'] = $side . '-' . $orderType;
        $clientOrderId = $this->safe_string_2($params, 'clientOrderId', 'client-order-id'); // must be 64 chars max and unique within 24 hours
        if ($clientOrderId === null) {
            $broker = $this->safe_value($this->options, 'broker', array());
            $brokerId = $this->safe_string($broker, 'id');
            $request['client-order-id'] = $brokerId . $this->uuid();
        } else {
            $request['client-order-id'] = $clientOrderId;
        }
        if ($marginMode === 'cross') {
            $request['source'] = 'super-margin-api';
        } elseif ($marginMode === 'isolated') {
            $request['source'] = 'margin-api';
        } elseif ($marginMode === 'c2c') {
            $request['source'] = 'c2c-margin-api';
        }
        if (($orderType === 'market') && ($side === 'buy')) {
            $quoteAmount = null;
            $createMarketBuyOrderRequiresPrice = true;
            list($createMarketBuyOrderRequiresPrice, $params) = $this->handle_option_and_params($params, 'createOrder', 'createMarketBuyOrderRequiresPrice', true);
            $cost = $this->safe_number($params, 'cost');
            $params = $this->omit($params, 'cost');
            if ($cost !== null) {
                $quoteAmount = $this->amount_to_precision($symbol, $cost);
            } elseif ($createMarketBuyOrderRequiresPrice) {
                if ($price === null) {
                    throw new InvalidOrder($this->id . ' createOrder() requires the $price argument for $market buy orders to calculate the total $cost to spend ($amount * $price), alternatively set the $createMarketBuyOrderRequiresPrice option or param to false and pass the $cost to spend in the $amount argument');
                } else {
                    // 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 = $this->number_to_string($amount);
                    $priceString = $this->number_to_string($price);
                    $quoteAmount = $this->amount_to_precision($symbol, Precise::string_mul($amountString, $priceString));
                }
            } else {
                $quoteAmount = $this->amount_to_precision($symbol, $amount);
            }
            $request['amount'] = $quoteAmount;
        } else {
            $request['amount'] = $this->amount_to_precision($symbol, $amount);
        }
        $limitOrderTypes = $this->safe_value($options, 'limitOrderTypes', array());
        if (is_array($limitOrderTypes) && array_key_exists($orderType, $limitOrderTypes)) {
            $request['price'] = $this->price_to_precision($symbol, $price);
        }
        $params = $this->omit($params, array( 'triggerPrice', 'stopPrice', 'stop-price', 'clientOrderId', 'client-order-id', 'operator', 'timeInForce' ));
        return $this->extend($request, $params);
    }

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

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

    public function create_orders(array $orders, $params = array ()) {
        /**
         * create a list of trade $orders
         *
         * @see https://huobiapi.github.io/docs/spot/v1/en/#place-a-batch-of-$orders
         * @see https://huobiapi.github.io/docs/dm/v1/en/#place-a-batch-of-$orders
         * @see https://huobiapi.github.io/docs/coin_margined_swap/v1/en/#place-a-batch-of-$orders
         * @see https://huobiapi.github.io/docs/usdt_swap/v1/en/#isolated-place-a-batch-of-$orders
         * @see https://huobiapi.github.io/docs/usdt_swap/v1/en/#cross-place-a-batch-of-$orders
         *
         * @param {Array} $orders list of $orders to create, each object should contain the parameters required by createOrder, namely $symbol, $type, $side, $amount, $price and $params
         * @param {array} [$params] extra parameters specific to the exchange API endpoint
         * @return {array} an ~@link https://docs.ccxt.com/#/?id=order-structure order structure~
         */
        $this->load_markets();
        $ordersRequests = array();
        $symbol = null;
        $market = null;
        $marginMode = null;
        for ($i = 0; $i < count($orders); $i++) {
            $rawOrder = $orders[$i];
            $marketId = $this->safe_string($rawOrder, 'symbol');
            if ($symbol === null) {
                $symbol = $marketId;
            } else {
                if ($symbol !== $marketId) {
                    throw new BadRequest($this->id . ' createOrders() requires all $orders to have the same symbol');
                }
            }
            $type = $this->safe_string($rawOrder, 'type');
            $side = $this->safe_string($rawOrder, 'side');
            $amount = $this->safe_value($rawOrder, 'amount');
            $price = $this->safe_value($rawOrder, 'price');
            $orderParams = $this->safe_value($rawOrder, 'params', array());
            $marginResult = $this->handle_margin_mode_and_params('createOrders', $orderParams);
            $currentMarginMode = $marginResult[0];
            if ($currentMarginMode !== null) {
                if ($marginMode === null) {
                    $marginMode = $currentMarginMode;
                } else {
                    if ($marginMode !== $currentMarginMode) {
                        throw new BadRequest($this->id . ' createOrders() requires all $orders to have the same margin mode (isolated or cross)');
                    }
                }
            }
            $market = $this->market($symbol);
            $orderRequest = null;
            if ($market['spot']) {
                $orderRequest = $this->create_spot_order_request($marketId, $type, $side, $amount, $price, $orderParams);
            } else {
                $orderRequest = $this->create_contract_order_request($marketId, $type, $side, $amount, $price, $orderParams);
            }
            $orderRequest = $this->omit($orderRequest, 'marginMode');
            $ordersRequests[] = $orderRequest;
        }
        $request = array();
        $response = null;
        if ($market['spot']) {
            $response = $this->privatePostOrderBatchOrders ($ordersRequests);
        } else {
            $request['orders_data'] = $ordersRequests;
            if ($market['linear']) {
                $marginMode = ($marginMode === null) ? 'cross' : $marginMode;
                if ($marginMode === 'isolated') {
                    $response = $this->contractPrivatePostLinearSwapApiV1SwapBatchorder ($request);
                } elseif ($marginMode === 'cross') {
                    $response = $this->contractPrivatePostLinearSwapApiV1SwapCrossBatchorder ($request);
                }
            } elseif ($market['inverse']) {
                if ($market['swap']) {
                    $response = $this->contractPrivatePostSwapApiV1SwapBatchorder ($request);
                } elseif ($market['future']) {
                    $response = $this->contractPrivatePostApiV1ContractBatchorder ($request);
                }
            }
        }
        //
        // spot
        //
        //     {
        //         "status" => "ok",
        //         "data" => array(
        //             array(
        //                 "order-id" => 936847569789079,
        //                 "client-order-id" => "AA03022abc3a55e82c-0087-4fc2-beac-112fdebb1ee9"
        //             ),
        //             {
        //                 "client-order-id" => "AA03022abcdb3baefb-3cfa-4891-8009-082b3d46ca82",
        //                 "err-code" => "account-frozen-balance-insufficient-error",
        //                 "err-msg" => "trade account balance is not enough, left => `89`"
        //             }
        //         )
        //     }
        //
        // swap and future
        //
        //     {
        //         "status" => "ok",
        //         "data" => {
        //             "errors" => array(
        //                 {
        //                     "index" => 2,
        //                     "err_code" => 1047,
        //                     "err_msg" => "Insufficient margin available."
        //                 }
        //             ),
        //             "success" => array(
        //                 array(
        //                     "order_id" => 1172923090632953857,
        //                     "index" => 1,
        //                     "order_id_str" => "1172923090632953857"
        //                 }
        //             )
        //         ),
        //         "ts" => 1699688256671
        //     }
        //
        $result = null;
        if ($market['spot']) {
            $result = $this->safe_value($response, 'data', array());
        } else {
            $data = $this->safe_value($response, 'data', array());
            $success = $this->safe_value($data, 'success', array());
            $errors = $this->safe_value($data, 'errors', array());
            $result = $this->array_concat($success, $errors);
        }
        return $this->parse_orders($result, $market);
    }

    public function cancel_order(string $id, ?string $symbol = null, $params = array ()) {
        /**
         * cancels an open order
         * @param {string} $id order $id
         * @param {string} $symbol unified $symbol of the $market the order was made in
         * @param {array} [$params] extra parameters specific to the exchange API endpoint
         * @param {boolean} [$params->trigger] *contract only* if the order is a $trigger trigger order or not
         * @param {boolean} [$params->stopLossTakeProfit] *contract only* if the order is a stop-loss or take-profit order
         * @param {boolean} [$params->trailing] *contract only* set to true if you want to cancel a $trailing order
         * @return {array} An ~@link https://docs.ccxt.com/#/?$id=order-structure order structure~
         */
        $this->load_markets();
        $market = null;
        if ($symbol !== null) {
            $market = $this->market($symbol);
        }
        $marketType = null;
        list($marketType, $params) = $this->handle_market_type_and_params('cancelOrder', $market, $params);
        $request = array(
            // 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, this_week, next_week, quarter, next_ quarter
        );
        $response = null;
        if ($marketType === 'spot') {
            $clientOrderId = $this->safe_string_2($params, 'client-order-id', 'clientOrderId');
            if ($clientOrderId === null) {
                $request['order-id'] = $id;
                $response = $this->spotPrivatePostV1OrderOrdersOrderIdSubmitcancel ($this->extend($request, $params));
            } else {
                $request['client-order-id'] = $clientOrderId;
                $params = $this->omit($params, array( 'client-order-id', 'clientOrderId' ));
                $response = $this->spotPrivatePostV1OrderOrdersSubmitCancelClientOrder ($this->extend($request, $params));
            }
        } else {
            if ($symbol === null) {
                throw new ArgumentsRequired($this->id . ' cancelOrder() requires a $symbol argument');
            }
            $clientOrderId = $this->safe_string_2($params, 'client_order_id', 'clientOrderId');
            if ($clientOrderId === null) {
                $request['order_id'] = $id;
            } else {
                $request['client_order_id'] = $clientOrderId;
                $params = $this->omit($params, array( 'client_order_id', 'clientOrderId' ));
            }
            if ($market['future']) {
                $request['symbol'] = $market['settleId'];
            } else {
                $request['contract_code'] = $market['id'];
            }
            $trigger = $this->safe_bool_2($params, 'stop', 'trigger');
            $stopLossTakeProfit = $this->safe_value($params, 'stopLossTakeProfit');
            $trailing = $this->safe_bool($params, 'trailing', false);
            $params = $this->omit($params, array( 'stop', 'stopLossTakeProfit', 'trailing', 'trigger' ));
            if ($market['linear']) {
                $marginMode = null;
                list($marginMode, $params) = $this->handle_margin_mode_and_params('cancelOrder', $params);
                $marginMode = ($marginMode === null) ? 'cross' : $marginMode;
                if ($marginMode === 'isolated') {
                    if ($trigger) {
                        $response = $this->contractPrivatePostLinearSwapApiV1SwapTriggerCancel ($this->extend($request, $params));
                    } elseif ($stopLossTakeProfit) {
                        $response = $this->contractPrivatePostLinearSwapApiV1SwapTpslCancel ($this->extend($request, $params));
                    } elseif ($trailing) {
                        $response = $this->contractPrivatePostLinearSwapApiV1SwapTrackCancel ($this->extend($request, $params));
                    } else {
                        $response = $this->contractPrivatePostLinearSwapApiV1SwapCancel ($this->extend($request, $params));
                    }
                } elseif ($marginMode === 'cross') {
                    if ($trigger) {
                        $response = $this->contractPrivatePostLinearSwapApiV1SwapCrossTriggerCancel ($this->extend($request, $params));
                    } elseif ($stopLossTakeProfit) {
                        $response = $this->contractPrivatePostLinearSwapApiV1SwapCrossTpslCancel ($this->extend($request, $params));
                    } elseif ($trailing) {
                        $response = $this->contractPrivatePostLinearSwapApiV1SwapCrossTrackCancel ($this->extend($request, $params));
                    } else {
                        $response = $this->contractPrivatePostLinearSwapApiV1SwapCrossCancel ($this->extend($request, $params));
                    }
                }
            } elseif ($market['inverse']) {
                if ($market['swap']) {
                    if ($trigger) {
                        $response = $this->contractPrivatePostSwapApiV1SwapTriggerCancel ($this->extend($request, $params));
                    } elseif ($stopLossTakeProfit) {
                        $response = $this->contractPrivatePostSwapApiV1SwapTpslCancel ($this->extend($request, $params));
                    } elseif ($trailing) {
                        $response = $this->contractPrivatePostSwapApiV1SwapTrackCancel ($this->extend($request, $params));
                    } else {
                        $response = $this->contractPrivatePostSwapApiV1SwapCancel ($this->extend($request, $params));
                    }
                } elseif ($market['future']) {
                    if ($trigger) {
                        $response = $this->contractPrivatePostApiV1ContractTriggerCancel ($this->extend($request, $params));
                    } elseif ($stopLossTakeProfit) {
                        $response = $this->contractPrivatePostApiV1ContractTpslCancel ($this->extend($request, $params));
                    } elseif ($trailing) {
                        $response = $this->contractPrivatePostApiV1ContractTrackCancel ($this->extend($request, $params));
                    } else {
                        $response = $this->contractPrivatePostApiV1ContractCancel ($this->extend($request, $params));
                    }
                }
            } else {
                throw new NotSupported($this->id . ' cancelOrder() does not support ' . $marketType . ' markets');
            }
        }
        //
        // spot
        //
        //     {
        //         "status" => "ok",
        //         "data" => "10138899000",
        //     }
        //
        // future and swap
        //
        //     {
        //         "status" => "ok",
        //         "data" => array(
        //             "errors" => array(),
        //             "successes" => "924660854912552960"
        //         ),
        //         "ts" => 1640504486089
        //     }
        //
        return $this->extend($this->parse_order($response, $market), array(
            'id' => $id,
            'status' => 'canceled',
        ));
    }

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

    public function parse_cancel_orders($orders) {
        //
        //    {
        //        "success" => array(
        //            "5983466"
        //        ),
        //        "failed" => array(
        //            array(
        //                "err-msg" => "Incorrect $order state",
        //                "order-state" => 7,
        //                "order-id" => "",
        //                "err-code" => "order-orderstate-error",
        //                "client-$order-id" => "first"
        //            ),
        //            ...
        //        )
        //    }
        //
        //    {
        //        "errors" => array(
        //            {
        //                "order_id" => "769206471845261312",
        //                "err_code" => 1061,
        //                "err_msg" => "This $order doesnt exist."
        //            }
        //        ),
        //        "successes" => "1258075374411399168,1258075393254871040"
        //    }
        //
        $successes = $this->safe_string($orders, 'successes');
        $success = null;
        if ($successes !== null) {
            $success = explode(',', $successes);
        } else {
            $success = $this->safe_list($orders, 'success', array());
        }
        $failed = $this->safe_list_2($orders, 'errors', 'failed', array());
        $result = array();
        for ($i = 0; $i < count($success); $i++) {
            $order = $success[$i];
            $result[] = $this->safe_order(array(
                'info' => $order,
                'id' => $order,
                'status' => 'canceled',
            ));
        }
        for ($i = 0; $i < count($failed); $i++) {
            $order = $failed[$i];
            $result[] = $this->safe_order(array(
                'info' => $order,
                'id' => $this->safe_string_2($order, 'order-id', 'order_id'),
                'status' => 'failed',
                'clientOrderId' => $this->safe_string($order, 'client-$order-id'),
            ));
        }
        return $result;
    }

    public function cancel_all_orders(?string $symbol = null, $params = array ()) {
        /**
         * cancel all open orders
         * @param {string} $symbol unified $market $symbol, only orders in the $market of this $symbol are cancelled when $symbol is not null
         * @param {array} [$params] extra parameters specific to the exchange API endpoint
         * @param {boolean} [$params->trigger] *contract only* if the orders are $trigger trigger orders or not
         * @param {boolean} [$params->stopLossTakeProfit] *contract only* if the orders are stop-loss or take-profit orders
         * @param {boolean} [$params->trailing] *contract only* set to true if you want to cancel all $trailing orders
         * @return {array[]} a list of ~@link https://docs.ccxt.com/#/?id=order-structure order structures~
         */
        $this->load_markets();
        $market = null;
        if ($symbol !== null) {
            $market = $this->market($symbol);
        }
        $marketType = null;
        list($marketType, $params) = $this->handle_market_type_and_params('cancelAllOrders', $market, $params);
        $request = array(
            // 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, this_week, next_week, quarter, next_ quarter
            // 'direction' => 'buy' => // buy, sell
            // 'offset' => 'open', // open, close
        );
        $response = null;
        if ($marketType === 'spot') {
            if ($symbol !== null) {
                $request['symbol'] = $market['id'];
            }
            $response = $this->spotPrivatePostV1OrderOrdersBatchCancelOpenOrders ($this->extend($request, $params));
            //
            //     {
            //         "code" => 200,
            //         "data" => {
            //             "success-count" => 2,
            //             "failed-count" => 0,
            //             "next-id" => 5454600
            //         }
            //     }
            //
            $data = $this->safe_dict($response, 'data');
            return array(
                $this->safe_order(array(
                    'info' => $data,
                )),
            );
        } else {
            if ($symbol === null) {
                throw new ArgumentsRequired($this->id . ' cancelAllOrders() requires a $symbol argument');
            }
            if ($market['future']) {
                $request['symbol'] = $market['settleId'];
            }
            $request['contract_code'] = $market['id'];
            $trigger = $this->safe_bool_2($params, 'stop', 'trigger');
            $stopLossTakeProfit = $this->safe_value($params, 'stopLossTakeProfit');
            $trailing = $this->safe_bool($params, 'trailing', false);
            $params = $this->omit($params, array( 'stop', 'stopLossTakeProfit', 'trailing', 'trigger' ));
            if ($market['linear']) {
                $marginMode = null;
                list($marginMode, $params) = $this->handle_margin_mode_and_params('cancelAllOrders', $params);
                $marginMode = ($marginMode === null) ? 'cross' : $marginMode;
                if ($marginMode === 'isolated') {
                    if ($trigger) {
                        $response = $this->contractPrivatePostLinearSwapApiV1SwapTriggerCancelall ($this->extend($request, $params));
                    } elseif ($stopLossTakeProfit) {
                        $response = $this->contractPrivatePostLinearSwapApiV1SwapTpslCancelall ($this->extend($request, $params));
                    } elseif ($trailing) {
                        $response = $this->contractPrivatePostLinearSwapApiV1SwapTrackCancelall ($this->extend($request, $params));
                    } else {
                        $response = $this->contractPrivatePostLinearSwapApiV1SwapCancelall ($this->extend($request, $params));
                    }
                } elseif ($marginMode === 'cross') {
                    if ($trigger) {
                        $response = $this->contractPrivatePostLinearSwapApiV1SwapCrossTriggerCancelall ($this->extend($request, $params));
                    } elseif ($stopLossTakeProfit) {
                        $response = $this->contractPrivatePostLinearSwapApiV1SwapCrossTpslCancelall ($this->extend($request, $params));
                    } elseif ($trailing) {
                        $response = $this->contractPrivatePostLinearSwapApiV1SwapCrossTrackCancelall ($this->extend($request, $params));
                    } else {
                        $response = $this->contractPrivatePostLinearSwapApiV1SwapCrossCancelall ($this->extend($request, $params));
                    }
                }
            } elseif ($market['inverse']) {
                if ($market['swap']) {
                    if ($trigger) {
                        $response = $this->contractPrivatePostSwapApiV1SwapTriggerCancelall ($this->extend($request, $params));
                    } elseif ($stopLossTakeProfit) {
                        $response = $this->contractPrivatePostSwapApiV1SwapTpslCancelall ($this->extend($request, $params));
                    } elseif ($trailing) {
                        $response = $this->contractPrivatePostSwapApiV1SwapTrackCancelall ($this->extend($request, $params));
                    } else {
                        $response = $this->contractPrivatePostSwapApiV1SwapCancelall ($this->extend($request, $params));
                    }
                } elseif ($market['future']) {
                    if ($trigger) {
                        $response = $this->contractPrivatePostApiV1ContractTriggerCancelall ($this->extend($request, $params));
                    } elseif ($stopLossTakeProfit) {
                        $response = $this->contractPrivatePostApiV1ContractTpslCancelall ($this->extend($request, $params));
                    } elseif ($trailing) {
                        $response = $this->contractPrivatePostApiV1ContractTrackCancelall ($this->extend($request, $params));
                    } else {
                        $response = $this->contractPrivatePostApiV1ContractCancelall ($this->extend($request, $params));
                    }
                }
            } else {
                throw new NotSupported($this->id . ' cancelAllOrders() does not support ' . $marketType . ' markets');
            }
            //
            //     {
            //         "status" => "ok",
            //         "data" => array(
            //             "errors" => array(),
            //             "successes" => "1104754904426696704"
            //         ),
            //         "ts" => "1683435723755"
            //     }
            //
            $data = $this->safe_dict($response, 'data');
            return $this->parse_cancel_orders($data);
        }
    }

    public function cancel_all_orders_after(?int $timeout, $params = array ()) {
        /**
         * dead man's switch, cancel all orders after the given $timeout
         *
         * @see https://huobiapi.github.io/docs/spot/v1/en/#dead-man-s-switch
         *
         * @param {number} $timeout time in milliseconds, 0 represents cancel the timer
         * @param {array} [$params] extra parameters specific to the exchange API endpoint
         * @return {array} the api result
         */
        $this->load_markets();
        $request = array(
            'timeout' => ($timeout > 0) ? $this->parse_to_int($timeout / 1000) : 0,
        );
        $response = $this->v2PrivatePostAlgoOrdersCancelAllAfter ($this->extend($request, $params));
        //
        //     {
        //         "code" => 200,
        //         "message" => "success",
        //         "data" => {
        //             "currentTime" => 1630491627230,
        //             "triggerTime" => 1630491637230
        //         }
        //     }
        //
        return $response;
    }

    public function parse_deposit_address($depositAddress, ?array $currency = null) {
        //
        //     {
        //         "currency" => "usdt",
        //         "address" => "0xf7292eb9ba7bc50358e27f0e025a4d225a64127b",
        //         "addressTag" => "",
        //         "chain" => "usdterc20", // trc20usdt, hrc20usdt, usdt, algousdt
        //     }
        //
        $address = $this->safe_string($depositAddress, 'address');
        $tag = $this->safe_string($depositAddress, 'addressTag');
        $currencyId = $this->safe_string($depositAddress, 'currency');
        $currency = $this->safe_currency($currencyId, $currency);
        $code = $this->safe_currency_code($currencyId, $currency);
        $note = $this->safe_string($depositAddress, 'note');
        $networkId = $this->safe_string($depositAddress, 'chain');
        $this->check_address($address);
        return array(
            'currency' => $code,
            'address' => $address,
            'tag' => $tag,
            'network' => $this->network_id_to_code($networkId),
            'note' => $note,
            'info' => $depositAddress,
        );
    }

    public function fetch_deposit_addresses_by_network(string $code, $params = array ()): array {
        /**
         *
         * @see https://www.htx.com/en-us/opend/newApiPages/?id=7ec50029-7773-11ed-9966-0242ac110003
         *
         * fetch a dictionary of addresses for a $currency, indexed by network
         * @param {string} $code unified $currency $code of the $currency for the deposit address
         * @param {array} [$params] extra parameters specific to the exchange API endpoint
         * @return {array} a dictionary of ~@link https://docs.ccxt.com/#/?id=address-structure address structures~ indexed by the network
         */
        $this->load_markets();
        $currency = $this->currency($code);
        $request = array(
            'currency' => $currency['id'],
        );
        $response = $this->spotPrivateGetV2AccountDepositAddress ($this->extend($request, $params));
        //
        //     {
        //         "code" => 200,
        //         "data" => array(
        //             {
        //                 "currency" => "eth",
        //                 "address" => "0xf7292eb9ba7bc50358e27f0e025a4d225a64127b",
        //                 "addressTag" => "",
        //                 "chain" => "eth"
        //             }
        //         )
        //     }
        //
        $data = $this->safe_value($response, 'data', array());
        $parsed = $this->parse_deposit_addresses($data, [ $currency['code'] ], false);
        return $this->index_by($parsed, 'network');
    }

    public function fetch_deposit_address(string $code, $params = array ()): array {
        /**
         * fetch the deposit address for a $currency associated with this account
         *
         * @see https://www.htx.com/en-us/opend/newApiPages/?id=7ec50029-7773-11ed-9966-0242ac110003
         *
         * @param {string} $code unified $currency $code
         * @param {array} [$params] extra parameters specific to the exchange API endpoint
         * @return {array} an ~@link https://docs.ccxt.com/#/?id=address-structure address structure~
         */
        $this->load_markets();
        $currency = $this->currency($code);
        list($networkCode, $paramsOmited) = $this->handle_network_code_and_params($params);
        $indexedAddresses = $this->fetch_deposit_addresses_by_network($code, $paramsOmited);
        $selectedNetworkCode = $this->select_network_code_from_unified_networks($currency['code'], $networkCode, $indexedAddresses);
        return $indexedAddresses[$selectedNetworkCode];
    }

    public function fetch_withdraw_addresses(string $code, $note = null, $networkCode = null, $params = array ()) {
        $this->load_markets();
        $currency = $this->currency($code);
        $request = array(
            'currency' => $currency['id'],
        );
        $response = $this->spotPrivateGetV2AccountWithdrawAddress ($this->extend($request, $params));
        //
        //     {
        //         "code" => 200,
        //         "data" => array(
        //             {
        //                 "currency" => "eth",
        //                 "chain" => "eth"
        //                 "note" => "Binance - TRC20",
        //                 "addressTag" => "",
        //                 "address" => "0xf7292eb9ba7bc50358e27f0e025a4d225a64127b",
        //             }
        //         )
        //     }
        //
        $data = $this->safe_value($response, 'data', array());
        $allAddresses = $this->parse_deposit_addresses($data, [ $currency['code'] ], false); // cjg => to do remove this weird object or array ambiguity
        $addresses = array();
        for ($i = 0; $i < count($allAddresses); $i++) {
            $address = $allAddresses[$i];
            $noteMatch = ($note === null) || ($address['note'] === $note);
            $networkMatch = ($networkCode === null) || ($address['network'] === $networkCode);
            if ($noteMatch && $networkMatch) {
                $addresses[] = $address;
            }
        }
        return $addresses;
    }

    public function fetch_deposits(?string $code = null, ?int $since = null, ?int $limit = null, $params = array ()): array {
        /**
         *
         * @see https://www.htx.com/en-us/opend/newApiPages/?id=7ec4f050-7773-11ed-9966-0242ac110003
         *
         * fetch all deposits made to an account
         * @param {string} $code unified $currency $code
         * @param {int} [$since] the earliest time in ms to fetch deposits for
         * @param {int} [$limit] the maximum number of deposits structures to retrieve
         * @param {array} [$params] extra parameters specific to the exchange API endpoint
         * @return {array[]} a list of ~@link https://docs.ccxt.com/#/?id=transaction-structure transaction structures~
         */
        if ($limit === null || $limit > 100) {
            $limit = 100;
        }
        $this->load_markets();
        $currency = null;
        if ($code !== null) {
            $currency = $this->currency($code);
        }
        $request = array(
            '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 !== null) {
            $request['currency'] = $currency['id'];
        }
        if ($limit !== null) {
            $request['size'] = $limit; // max 100
        }
        $response = $this->spotPrivateGetV1QueryDepositWithdraw ($this->extend($request, $params));
        //
        //    {
        //         "status" => "ok",
        //         "data" => array(
        //             array(
        //                 "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 $this->parse_transactions($response['data'], $currency, $since, $limit);
    }

    public function fetch_withdrawals(?string $code = null, ?int $since = null, ?int $limit = null, $params = array ()): array {
        /**
         * fetch all withdrawals made from an account
         *
         * @see https://huobiapi.github.io/docs/spot/v1/en/#search-for-existed-withdraws-and-deposits
         *
         * @param {string} $code unified $currency $code
         * @param {int} [$since] the earliest time in ms to fetch withdrawals for
         * @param {int} [$limit] the maximum number of withdrawals structures to retrieve
         * @param {array} [$params] extra parameters specific to the exchange API endpoint
         * @return {array[]} a list of ~@link https://docs.ccxt.com/#/?id=transaction-structure transaction structures~
         */
        if ($limit === null || $limit > 100) {
            $limit = 100;
        }
        $this->load_markets();
        $currency = null;
        if ($code !== null) {
            $currency = $this->currency($code);
        }
        $request = array(
            '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 !== null) {
            $request['currency'] = $currency['id'];
        }
        if ($limit !== null) {
            $request['size'] = $limit; // max 100
        }
        $response = $this->spotPrivateGetV1QueryDepositWithdraw ($this->extend($request, $params));
        //
        //    {
        //         "status" => "ok",
        //         "data" => array(
        //             array(
        //                 "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 $this->parse_transactions($response['data'], $currency, $since, $limit);
    }

    public function parse_transaction(array $transaction, ?array $currency = null): array {
        //
        // fetchDeposits
        //
        //     array(
        //         "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 = $this->safe_integer($transaction, 'created-at');
        $code = $this->safe_currency_code($this->safe_string($transaction, 'currency'));
        $type = $this->safe_string($transaction, 'type');
        if ($type === 'withdraw') {
            $type = 'withdrawal';
        }
        $feeCost = $this->safe_string($transaction, 'fee');
        if ($feeCost !== null) {
            $feeCost = Precise::string_abs($feeCost);
        }
        $networkId = $this->safe_string($transaction, 'chain');
        $txHash = $this->safe_string($transaction, 'tx-hash');
        if ($networkId === 'ETH' && mb_strpos($txHash, '0x') === false) {
            $txHash = '0x' . $txHash;
        }
        $subType = $this->safe_string($transaction, 'sub-type');
        $internal = $subType === 'FAST';
        return array(
            'info' => $transaction,
            'id' => $this->safe_string_2($transaction, 'id', 'data'),
            'txid' => $txHash,
            'timestamp' => $timestamp,
            'datetime' => $this->iso8601($timestamp),
            'network' => $this->network_id_to_code($networkId),
            'address' => $this->safe_string($transaction, 'address'),
            'addressTo' => null,
            'addressFrom' => null,
            'tag' => $this->safe_string($transaction, 'address-tag'),
            'tagTo' => null,
            'tagFrom' => null,
            'type' => $type,
            'amount' => $this->safe_number($transaction, 'amount'),
            'currency' => $code,
            'status' => $this->parse_transaction_status($this->safe_string($transaction, 'state')),
            'updated' => $this->safe_integer($transaction, 'updated-at'),
            'comment' => null,
            'internal' => $internal,
            'fee' => array(
                'currency' => $code,
                'cost' => $this->parse_number($feeCost),
                'rate' => null,
            ),
        );
    }

    public function parse_transaction_status(?string $status) {
        $statuses = array(
            // 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 $this->safe_string($statuses, $status, $status);
    }

    public function withdraw(string $code, float $amount, string $address, ?string $tag = null, $params = array ()): array {
        /**
         *
         * @see https://www.htx.com/en-us/opend/newApiPages/?id=7ec4cc41-7773-11ed-9966-0242ac110003
         *
         * make a withdrawal
         * @param {string} $code unified $currency $code
         * @param {float} $amount the $amount to withdraw
         * @param {string} $address the $address to withdraw to
         * @param {string} $tag
         * @param {array} [$params] extra parameters specific to the exchange API endpoint
         * @return {array} a ~@link https://docs.ccxt.com/#/?id=transaction-structure transaction structure~
         */
        list($tag, $params) = $this->handle_withdraw_tag_and_params($tag, $params);
        $this->load_markets();
        $this->check_address($address);
        $currency = $this->currency($code);
        $request = array(
            'address' => $address, // only supports existing addresses in your withdraw $address list
            'currency' => strtolower($currency['id']),
        );
        if ($tag !== null) {
            $request['addr-tag'] = $tag; // only for XRP?
        }
        $networkCode = null;
        list($networkCode, $params) = $this->handle_network_code_and_params($params);
        if ($networkCode !== null) {
            $request['chain'] = $this->network_code_to_id($networkCode, $code);
        }
        $amount = floatval($this->currency_to_precision($code, $amount, $networkCode));
        $withdrawOptions = $this->safe_value($this->options, 'withdraw', array());
        if ($this->safe_bool($withdrawOptions, 'includeFee', false)) {
            $fee = $this->safe_number($params, 'fee');
            if ($fee === null) {
                $currencies = $this->fetch_currencies();
                $this->currencies = $this->map_to_safe_map($this->deep_extend($this->currencies, $currencies));
                $targetNetwork = $this->safe_value($currency['networks'], $networkCode, array());
                $fee = $this->safe_number($targetNetwork, 'fee');
                if ($fee === null) {
                    throw new ArgumentsRequired($this->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 = $this->currency_to_precision($code, $fee, $networkCode);
            $params = $this->omit($params, 'fee');
            $amountString = $this->number_to_string($amount);
            $amountSubtractedString = Precise::string_sub($amountString, $feeString);
            $amountSubtracted = floatval($amountSubtractedString);
            $request['fee'] = floatval($feeString);
            $amount = floatval($this->currency_to_precision($code, $amountSubtracted, $networkCode));
        }
        $request['amount'] = $amount;
        $response = $this->spotPrivatePostV1DwWithdrawApiCreate ($this->extend($request, $params));
        //
        //     {
        //         "status" => "ok",
        //         "data" => "99562054"
        //     }
        //
        return $this->parse_transaction($response, $currency);
    }

    public function parse_transfer(array $transfer, ?array $currency = null): array {
        //
        // $transfer
        //
        //     {
        //         "data" => 12345,
        //         "status" => "ok"
        //     }
        //
        $id = $this->safe_string($transfer, 'data');
        $code = $this->safe_currency_code(null, $currency);
        return array(
            'info' => $transfer,
            'id' => $id,
            'timestamp' => null,
            'datetime' => null,
            'currency' => $code,
            'amount' => null,
            'fromAccount' => null,
            'toAccount' => null,
            'status' => null,
        );
    }

    public function transfer(string $code, float $amount, string $fromAccount, string $toAccount, $params = array ()): array {
        /**
         * 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 {string} $code unified $currency $code
         * @param {float} $amount amount to transfer
         * @param {string} $fromAccount account to transfer from 'spot', 'future', 'swap'
         * @param {string} $toAccount account to transfer to 'spot', 'future', 'swap'
         * @param {array} [$params] extra parameters specific to the exchange API endpoint
         * @param {string} [$params->symbol] used for isolated margin transfer
         * @param {string} [$params->subType] 'linear' or 'inverse', only used when transfering to/from swap accounts
         * @return {array} a ~@link https://docs.ccxt.com/#/?id=transfer-structure transfer structure~
         */
        $this->load_markets();
        $currency = $this->currency($code);
        $request = array(
            'currency' => $currency['id'],
            'amount' => floatval($this->currency_to_precision($code, $amount)),
        );
        $subType = null;
        list($subType, $params) = $this->handle_sub_type_and_params('transfer', null, $params);
        $fromAccountId = $this->convert_type_to_account($fromAccount);
        $toAccountId = $this->convert_type_to_account($toAccount);
        $toCross = $toAccountId === 'cross';
        $fromCross = $fromAccountId === 'cross';
        $toIsolated = $this->in_array($toAccountId, $this->ids);
        $fromIsolated = $this->in_array($fromAccountId, $this->ids);
        $fromSpot = $fromAccountId === 'pro';
        $toSpot = $toAccountId === 'pro';
        if ($fromSpot && $toSpot) {
            throw new BadRequest($this->id . ' transfer () cannot make a transfer between ' . $fromAccount . ' and ' . $toAccount);
        }
        $fromOrToFuturesAccount = ($fromAccountId === 'futures') || ($toAccountId === 'futures');
        $response = null;
        if ($fromOrToFuturesAccount) {
            $type = $fromAccountId . '-to-' . $toAccountId;
            $type = $this->safe_string($params, 'type', $type);
            $request['type'] = $type;
            $response = $this->spotPrivatePostV1FuturesTransfer ($this->extend($request, $params));
        } elseif ($fromSpot && $toCross) {
            $response = $this->privatePostCrossMarginTransferIn ($this->extend($request, $params));
        } elseif ($fromCross && $toSpot) {
            $response = $this->privatePostCrossMarginTransferOut ($this->extend($request, $params));
        } elseif ($fromSpot && $toIsolated) {
            $request['symbol'] = $toAccountId;
            $response = $this->privatePostDwTransferInMargin ($this->extend($request, $params));
        } elseif ($fromIsolated && $toSpot) {
            $request['symbol'] = $fromAccountId;
            $response = $this->privatePostDwTransferOutMargin ($this->extend($request, $params));
        } else {
            if ($subType === 'linear') {
                if (($fromAccountId === 'swap') || ($fromAccount === 'linear-swap')) {
                    $fromAccountId = 'linear-swap';
                } else {
                    $toAccountId = 'linear-swap';
                }
                // check if cross-margin or isolated
                $symbol = $this->safe_string($params, 'symbol');
                $params = $this->omit($params, 'symbol');
                if ($symbol !== null) {
                    $symbol = $this->market_id($symbol);
                    $request['margin-account'] = $symbol;
                } else {
                    $request['margin-account'] = 'USDT'; // cross-margin
                }
            }
            $request['from'] = $fromSpot ? 'spot' : $fromAccountId;
            $request['to'] = $toSpot ? 'spot' : $toAccountId;
            $response = $this->v2PrivatePostAccountTransfer ($this->extend($request, $params));
        }
        //
        //    {
        //        "code" => "200",
        //        "data" => "660150061",
        //        "message" => "Succeed",
        //        "success" => true,
        //        "print-log" => true
        //    }
        //
        return $this->parse_transfer($response, $currency);
    }

    public function fetch_isolated_borrow_rates($params = array ()): IsolatedBorrowRates {
        /**
         * fetch the borrow interest rates of all currencies
         *
         * @see https://huobiapi.github.io/docs/spot/v1/en/#get-loan-interest-rate-and-quota-isolated
         *
         * @param {array} [$params] extra parameters specific to the exchange API endpoint
         * @return {array} a list of ~@link https://docs.ccxt.com/#/?id=isolated-borrow-rate-structure isolated borrow rate structures~
         */
        $this->load_markets();
        $response = $this->spotPrivateGetV1MarginLoanInfo ($params);
        //
        // {
        //     "status" => "ok",
        //     "data" => array(
        //         {
        //             "symbol" => "1inchusdt",
        //             "currencies" => array(
        //                 array(
        //                     "currency" => "1inch",
        //                     "interest-rate" => "0.00098",
        //                     "min-loan-amt" => "90.000000000000000000",
        //                     "max-loan-amt" => "1000.000000000000000000",
        //                     "loanable-amt" => "0.0",
        //                     "actual-rate" => "0.00098"
        //                 ),
        //                 array(
        //                     "currency" => "usdt",
        //                     "interest-rate" => "0.00098",
        //                     "min-loan-amt" => "100.000000000000000000",
        //                     "max-loan-amt" => "1000.000000000000000000",
        //                     "loanable-amt" => "0.0",
        //                     "actual-rate" => "0.00098"
        //                 }
        //             )
        //         ),
        //         ...
        //     )
        // }
        //
        $data = $this->safe_value($response, 'data', array());
        return $this->parse_isolated_borrow_rates($data);
    }

    public function parse_isolated_borrow_rate(array $info, ?array $market = null): array {
        //
        //     {
        //         "symbol" => "1inchusdt",
        //         "currencies" => array(
        //             array(
        //                 "currency" => "1inch",
        //                 "interest-rate" => "0.00098",
        //                 "min-loan-amt" => "90.000000000000000000",
        //                 "max-loan-amt" => "1000.000000000000000000",
        //                 "loanable-amt" => "0.0",
        //                 "actual-rate" => "0.00098"
        //             ),
        //             array(
        //                 "currency" => "usdt",
        //                 "interest-rate" => "0.00098",
        //                 "min-loan-amt" => "100.000000000000000000",
        //                 "max-loan-amt" => "1000.000000000000000000",
        //                 "loanable-amt" => "0.0",
        //                 "actual-rate" => "0.00098"
        //             }
        //         )
        //     ),
        //
        $marketId = $this->safe_string($info, 'symbol');
        $symbol = $this->safe_symbol($marketId, $market);
        $currencies = $this->safe_value($info, 'currencies', array());
        $baseData = $this->safe_value($currencies, 0);
        $quoteData = $this->safe_value($currencies, 1);
        $baseId = $this->safe_string($baseData, 'currency');
        $quoteId = $this->safe_string($quoteData, 'currency');
        return array(
            'symbol' => $symbol,
            'base' => $this->safe_currency_code($baseId),
            'baseRate' => $this->safe_number($baseData, 'actual-rate'),
            'quote' => $this->safe_currency_code($quoteId),
            'quoteRate' => $this->safe_number($quoteData, 'actual-rate'),
            'period' => 86400000,
            'timestamp' => null,
            'datetime' => null,
            'info' => $info,
        );
    }

    public function fetch_funding_rate_history(?string $symbol = null, ?int $since = null, ?int $limit = null, $params = array ()) {
        /**
         *
         * @see https://huobiapi.github.io/docs/usdt_swap/v1/en/#general-query-historical-funding-rate
         * @see https://huobiapi.github.io/docs/coin_margined_swap/v1/en/#query-historical-funding-rate
         *
         * fetches historical funding rate prices
         * @param {string} $symbol unified $symbol of the $market to fetch the funding rate history for
         * @param {int} [$since] not used by huobi, but filtered internally by ccxt
         * @param {int} [$limit] not used by huobi, but filtered internally by ccxt
         * @param {array} [$params] extra parameters specific to the exchange API endpoint
         * @param {boolean} [$params->paginate] default false, when true will automatically $paginate by calling this endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-$params)
         * @return {array[]} a list of ~@link https://docs.ccxt.com/#/?id=funding-rate-history-structure funding rate structures~
         */
        if ($symbol === null) {
            throw new ArgumentsRequired($this->id . ' fetchFundingRateHistory() requires a $symbol argument');
        }
        $paginate = false;
        list($paginate, $params) = $this->handle_option_and_params($params, 'fetchFundingRateHistory', 'paginate');
        if ($paginate) {
            return $this->fetch_paginated_call_cursor('fetchFundingRateHistory', $symbol, $since, $limit, $params, 'current_page', 'page_index', 1, 50);
        }
        $this->load_markets();
        $market = $this->market($symbol);
        $request = array(
            'contract_code' => $market['id'],
        );
        if ($limit !== null) {
            $request['page_size'] = $limit;
        } else {
            $request['page_size'] = 50; // max
        }
        $response = null;
        if ($market['inverse']) {
            $response = $this->contractPublicGetSwapApiV1SwapHistoricalFundingRate ($this->extend($request, $params));
        } elseif ($market['linear']) {
            $response = $this->contractPublicGetLinearSwapApiV1SwapHistoricalFundingRate ($this->extend($request, $params));
        } else {
            throw new NotSupported($this->id . ' fetchFundingRateHistory() supports inverse and linear swaps only');
        }
        //
        // {
        //     "status" => "ok",
        //     "data" => array(
        //         "total_page" => 62,
        //         "current_page" => 1,
        //         "total_size" => 1237,
        //         "data" => array(
        //             array(
        //                 "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 = $this->safe_value($response, 'data');
        $cursor = $this->safe_value($data, 'current_page');
        $result = $this->safe_value($data, 'data', array());
        $rates = array();
        for ($i = 0; $i < count($result); $i++) {
            $entry = $result[$i];
            $entry['current_page'] = $cursor;
            $marketId = $this->safe_string($entry, 'contract_code');
            $symbolInner = $this->safe_symbol($marketId);
            $timestamp = $this->safe_integer($entry, 'funding_time');
            $rates[] = array(
                'info' => $entry,
                'symbol' => $symbolInner,
                'fundingRate' => $this->safe_number($entry, 'funding_rate'),
                'timestamp' => $timestamp,
                'datetime' => $this->iso8601($timestamp),
            );
        }
        $sorted = $this->sort_by($rates, 'timestamp');
        return $this->filter_by_symbol_since_limit($sorted, $market['symbol'], $since, $limit);
    }

    public function parse_funding_rate($contract, ?array $market = null): array {
        //
        // {
        //      "status" => "ok",
        //      "data" => array(
        //         "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 = $this->safe_number($contract, 'estimated_rate');
        $fundingTimestamp = $this->safe_integer($contract, 'funding_time');
        $nextFundingTimestamp = $this->safe_integer($contract, 'next_funding_time');
        $fundingTimeString = $this->safe_string($contract, 'funding_time');
        $nextFundingTimeString = $this->safe_string($contract, 'next_funding_time');
        $millisecondsInterval = Precise::string_sub($nextFundingTimeString, $fundingTimeString);
        $marketId = $this->safe_string($contract, 'contract_code');
        $symbol = $this->safe_symbol($marketId, $market);
        return array(
            'info' => $contract,
            'symbol' => $symbol,
            'markPrice' => null,
            'indexPrice' => null,
            'interestRate' => null,
            'estimatedSettlePrice' => null,
            'timestamp' => null,
            'datetime' => null,
            'fundingRate' => $this->safe_number($contract, 'funding_rate'),
            'fundingTimestamp' => $fundingTimestamp,
            'fundingDatetime' => $this->iso8601($fundingTimestamp),
            'nextFundingRate' => $nextFundingRate,
            'nextFundingTimestamp' => $nextFundingTimestamp,
            'nextFundingDatetime' => $this->iso8601($nextFundingTimestamp),
            'previousFundingRate' => null,
            'previousFundingTimestamp' => null,
            'previousFundingDatetime' => null,
            'interval' => $this->parse_funding_interval($millisecondsInterval),
        );
    }

    public function parse_funding_interval($interval) {
        $intervals = array(
            '3600000' => '1h',
            '14400000' => '4h',
            '28800000' => '8h',
            '57600000' => '16h',
            '86400000' => '24h',
        );
        return $this->safe_string($intervals, $interval, $interval);
    }

    public function fetch_funding_rate(string $symbol, $params = array ()): array {
        /**
         * fetch the current funding rate
         *
         * @see https://huobiapi.github.io/docs/coin_margined_swap/v1/en/#query-funding-rate
         * @see https://huobiapi.github.io/docs/usdt_swap/v1/en/#general-query-funding-rate
         *
         * @param {string} $symbol unified $market $symbol
         * @param {array} [$params] extra parameters specific to the exchange API endpoint
         * @return {array} a ~@link https://docs.ccxt.com/#/?id=funding-rate-structure funding rate structure~
         */
        $this->load_markets();
        $market = $this->market($symbol);
        $request = array(
            'contract_code' => $market['id'],
        );
        $response = null;
        if ($market['inverse']) {
            $response = $this->contractPublicGetSwapApiV1SwapFundingRate ($this->extend($request, $params));
        } elseif ($market['linear']) {
            $response = $this->contractPublicGetLinearSwapApiV1SwapFundingRate ($this->extend($request, $params));
        } else {
            throw new NotSupported($this->id . ' fetchFundingRate() supports inverse and linear swaps only');
        }
        //
        // {
        //     "status" => "ok",
        //     "data" => array(
        //         "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 = $this->safe_value($response, 'data', array());
        return $this->parse_funding_rate($result, $market);
    }

    public function fetch_funding_rates(?array $symbols = null, $params = array ()): array {
        /**
         * fetch the funding rate for multiple markets
         *
         * @see https://huobiapi.github.io/docs/usdt_swap/v1/en/#general-query-a-batch-of-funding-rate
         * @see https://huobiapi.github.io/docs/coin_margined_swap/v1/en/#query-a-batch-of-funding-rate
         *
         * @param {string[]|null} $symbols list of unified $market $symbols
         * @param {array} [$params] extra parameters specific to the exchange API endpoint
         * @return {array[]} a list of ~@link https://docs.ccxt.com/#/?id=funding-rates-structure funding rate structures~, indexed by $market $symbols
         */
        $this->load_markets();
        $symbols = $this->market_symbols($symbols);
        $defaultSubType = $this->safe_string($this->options, 'defaultSubType', 'linear');
        $subType = null;
        list($subType, $params) = $this->handle_option_and_params($params, 'fetchFundingRates', 'subType', $defaultSubType);
        if ($symbols !== null) {
            $firstSymbol = $this->safe_string($symbols, 0);
            $market = $this->market($firstSymbol);
            $isLinear = $market['linear'];
            $subType = $isLinear ? 'linear' : 'inverse';
        }
        $request = array(
            // 'contract_code' => $market['id'],
        );
        $response = null;
        if ($subType === 'linear') {
            $response = $this->contractPublicGetLinearSwapApiV1SwapBatchFundingRate ($this->extend($request, $params));
        } elseif ($subType === 'inverse') {
            $response = $this->contractPublicGetSwapApiV1SwapBatchFundingRate ($this->extend($request, $params));
        } else {
            throw new NotSupported($this->id . ' fetchFundingRates() not support this $market type');
        }
        //
        //     {
        //         "status" => "ok",
        //         "data" => array(
        //             array(
        //                 "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 = $this->safe_value($response, 'data', array());
        return $this->parse_funding_rates($data, $symbols);
    }

    public function fetch_borrow_interest(?string $code = null, ?string $symbol = null, ?int $since = null, ?int $limit = null, $params = array ()): array {
        /**
         * fetch the $interest owed by the user for borrowing $currency for margin trading
         *
         * @see https://huobiapi.github.io/docs/spot/v1/en/#search-past-margin-orders-cross
         * @see https://huobiapi.github.io/docs/spot/v1/en/#search-past-margin-orders-isolated
         *
         * @param {string} $code unified $currency $code
         * @param {string} $symbol unified $market $symbol when fetch $interest in isolated markets
         * @param {int} [$since] the earliest time in ms to fetch borrrow $interest for
         * @param {int} [$limit] the maximum number of structures to retrieve
         * @param {array} [$params] extra parameters specific to the exchange API endpoint
         * @return {array[]} a list of ~@link https://docs.ccxt.com/#/?id=borrow-$interest-structure borrow $interest structures~
         */
        $this->load_markets();
        $marginMode = null;
        list($marginMode, $params) = $this->handle_margin_mode_and_params('fetchBorrowInterest', $params);
        $marginMode = ($marginMode === null) ? 'cross' : $marginMode;
        $request = array();
        if ($since !== null) {
            $request['start-date'] = $this->yyyymmdd($since);
        }
        if ($limit !== null) {
            $request['size'] = $limit;
        }
        $market = null;
        $response = null;
        if ($marginMode === 'isolated') {
            if ($symbol !== null) {
                $market = $this->market($symbol);
                $request['symbol'] = $market['id'];
            }
            $response = $this->privateGetMarginLoanOrders ($this->extend($request, $params));
        } else {  // Cross
            if ($code !== null) {
                $currency = $this->currency($code);
                $request['currency'] = $currency['id'];
            }
            $response = $this->privateGetCrossMarginLoanOrders ($this->extend($request, $params));
        }
        //
        //    {
        //        "status":"ok",
        //        "data":array(
        //            {
        //                "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 = $this->safe_value($response, 'data');
        $interest = $this->parse_borrow_interests($data, $market);
        return $this->filter_by_currency_since_limit($interest, $code, $since, $limit);
    }

    public function parse_borrow_interest(array $info, ?array $market = null): array {
        // 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 = $this->safe_string($info, 'symbol');
        $marginMode = ($marketId === null) ? 'cross' : 'isolated';
        $market = $this->safe_market($marketId);
        $symbol = $this->safe_string($market, 'symbol');
        $timestamp = $this->safe_integer($info, 'accrued-at');
        return array(
            'info' => $info,
            'symbol' => $symbol,
            'currency' => $this->safe_currency_code($this->safe_string($info, 'currency')),
            'interest' => $this->safe_number($info, 'interest-amount'),
            'interestRate' => $this->safe_number($info, 'interest-rate'),
            'amountBorrowed' => $this->safe_number($info, 'loan-amount'),
            'marginMode' => $marginMode,
            'timestamp' => $timestamp,  // Interest accrued time
            'datetime' => $this->iso8601($timestamp),
        );
    }

    public function nonce() {
        return $this->milliseconds() - $this->options['timeDifference'];
    }

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

    public function handle_errors(int $httpCode, string $reason, string $url, string $method, array $headers, string $body, $response, $requestHeaders, $requestBody) {
        if ($response === null) {
            return null; // fallback to default error handler
        }
        if (is_array($response) && array_key_exists('status', $response)) {
            //
            //     array("status":"error","err-$code":"order-limitorder-amount-min-error","err-msg":"limit order amount error, min => `0.001`","data":null)
            //     array("status":"ok","data":array("errors":[array("order_id":"1349442392365359104","err_code":1061,"err_msg":"The order does not exist.")],"successes":""),"ts":1741773744526)
            //
            $status = $this->safe_string($response, 'status');
            if ($status === 'error') {
                $code = $this->safe_string_2($response, 'err-code', 'err_code');
                $feedback = $this->id . ' ' . $body;
                $this->throw_broadly_matched_exception($this->exceptions['broad'], $body, $feedback);
                $this->throw_exactly_matched_exception($this->exceptions['exact'], $code, $feedback);
                $message = $this->safe_string_2($response, 'err-msg', 'err_msg');
                $this->throw_exactly_matched_exception($this->exceptions['exact'], $message, $feedback);
                throw new ExchangeError($feedback);
            }
        }
        if (is_array($response) && array_key_exists('code', $response)) {
            // array($code => '1003', $message => 'invalid signature')
            $feedback = $this->id . ' ' . $body;
            $code = $this->safe_string($response, 'code');
            $this->throw_exactly_matched_exception($this->exceptions['exact'], $code, $feedback);
        }
        $data = $this->safe_dict($response, 'data');
        $errorsList = $this->safe_list($data, 'errors');
        if ($errorsList !== null) {
            $first = $this->safe_dict($errorsList, 0);
            $errcode = $this->safe_string($first, 'err_code');
            $errmessage = $this->safe_string($first, 'err_msg');
            $feedBack = $this->id . ' ' . $body;
            $this->throw_exactly_matched_exception($this->exceptions['exact'], $errcode, $feedBack);
            $this->throw_exactly_matched_exception($this->exceptions['exact'], $errmessage, $feedBack);
        }
        return null;
    }

    public function fetch_funding_history(?string $symbol = null, ?int $since = null, ?int $limit = null, $params = array ()) {
        /**
         * fetch the history of funding payments paid and received on this 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 {string} $symbol unified $market $symbol
         * @param {int} [$since] the earliest time in ms to fetch funding history for
         * @param {int} [$limit] the maximum number of funding history structures to retrieve
         * @param {array} [$params] extra parameters specific to the exchange API endpoint
         * @return {array} a ~@link https://docs.ccxt.com/#/?id=funding-history-structure funding history structure~
         */
        $this->load_markets();
        $market = $this->market($symbol);
        list($marketType, $query) = $this->handle_market_type_and_params('fetchFundingHistory', $market, $params);
        $request = array(
            'type' => '30,31',
        );
        if ($since !== null) {
            $request['start_date'] = $since;
        }
        $response = null;
        if ($marketType === 'swap') {
            $request['contract'] = $market['id'];
            if ($market['linear']) {
                //
                //    {
                //        "status" => "ok",
                //        "data" => array(
                //           "financial_record" => array(
                //               array(
                //                   "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 = null;
                list($marginMode, $params) = $this->handle_margin_mode_and_params('fetchFundingHistory', $params);
                $marginMode = ($marginMode === null) ? 'cross' : $marginMode;
                if ($marginMode === 'isolated') {
                    $request['mar_acct'] = $market['id'];
                } else {
                    $request['mar_acct'] = $market['quoteId'];
                }
                $response = $this->contractPrivatePostLinearSwapApiV3SwapFinancialRecordExact ($this->extend($request, $query));
            } else {
                //
                //     {
                //         "code" => 200,
                //         "msg" => "",
                //         "data" => array(
                //             {
                //                 "query_id" => 138798248,
                //                 "id" => 117840,
                //                 "type" => 5,
                //                 "amount" => -0.024464850000000000,
                //                 "ts" => 1638758435635,
                //                 "contract_code" => "BTC-USDT-211210",
                //                 "asset" => "USDT",
                //                 "margin_account" => "USDT",
                //                 "face_margin_account" => ""
                //             }
                //         ),
                //         "ts" => 1604312615051
                //     }
                //
                $response = $this->contractPrivatePostSwapApiV3SwapFinancialRecordExact ($this->extend($request, $query));
            }
        } else {
            $request['symbol'] = $market['id'];
            $response = $this->contractPrivatePostApiV3ContractFinancialRecordExact ($this->extend($request, $query));
        }
        $data = $this->safe_list($response, 'data', array());
        return $this->parse_incomes($data, $market, $since, $limit);
    }

    public function set_leverage(int $leverage, ?string $symbol = null, $params = array ()) {
        /**
         * set the level of $leverage for a $market
         *
         * @see https://huobiapi.github.io/docs/usdt_swap/v1/en/#isolated-switch-$leverage
         * @see https://huobiapi.github.io/docs/usdt_swap/v1/en/#cross-switch-$leverage
         * @see https://huobiapi.github.io/docs/coin_margined_swap/v1/en/#switch-$leverage
         * @see https://huobiapi.github.io/docs/dm/v1/en/#switch-$leverage  // Coin-m futures
         *
         * @param {float} $leverage the rate of $leverage
         * @param {string} $symbol unified $market $symbol
         * @param {array} [$params] extra parameters specific to the exchange API endpoint
         * @return {array} $response from the exchange
         */
        if ($symbol === null) {
            throw new ArgumentsRequired($this->id . ' setLeverage() requires a $symbol argument');
        }
        $this->load_markets();
        $market = $this->market($symbol);
        list($marketType, $query) = $this->handle_market_type_and_params('setLeverage', $market, $params);
        $request = array(
            'lever_rate' => $leverage,
        );
        if ($marketType === 'future' && $market['inverse']) {
            $request['symbol'] = $market['settleId'];
        } else {
            $request['contract_code'] = $market['id'];
        }
        $response = null;
        if ($market['linear']) {
            $marginMode = null;
            list($marginMode, $params) = $this->handle_margin_mode_and_params('setLeverage', $params);
            $marginMode = ($marginMode === null) ? 'cross' : $marginMode;
            if ($marginMode === 'isolated') {
                $response = $this->contractPrivatePostLinearSwapApiV1SwapSwitchLeverRate ($this->extend($request, $query));
            } elseif ($marginMode === 'cross') {
                $response = $this->contractPrivatePostLinearSwapApiV1SwapCrossSwitchLeverRate ($this->extend($request, $query));
            } else {
                throw new NotSupported($this->id . ' setLeverage() not support this $market type');
            }
            //
            //     {
            //       "status" => "ok",
            //       "data" => array(
            //         "contract_code" => "BTC-USDT",
            //         "lever_rate" => "100",
            //         "margin_mode" => "isolated"
            //       ),
            //       "ts" => "1641184710649"
            //     }
            //
        } else {
            if ($marketType === 'future') {
                $response = $this->contractPrivatePostApiV1ContractSwitchLeverRate ($this->extend($request, $query));
            } elseif ($marketType === 'swap') {
                $response = $this->contractPrivatePostSwapApiV1SwapSwitchLeverRate ($this->extend($request, $query));
            } else {
                throw new NotSupported($this->id . ' setLeverage() not support this $market type');
            }
            //
            // future
            //     {
            //       "status" => "ok",
            //       "data" => array( $symbol => "BTC", lever_rate => 5 ),
            //       "ts" => 1641184578678
            //     }
            //
            // swap
            //
            //     {
            //       "status" => "ok",
            //       "data" => array( contract_code => "BTC-USD", lever_rate => "5" ),
            //       "ts" => "1641184652979"
            //     }
            //
        }
        return $response;
    }

    public function parse_income($income, ?array $market = null) {
        //
        //     {
        //       "id" => "1667161118",
        //       "symbol" => "BTC",
        //       "type" => "31",
        //       "amount" => "-2.11306593188E-7",
        //       "ts" => "1641139308983",
        //       "contract_code" => "BTC-USD"
        //     }
        //
        $marketId = $this->safe_string($income, 'contract_code');
        $symbol = $this->safe_symbol($marketId, $market);
        $amount = $this->safe_number($income, 'amount');
        $timestamp = $this->safe_integer($income, 'ts');
        $id = $this->safe_string($income, 'id');
        $currencyId = $this->safe_string_2($income, 'symbol', 'asset');
        $code = $this->safe_currency_code($currencyId);
        return array(
            'info' => $income,
            'symbol' => $symbol,
            'code' => $code,
            'timestamp' => $timestamp,
            'datetime' => $this->iso8601($timestamp),
            'id' => $id,
            'amount' => $amount,
        );
    }

    public function parse_position(array $position, ?array $market = null) {
        //
        //    {
        //        "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 = $this->safe_market($this->safe_string($position, 'contract_code'));
        $symbol = $market['symbol'];
        $contracts = $this->safe_string($position, 'volume');
        $contractSize = $this->safe_value($market, 'contractSize');
        $contractSizeString = $this->number_to_string($contractSize);
        $entryPrice = $this->safe_number($position, 'cost_open');
        $initialMargin = $this->safe_string($position, 'position_margin');
        $rawSide = $this->safe_string($position, 'direction');
        $side = ($rawSide === 'buy') ? 'long' : 'short';
        $unrealizedProfit = $this->safe_number($position, 'profit_unreal');
        $marginMode = $this->safe_string($position, 'margin_mode');
        $leverage = $this->safe_string($position, 'lever_rate');
        $percentage = Precise::string_mul($this->safe_string($position, 'profit_rate'), '100');
        $lastPrice = $this->safe_string($position, 'last_price');
        $faceValue = Precise::string_mul($contracts, $contractSizeString);
        $notional = null;
        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 = $this->safe_string($position, 'margin_balance');
        $liquidationPrice = $this->safe_number($position, 'liquidation_price');
        $adjustmentFactor = $this->safe_string($position, 'adjust_factor');
        $maintenanceMarginPercentage = Precise::string_div($adjustmentFactor, $leverage);
        $maintenanceMargin = Precise::string_mul($maintenanceMarginPercentage, $notional);
        $marginRatio = Precise::string_div($maintenanceMargin, $collateral);
        return $this->safe_position(array(
            'info' => $position,
            'id' => null,
            'symbol' => $symbol,
            'contracts' => $this->parse_number($contracts),
            'contractSize' => $contractSize,
            'entryPrice' => $entryPrice,
            'collateral' => $this->parse_number($collateral),
            'side' => $side,
            'unrealizedPnl' => $unrealizedProfit,
            'leverage' => $this->parse_number($leverage),
            'percentage' => $this->parse_number($percentage),
            'marginMode' => $marginMode,
            'notional' => $this->parse_number($notional),
            'markPrice' => null,
            'lastPrice' => null,
            'liquidationPrice' => $liquidationPrice,
            'initialMargin' => $this->parse_number($initialMargin),
            'initialMarginPercentage' => $this->parse_number($intialMarginPercentage),
            'maintenanceMargin' => $this->parse_number($maintenanceMargin),
            'maintenanceMarginPercentage' => $this->parse_number($maintenanceMarginPercentage),
            'marginRatio' => $this->parse_number($marginRatio),
            'timestamp' => null,
            'datetime' => null,
            'hedged' => null,
            'lastUpdateTimestamp' => null,
            'stopLossPrice' => null,
            'takeProfitPrice' => null,
        ));
    }

    public function fetch_positions(?array $symbols = null, $params = array ()): array {
        /**
         * fetch all open positions
         *
         * @see https://huobiapi.github.io/docs/usdt_swap/v1/en/#cross-query-user-39-s-$position-information
         * @see https://huobiapi.github.io/docs/usdt_swap/v1/en/#isolated-query-user-s-$position-information
         * @see https://huobiapi.github.io/docs/coin_margined_swap/v1/en/#query-user-s-$position-information
         * @see https://huobiapi.github.io/docs/dm/v1/en/#query-user-s-$position-information
         *
         * @param {string[]} [$symbols] list of unified $market $symbols
         * @param {array} [$params] extra parameters specific to the exchange API endpoint
         * @param {string} [$params->subType] 'linear' or 'inverse'
         * @param {string} [$params->type] *inverse only* 'future', or 'swap'
         * @param {string} [$params->marginMode] *linear only* 'cross' or 'isolated'
         * @return {array[]} a list of ~@link https://docs.ccxt.com/#/?id=$position-structure $position structure~
         */
        $this->load_markets();
        $symbols = $this->market_symbols($symbols);
        $market = null;
        if ($symbols !== null) {
            $symbolsLength = count($symbols);
            if ($symbolsLength > 0) {
                $first = $this->safe_string($symbols, 0);
                $market = $this->market($first);
            }
        }
        $marginMode = null;
        list($marginMode, $params) = $this->handle_margin_mode_and_params('fetchPositions', $params, 'cross');
        $subType = null;
        list($subType, $params) = $this->handle_sub_type_and_params('fetchPositions', $market, $params, 'linear');
        $marketType = null;
        list($marketType, $params) = $this->handle_market_type_and_params('fetchPositions', $market, $params);
        if ($marketType === 'spot') {
            $marketType = 'future';
        }
        $response = null;
        if ($subType === 'linear') {
            if ($marginMode === 'isolated') {
                $response = $this->contractPrivatePostLinearSwapApiV1SwapPositionInfo ($params);
            } elseif ($marginMode === 'cross') {
                $response = $this->contractPrivatePostLinearSwapApiV1SwapCrossPositionInfo ($params);
            } else {
                throw new NotSupported($this->id . ' fetchPositions() not support this $market type');
            }
            //
            //     {
            //       "status" => "ok",
            //       "data" => array(
            //         {
            //           "symbol" => "BTC",
            //           "contract_code" => "BTC-USDT",
            //           "volume" => "1.000000000000000000",
            //           "available" => "1.000000000000000000",
            //           "frozen" => "0E-18",
            //           "cost_open" => "47162.000000000000000000",
            //           "cost_hold" => "47162.000000000000000000",
            //           "profit_unreal" => "0.047300000000000000",
            //           "profit_rate" => "0.002005852169119206",
            //           "lever_rate" => "2",
            //           "position_margin" => "23.604650000000000000",
            //           "direction" => "buy",
            //           "profit" => "0.047300000000000000",
            //           "last_price" => "47209.3",
            //           "margin_asset" => "USDT",
            //           "margin_mode" => "isolated",
            //           "margin_account" => "BTC-USDT"
            //         }
            //       ),
            //       "ts" => "1641108676768"
            //     }
            //
        } else {
            if ($marketType === 'future') {
                $response = $this->contractPrivatePostApiV1ContractPositionInfo ($params);
            } elseif ($marketType === 'swap') {
                $response = $this->contractPrivatePostSwapApiV1SwapPositionInfo ($params);
            } else {
                throw new NotSupported($this->id . ' fetchPositions() not support this $market type');
            }
            //
            // future
            //     {
            //       "status" => "ok",
            //       "data" => array(
            //         {
            //           "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" => array(
            //         {
            //           "symbol" => "BTC",
            //           "contract_code" => "BTC-USD",
            //           "volume" => "1.000000000000000000",
            //           "available" => "1.000000000000000000",
            //           "frozen" => "0E-18",
            //           "cost_open" => "47150.000000000012353300",
            //           "cost_hold" => "47150.000000000012353300",
            //           "profit_unreal" => "0E-54",
            //           "profit_rate" => "-7.86E-16",
            //           "lever_rate" => "3",
            //           "position_margin" => "0.000706963591375044",
            //           "direction" => "buy",
            //           "profit" => "0E-54",
            //           "last_price" => "47150"
            //         }
            //       ),
            //       "ts" => "1641109636572"
            //     }
            //
        }
        $data = $this->safe_value($response, 'data', array());
        $timestamp = $this->safe_integer($response, 'ts');
        $result = array();
        for ($i = 0; $i < count($data); $i++) {
            $position = $data[$i];
            $parsed = $this->parse_position($position);
            $result[] = $this->extend($parsed, array(
                'timestamp' => $timestamp,
                'datetime' => $this->iso8601($timestamp),
            ));
        }
        return $this->filter_by_array_positions($result, 'symbol', $symbols, false);
    }

    public function fetch_position(string $symbol, $params = array ()) {
        /**
         * fetch $data on a single open contract trade $position
         *
         * @see https://huobiapi.github.io/docs/usdt_swap/v1/en/#cross-$query-assets-and-$positions
         * @see https://huobiapi.github.io/docs/usdt_swap/v1/en/#isolated-$query-assets-and-$positions
         * @see https://huobiapi.github.io/docs/coin_margined_swap/v1/en/#$query-assets-and-$positions
         * @see https://huobiapi.github.io/docs/dm/v1/en/#$query-assets-and-$positions
         *
         * @param {string} $symbol unified $market $symbol of the $market the $position is held in, default is null
         * @param {array} [$params] extra parameters specific to the exchange API endpoint
         * @return {array} a ~@link https://docs.ccxt.com/#/?id=$position-structure $position structure~
         */
        $this->load_markets();
        $market = $this->market($symbol);
        $marginMode = null;
        list($marginMode, $params) = $this->handle_margin_mode_and_params('fetchPosition', $params);
        $marginMode = ($marginMode === null) ? 'cross' : $marginMode;
        list($marketType, $query) = $this->handle_market_type_and_params('fetchPosition', $market, $params);
        $request = array();
        if ($market['future'] && $market['inverse']) {
            $request['symbol'] = $market['settleId'];
        } else {
            if ($marginMode === 'cross') {
                $request['margin_account'] = 'USDT'; // only allowed value
            }
            $request['contract_code'] = $market['id'];
        }
        $response = null;
        if ($market['linear']) {
            if ($marginMode === 'isolated') {
                $response = $this->contractPrivatePostLinearSwapApiV1SwapAccountPositionInfo ($this->extend($request, $query));
            } elseif ($marginMode === 'cross') {
                $response = $this->contractPrivatePostLinearSwapApiV1SwapCrossAccountPositionInfo ($this->extend($request, $query));
            } else {
                throw new NotSupported($this->id . ' fetchPosition() not support this $market type');
            }
            //
            // isolated
            //
            //     {
            //         "status" => "ok",
            //         "data" => array(
            //             array(
            //                 "positions" => array(),
            //                 "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" => array(
            //             "positions" => array(
            //                 array(
            //                     "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" => array(
            //                 array(
            //                     "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" => array(
            //                array(
            //                     "symbol" => "BTC",
            //                     "contract_code" => "BTC-USDT",
            //                     "margin_position" => "0.590400000000000000",
            //                     "margin_frozen" => "0E-18",
            //                     "margin_available" => "1.497799766913531118",
            //                     "profit_unreal" => "-0.010000000000000000",
            //                     "liquidation_price" => "27625.176468365024050352",
            //                     "lever_rate" => "50",
            //                     "adjust_factor" => "0.350000000000000000",
            //                     "contract_type" => "swap",
            //                     "pair" => "BTC-USDT",
            //                     "business_type" => "swap",
            //                     "trade_partition" => "USDT"
            //                 ),
            //                 ... all symbols listed
            //             ),
            //             "position_mode" => "dual_side"
            //         ),
            //         "ts" => "1653604697466"
            //     }
            //
        } else {
            if ($marketType === 'future') {
                $response = $this->contractPrivatePostApiV1ContractAccountPositionInfo ($this->extend($request, $query));
            } elseif ($marketType === 'swap') {
                $response = $this->contractPrivatePostSwapApiV1SwapAccountPositionInfo ($this->extend($request, $query));
            } else {
                throw new NotSupported($this->id . ' setLeverage() not support this $market type');
            }
            //
            // future, swap
            //
            //     {
            //       "status" => "ok",
            //       "data" => array(
            //         {
            //             "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" => array(
            //                 array(
            //                     "symbol" => "XRP",
            //                     "contract_code" => "XRP-USD",
            //                     // "contract_type" => "this_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":array(
            //             "positions":array(),
            //             "futures_contract_detail":array()
            //             "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":array()
            //         ),
            //         "ts":"1645521118946"
            //     }
            //
        }
        $data = $this->safe_value($response, 'data');
        $account = null;
        if ($marginMode === 'cross') {
            $account = $data;
        } else {
            $account = $this->safe_value($data, 0);
        }
        $omitted = $this->omit($account, array( 'positions' ));
        $positions = $this->safe_value($account, 'positions');
        $position = null;
        if ($market['future'] && $market['inverse']) {
            for ($i = 0; $i < count($positions); $i++) {
                $entry = $positions[$i];
                if ($entry['contract_code'] === $market['id']) {
                    $position = $entry;
                    break;
                }
            }
        } else {
            $position = $this->safe_value($positions, 0);
        }
        $timestamp = $this->safe_integer($response, 'ts');
        $parsed = $this->parse_position($this->extend($position, $omitted));
        $parsed['timestamp'] = $timestamp;
        $parsed['datetime'] = $this->iso8601($timestamp);
        return $parsed;
    }

    public function parse_ledger_entry_type($type) {
        $types = array(
            '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 $this->safe_string($types, $type, $type);
    }

    public function parse_ledger_entry(array $item, ?array $currency = null): array {
        //
        //     {
        //         "accountId" => 10000001,
        //         "currency" => "usdt",
        //         "transactAmt" => 10.000000000000000000,
        //         "transactType" => "transfer",
        //         "transferType" => "margin-transfer-out",
        //         "transactId" => 0,
        //         "transactTime" => 1629882331066,
        //         "transferer" => 28483123,
        //         "transferee" => 13496526
        //     }
        //
        $currencyId = $this->safe_string($item, 'currency');
        $code = $this->safe_currency_code($currencyId, $currency);
        $currency = $this->safe_currency($currencyId, $currency);
        $id = $this->safe_string($item, 'transactId');
        $transferType = $this->safe_string($item, 'transferType');
        $timestamp = $this->safe_integer($item, 'transactTime');
        $account = $this->safe_string($item, 'accountId');
        return $this->safe_ledger_entry(array(
            'info' => $item,
            'id' => $id,
            'direction' => $this->safe_string($item, 'direction'),
            'account' => $account,
            'referenceId' => $id,
            'referenceAccount' => $account,
            'type' => $this->parse_ledger_entry_type($transferType),
            'currency' => $code,
            'amount' => $this->safe_number($item, 'transactAmt'),
            'timestamp' => $timestamp,
            'datetime' => $this->iso8601($timestamp),
            'before' => null,
            'after' => null,
            'status' => null,
            'fee' => null,
        ), $currency);
    }

    public function fetch_ledger(?string $code = null, ?int $since = null, ?int $limit = null, $params = array ()): array {
        /**
         * fetch the history of changes, actions done by the user or operations that altered the balance of the user
         *
         * @see https://huobiapi.github.io/docs/spot/v1/en/#get-account-history
         *
         * @param {string} [$code] unified $currency $code, default is null
         * @param {int} [$since] timestamp in ms of the earliest ledger entry, default is null
         * @param {int} [$limit] max number of ledger entries to return, default is null
         * @param {array} [$params] extra parameters specific to the exchange API endpoint
         * @param {int} [$params->until] the latest time in ms to fetch entries for
         * @param {boolean} [$params->paginate] default false, when true will automatically $paginate by calling this endpoint multiple times. See in the docs all the [available parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-$params)
         * @return {array} a ~@link https://docs.ccxt.com/#/?id=ledger ledger structure~
         */
        $this->load_markets();
        $paginate = false;
        list($paginate, $params) = $this->handle_option_and_params($params, 'fetchLedger', 'paginate');
        if ($paginate) {
            return $this->fetch_paginated_call_dynamic('fetchLedger', $code, $since, $limit, $params, 500);
        }
        $accountId = $this->fetch_account_id_by_type('spot', null, null, $params);
        $request = array(
            '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 property_exists($this, ID) query for pagination
        );
        $currency = null;
        if ($code !== null) {
            $currency = $this->currency($code);
            $request['currency'] = $currency['id'];
        }
        if ($since !== null) {
            $request['startTime'] = $since;
        }
        if ($limit !== null) {
            $request['limit'] = $limit; // max 500
        }
        list($request, $params) = $this->handle_until_option('endTime', $request, $params);
        $response = $this->spotPrivateGetV2AccountLedger ($this->extend($request, $params));
        //
        //     {
        //         "code" => 200,
        //         "message" => "success",
        //         "data" => array(
        //             array(
        //                 "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 = $this->safe_value($response, 'data', array());
        return $this->parse_ledger($data, $currency, $since, $limit);
    }

    public function fetch_leverage_tiers(?array $symbols = null, $params = array ()): array {
        /**
         * retrieve information on the maximum leverage, and maintenance margin for trades of varying trade sizes
         * @param {string[]|null} $symbols list of unified market $symbols
         * @param {array} [$params] extra parameters specific to the exchange API endpoint
         * @return {array} a dictionary of ~@link https://docs.ccxt.com/#/?id=leverage-tiers-structure leverage tiers structures~, indexed by market $symbols
         */
        $this->load_markets();
        $response = $this->contractPublicGetLinearSwapApiV1SwapAdjustfactor ($params);
        //
        //    {
        //        "status" => "ok",
        //        "data" => array(
        //            {
        //                "symbol" => "MANA",
        //                "contract_code" => "MANA-USDT",
        //                "margin_mode" => "isolated",
        //                "trade_partition" => "USDT",
        //                "list" => array(
        //                    array(
        //                        "lever_rate" => 75,
        //                        "ladders" => array(
        //                            array(
        //                                "ladder" => 0,
        //                                "min_size" => 0,
        //                                "max_size" => 999,
        //                                "adjust_factor" => 0.7
        //                            ),
        //                            ...
        //                        )
        //                    }
        //                    ...
        //                )
        //            ),
        //            ...
        //        )
        //    }
        //
        $data = $this->safe_list($response, 'data', array());
        return $this->parse_leverage_tiers($data, $symbols, 'contract_code');
    }

    public function parse_market_leverage_tiers($info, ?array $market = null): array {
        $currencyId = $this->safe_string($info, 'trade_partition');
        $marketId = $this->safe_string($info, 'contract_code');
        $tiers = array();
        $brackets = $this->safe_list($info, 'list', array());
        for ($i = 0; $i < count($brackets); $i++) {
            $item = $brackets[$i];
            $leverage = $this->safe_string($item, 'lever_rate');
            $ladders = $this->safe_list($item, 'ladders', array());
            for ($k = 0; $k < count($ladders); $k++) {
                $bracket = $ladders[$k];
                $adjustFactor = $this->safe_string($bracket, 'adjust_factor');
                $tiers[] = array(
                    'tier' => $this->safe_integer($bracket, 'ladder'),
                    'symbol' => $this->safe_symbol($marketId, $market, null, 'swap'),
                    'currency' => $this->safe_currency_code($currencyId),
                    'minNotional' => $this->safe_number($bracket, 'min_size'),
                    'maxNotional' => $this->safe_number($bracket, 'max_size'),
                    'maintenanceMarginRate' => $this->parse_number(Precise::string_div($adjustFactor, $leverage)),
                    'maxLeverage' => $this->parse_number($leverage),
                    'info' => $bracket,
                );
            }
        }
        return $tiers;
    }

    public function fetch_open_interest_history(string $symbol, $timeframe = '1h', ?int $since = null, ?int $limit = null, $params = array ()) {
        /**
         * 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 {string} $symbol Unified CCXT $market $symbol
         * @param {string} $timeframe '1h', '4h', '12h', or '1d'
         * @param {int} [$since] Not used by huobi api, but $response parsed by CCXT
         * @param {int} [$limit] Default：48，Data Range [1,200]
         * @param {array} [$params] Exchange specific parameters
         * @param {int} [$params->amount_type] *required* Open interest unit. 1-cont，2-cryptocurrency
         * @param {int} [$params->pair] eg BTC-USDT *Only for USDT-M*
         * @return {array} an array of ~@link https://docs.ccxt.com/#/?id=open-interest-structure open interest structures~
         */
        if ($timeframe !== '1h' && $timeframe !== '4h' && $timeframe !== '12h' && $timeframe !== '1d') {
            throw new BadRequest($this->id . ' fetchOpenInterestHistory cannot only use the 1h, 4h, 12h and 1d timeframe');
        }
        $this->load_markets();
        $timeframes = array(
            '1h' => '60min',
            '4h' => '4hour',
            '12h' => '12hour',
            '1d' => '1day',
        );
        $market = $this->market($symbol);
        $amountType = $this->safe_integer_2($params, 'amount_type', 'amountType', 2);
        $request = array(
            'period' => $timeframes[$timeframe],
            'amount_type' => $amountType,
        );
        if ($limit !== null) {
            $request['size'] = $limit;
        }
        $response = null;
        if ($market['future']) {
            $request['contract_type'] = $this->safe_string($market['info'], 'contract_type');
            $request['symbol'] = $market['baseId'];  // currency code on coin-m futures
            // coin-m futures
            $response = $this->contractPublicGetApiV1ContractHisOpenInterest ($this->extend($request, $params));
        } elseif ($market['linear']) {
            $request['contract_type'] = 'swap';
            $request['contract_code'] = $market['id'];
            $request['contract_code'] = $market['id'];
            // USDT-M
            $response = $this->contractPublicGetLinearSwapApiV1SwapHisOpenInterest ($this->extend($request, $params));
        } else {
            $request['contract_code'] = $market['id'];
            // coin-m swaps
            $response = $this->contractPublicGetSwapApiV1SwapHisOpenInterest ($this->extend($request, $params));
        }
        //
        //  contractPublicGetlinearSwapApiV1SwapHisOpenInterest
        //    {
        //        "status" => "ok",
        //        "data" => array(
        //            "symbol" => "BTC",
        //            "tick" => array(
        //                array(
        //                    "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" => array(
        //            "symbol" => "CRV",
        //            "tick" => array(
        //                array(
        //                    "volume" => 19174.0000000000000000,
        //                    "amount_type" => 1,
        //                    "ts" => 1648224000000
        //                ),
        //                ...
        //            ),
        //            "contract_code" => "CRV-USD"
        //        ),
        //        "ts" => 1648226554260
        //    }
        //
        //  contractPublicGetApiV1ContractHisOpenInterest
        //    {
        //         "status" => "ok",
        //         "data" => array(
        //             "symbol" => "BTC",
        //             "contract_type" => "this_week",
        //             "tick" => array(
        //                array(
        //                     "volume" => "48419.0000000000000000",
        //                     "amount_type" => 1,
        //                     "ts" => 1648224000000
        //                ),
        //                ...
        //            )
        //        ),
        //        "ts" => 1648227062944
        //    }
        //
        $data = $this->safe_value($response, 'data');
        $tick = $this->safe_list($data, 'tick');
        return $this->parse_open_interests_history($tick, $market, $since, $limit);
    }

    public function fetch_open_interests(?array $symbols = null, $params = array ()) {
        /**
         * Retrieves the open interest for a list of $symbols
         *
         * @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 {string[]} [$symbols] a list of unified CCXT $market $symbols
         * @param {array} [$params] exchange specific parameters
         * @return {array[]} a list of ~@link https://docs.ccxt.com/#/?id=open-interest-structure open interest structures~
         */
        $this->load_markets();
        $symbols = $this->market_symbols($symbols);
        $market = null;
        if ($symbols !== null) {
            $symbolsLength = count($symbols);
            if ($symbolsLength > 0) {
                $first = $this->safe_string($symbols, 0);
                $market = $this->market($first);
            }
        }
        $request = array();
        $subType = null;
        list($subType, $params) = $this->handle_sub_type_and_params('fetchPositions', $market, $params, 'linear');
        $marketType = null;
        list($marketType, $params) = $this->handle_market_type_and_params('fetchPositions', $market, $params);
        $response = null;
        if ($marketType === 'future') {
            $response = $this->contractPublicGetApiV1ContractOpenInterest ($this->extend($request, $params));
            //
            //     {
            //         "status" => "ok",
            //         "data" => array(
            //             {
            //                 "volume" => 118850.000000000000000000,
            //                 "amount" => 635.502025211544374189,
            //                 "symbol" => "BTC",
            //                 "contract_type" => "this_week",
            //                 "contract_code" => "BTC220930",
            //                 "trade_amount" => 1470.9400749347598691119206024033947897351,
            //                 "trade_volume" => 286286,
            //                 "trade_turnover" => 28628600.000000000000000000
            //             }
            //         ),
            //         "ts" => 1664337928805
            //     }
            //
        } elseif ($subType === 'inverse') {
            $response = $this->contractPublicGetSwapApiV1SwapOpenInterest ($this->extend($request, $params));
            //
            //     {
            //         "status" => "ok",
            //         "data" => array(
            //             {
            //                 "volume" => 518018.000000000000000000,
            //                 "amount" => 2769.675777407074725180,
            //                 "symbol" => "BTC",
            //                 "contract_code" => "BTC-USD",
            //                 "trade_amount" => 9544.4032080046491323463688602729806842458,
            //                 "trade_volume" => 1848448,
            //                 "trade_turnover" => 184844800.000000000000000000
            //             }
            //         ),
            //         "ts" => 1664337226028
            //     }
            //
        } else {
            $request['contract_type'] = 'swap';
            $response = $this->contractPublicGetLinearSwapApiV1SwapOpenInterest ($this->extend($request, $params));
            //
            //     {
            //         "status" => "ok",
            //         "data" => array(
            //             {
            //                 "volume" => 7192610.000000000000000000,
            //                 "amount" => 7192.610000000000000000,
            //                 "symbol" => "BTC",
            //                 "value" => 134654290.332000000000000000,
            //                 "contract_code" => "BTC-USDT",
            //                 "trade_amount" => 70692.804,
            //                 "trade_volume" => 70692804,
            //                 "trade_turnover" => 1379302592.9518,
            //                 "business_type" => "swap",
            //                 "pair" => "BTC-USDT",
            //                 "contract_type" => "swap",
            //                 "trade_partition" => "USDT"
            //             }
            //         ),
            //         "ts" => 1664336503144
            //     }
            //
        }
        $data = $this->safe_list($response, 'data', array());
        return $this->parse_open_interests($data, $symbols);
    }

    public function fetch_open_interest(string $symbol, $params = array ()) {
        /**
         * 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 {string} $symbol Unified CCXT $market $symbol
         * @param {array} [$params] exchange specific parameters
         * @return {array} an open interest structurearray(@link https://docs.ccxt.com/#/?id=open-interest-structure)
         */
        $this->load_markets();
        $market = $this->market($symbol);
        if (!$market['contract']) {
            throw new BadRequest($this->id . ' fetchOpenInterest() supports contract markets only');
        }
        if ($market['option']) {
            throw new NotSupported($this->id . ' fetchOpenInterest() does not currently support option markets');
        }
        $request = array(
            'contract_code' => $market['id'],
        );
        $response = null;
        if ($market['future']) {
            $request['contract_type'] = $this->safe_string($market['info'], 'contract_type');
            $request['symbol'] = $market['baseId'];
            // COIN-M futures
            $response = $this->contractPublicGetApiV1ContractOpenInterest ($this->extend($request, $params));
        } elseif ($market['linear']) {
            $request['contract_type'] = 'swap';
            // USDT-M
            $response = $this->contractPublicGetLinearSwapApiV1SwapOpenInterest ($this->extend($request, $params));
        } else {
            // COIN-M swaps
            $response = $this->contractPublicGetSwapApiV1SwapOpenInterest ($this->extend($request, $params));
        }
        //
        // USDT-M contractPublicGetLinearSwapApiV1SwapOpenInterest
        //
        //     {
        //         "status" => "ok",
        //         "data" => array(
        //             {
        //                 "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" => array(
        //             {
        //                 "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" => array(
        //             {
        //                 "volume" => 118850.000000000000000000,
        //                 "amount" => 635.502025211544374189,
        //                 "symbol" => "BTC",
        //                 "contract_type" => "this_week",
        //                 "contract_code" => "BTC220930",
        //                 "trade_amount" => 1470.9400749347598691119206024033947897351,
        //                 "trade_volume" => 286286,
        //                 "trade_turnover" => 28628600.000000000000000000
        //             }
        //         ),
        //         "ts" => 1664337928805
        //     }
        //
        $data = $this->safe_value($response, 'data', array());
        $openInterest = $this->parse_open_interest($data[0], $market);
        $timestamp = $this->safe_integer($response, 'ts');
        $openInterest['timestamp'] = $timestamp;
        $openInterest['datetime'] = $this->iso8601($timestamp);
        return $openInterest;
    }

    public function parse_open_interest($interest, ?array $market = null) {
        //
        // 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" => "this_week",
        //         "contract_code" => "BTC220930",
        //         "trade_amount" => 1470.9400749347598691119206024033947897351,
        //         "trade_volume" => 286286,
        //         "trade_turnover" => 28628600.000000000000000000
        //     }
        //
        $timestamp = $this->safe_integer($interest, 'ts');
        $amount = $this->safe_number($interest, 'volume');
        $value = $this->safe_number($interest, 'value');
        $marketId = $this->safe_string($interest, 'contract_code');
        return $this->safe_open_interest(array(
            'symbol' => $this->safe_symbol($marketId, $market),
            'baseVolume' => $amount,  // deprecated
            'quoteVolume' => $value,  // deprecated
            'openInterestAmount' => $amount,
            'openInterestValue' => $value,
            'timestamp' => $timestamp,
            'datetime' => $this->iso8601($timestamp),
            'info' => $interest,
        ), $market);
    }

    public function borrow_isolated_margin(string $symbol, string $code, float $amount, $params = array ()) {
        /**
         * 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 {string} $symbol unified $market $symbol, required for isolated margin
         * @param {string} $code unified $currency $code of the $currency to borrow
         * @param {float} $amount the $amount to borrow
         * @param {array} [$params] extra parameters specific to the exchange API endpoint
         * @return {array} a ~@link https://docs.ccxt.com/#/?id=margin-loan-structure margin loan structure~
         */
        $this->load_markets();
        $currency = $this->currency($code);
        $market = $this->market($symbol);
        $request = array(
            'currency' => $currency['id'],
            'amount' => $this->currency_to_precision($code, $amount),
            'symbol' => $market['id'],
        );
        $response = $this->privatePostMarginOrders ($this->extend($request, $params));
        //
        // Isolated
        //
        //     {
        //         "data" => 1000
        //     }
        //
        $transaction = $this->parse_margin_loan($response, $currency);
        return $this->extend($transaction, array(
            'amount' => $amount,
            'symbol' => $symbol,
        ));
    }

    public function borrow_cross_margin(string $code, float $amount, $params = array ()) {
        /**
         * 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 {string} $code unified $currency $code of the $currency to borrow
         * @param {float} $amount the $amount to borrow
         * @param {array} [$params] extra parameters specific to the exchange API endpoint
         * @return {array} a ~@link https://docs.ccxt.com/#/?id=margin-loan-structure margin loan structure~
         */
        $this->load_markets();
        $currency = $this->currency($code);
        $request = array(
            'currency' => $currency['id'],
            'amount' => $this->currency_to_precision($code, $amount),
        );
        $response = $this->privatePostCrossMarginOrders ($this->extend($request, $params));
        //
        // Cross
        //
        //     {
        //         "status" => "ok",
        //         "data" => null
        //     }
        //
        $transaction = $this->parse_margin_loan($response, $currency);
        return $this->extend($transaction, array(
            'amount' => $amount,
        ));
    }

    public function repay_isolated_margin(string $symbol, string $code, $amount, $params = array ()) {
        /**
         * repay borrowed margin and interest
         *
         * @see https://huobiapi.github.io/docs/spot/v1/en/#repay-margin-$loan-cross-isolated
         *
         * @param {string} $symbol unified market $symbol
         * @param {string} $code unified $currency $code of the $currency to repay
         * @param {float} $amount the $amount to repay
         * @param {array} [$params] extra parameters specific to the exchange API endpoint
         * @return {array} a ~@link https://docs.ccxt.com/#/?id=margin-$loan-structure margin $loan structure~
         */
        $this->load_markets();
        $currency = $this->currency($code);
        $accountId = $this->fetch_account_id_by_type('spot', 'isolated', $symbol, $params);
        $request = array(
            'currency' => $currency['id'],
            'amount' => $this->currency_to_precision($code, $amount),
            'accountId' => $accountId,
        );
        $response = $this->v2PrivatePostAccountRepayment ($this->extend($request, $params));
        //
        //     {
        //         "code":200,
        //         "data" => array(
        //             {
        //                 "repayId":1174424,
        //                 "repayTime":1600747722018
        //             }
        //         )
        //     }
        //
        $data = $this->safe_value($response, 'Data', array());
        $loan = $this->safe_value($data, 0);
        $transaction = $this->parse_margin_loan($loan, $currency);
        return $this->extend($transaction, array(
            'amount' => $amount,
            'symbol' => $symbol,
        ));
    }

    public function repay_cross_margin(string $code, $amount, $params = array ()) {
        /**
         * repay borrowed margin and interest
         *
         * @see https://huobiapi.github.io/docs/spot/v1/en/#repay-margin-$loan-cross-isolated
         *
         * @param {string} $code unified $currency $code of the $currency to repay
         * @param {float} $amount the $amount to repay
         * @param {array} [$params] extra parameters specific to the exchange API endpoint
         * @return {array} a ~@link https://docs.ccxt.com/#/?id=margin-$loan-structure margin $loan structure~
         */
        $this->load_markets();
        $currency = $this->currency($code);
        $accountId = $this->fetch_account_id_by_type('spot', 'cross', null, $params);
        $request = array(
            'currency' => $currency['id'],
            'amount' => $this->currency_to_precision($code, $amount),
            'accountId' => $accountId,
        );
        $response = $this->v2PrivatePostAccountRepayment ($this->extend($request, $params));
        //
        //     {
        //         "code":200,
        //         "data" => array(
        //             {
        //                 "repayId":1174424,
        //                 "repayTime":1600747722018
        //             }
        //         )
        //     }
        //
        $data = $this->safe_value($response, 'Data', array());
        $loan = $this->safe_value($data, 0);
        $transaction = $this->parse_margin_loan($loan, $currency);
        return $this->extend($transaction, array(
            'amount' => $amount,
        ));
    }

    public function parse_margin_loan($info, ?array $currency = null) {
        //
        // borrowMargin cross
        //
        //     {
        //         "status" => "ok",
        //         "data" => null
        //     }
        //
        // borrowMargin isolated
        //
        //     {
        //         "data" => 1000
        //     }
        //
        // repayMargin
        //
        //     {
        //         "repayId":1174424,
        //         "repayTime":1600747722018
        //     }
        //
        $timestamp = $this->safe_integer($info, 'repayTime');
        return array(
            'id' => $this->safe_string_2($info, 'repayId', 'data'),
            'currency' => $this->safe_currency_code(null, $currency),
            'amount' => null,
            'symbol' => null,
            'timestamp' => $timestamp,
            'datetime' => $this->iso8601($timestamp),
            'info' => $info,
        );
    }

    public function fetch_settlement_history(?string $symbol = null, ?int $since = null, ?int $limit = null, $params = array ()) {
        /**
         * Fetches historical settlement records
         *
         * @see https://huobiapi.github.io/docs/dm/v1/en/#query-historical-settlement-records-of-the-platform-interface
         * @see https://huobiapi.github.io/docs/coin_margined_swap/v1/en/#query-historical-settlement-records-of-the-platform-interface
         * @see https://huobiapi.github.io/docs/usdt_swap/v1/en/#general-query-historical-settlement-records-of-the-platform-interface
         *
         * @param {string} $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 {array} [$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 null
         * @return {array[]} a list of ~@link https://docs.ccxt.com/#/?id=settlement-history-structure settlement history objects~
         */
        if ($symbol === null) {
            throw new ArgumentsRequired($this->id . ' fetchSettlementHistory() requires a $symbol argument');
        }
        $until = $this->safe_integer($params, 'until');
        $params = $this->omit($params, array( 'until' ));
        $market = $this->market($symbol);
        $request = array();
        if ($market['future']) {
            $request['symbol'] = $market['baseId'];
        } else {
            $request['contract_code'] = $market['id'];
        }
        if ($since !== null) {
            $request['start_at'] = $since;
        }
        if ($limit !== null) {
            $request['page_size'] = $limit;
        }
        if ($until !== null) {
            $request['end_at'] = $until;
        }
        $response = null;
        if ($market['swap']) {
            if ($market['linear']) {
                $response = $this->contractPublicGetLinearSwapApiV1SwapSettlementRecords ($this->extend($request, $params));
            } else {
                $response = $this->contractPublicGetSwapApiV1SwapSettlementRecords ($this->extend($request, $params));
            }
        } else {
            $response = $this->contractPublicGetApiV1ContractSettlementRecords ($this->extend($request, $params));
        }
        //
        // linear swap, coin-m swap
        //
        //    {
        //        "status" => "ok",
        //        "data" => {
        //        "total_page" => 14,
        //        "current_page" => 1,
        //        "total_size" => 270,
        //        "settlement_record" => array(
        //            array(
        //                "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" => array(
        //                array(
        //                    "symbol" => "FIL",
        //                    "settlement_time" => 1652342400000,
        //                    "clawback_ratio" => 0E-18,
        //                    "list" => array(
        //                        array(
        //                            "contract_code" => "FIL220513",
        //                            "settlement_price" => 7.016000000000000000,
        //                            "settlement_type" => "settlement"
        //                        ),
        //                        ...
        //                    )
        //                ),
        //            )
        //        }
        //    }
        //
        $data = $this->safe_value($response, 'data');
        $settlementRecord = $this->safe_value($data, 'settlement_record');
        $settlements = $this->parse_settlements($settlementRecord, $market);
        return $this->sort_by($settlements, 'timestamp');
    }

    public function fetch_deposit_withdraw_fees(?array $codes = null, $params = array ()) {
        /**
         * fetch deposit and withdraw fees
         *
         * @see https://huobiapi.github.io/docs/spot/v1/en/#get-all-supported-currencies-v2
         *
         * @param {string[]|null} $codes list of unified currency $codes
         * @param {array} [$params] extra parameters specific to the exchange API endpoint
         * @return {array[]} a list of ~@link https://docs.ccxt.com/#/?id=fee-structure fees structures~
         */
        $this->load_markets();
        $response = $this->spotPublicGetV2ReferenceCurrencies ($params);
        //
        //    {
        //        "code" => 200,
        //        "data" => array(
        //            {
        //                "currency" => "sxp",
        //                "assetType" => "1",
        //                "chains" => array(
        //                    {
        //                        "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 = $this->safe_list($response, 'data');
        return $this->parse_deposit_withdraw_fees($data, $codes, 'currency');
    }

    public function parse_deposit_withdraw_fee($fee, ?array $currency = null) {
        //
        //            {
        //              "currency" => "sxp",
        //              "assetType" => "1",
        //              "chains" => array(
        //                  {
        //                      "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 = $this->safe_value($fee, 'chains', array());
        $result = $this->deposit_withdraw_fee($fee);
        for ($j = 0; $j < count($chains); $j++) {
            $chainEntry = $chains[$j];
            $networkId = $this->safe_string($chainEntry, 'chain');
            $withdrawFeeType = $this->safe_string($chainEntry, 'withdrawFeeType');
            $networkCode = $this->network_id_to_code($networkId);
            $withdrawFee = null;
            $withdrawResult = null;
            if ($withdrawFeeType === 'fixed') {
                $withdrawFee = $this->safe_number($chainEntry, 'transactFeeWithdraw');
                $withdrawResult = array(
                    'fee' => $withdrawFee,
                    'percentage' => false,
                );
            } else {
                $withdrawFee = $this->safe_number($chainEntry, 'transactFeeRateWithdraw');
                $withdrawResult = array(
                    'fee' => $withdrawFee,
                    'percentage' => true,
                );
            }
            $result['networks'][$networkCode] = array(
                'withdraw' => $withdrawResult,
                'deposit' => array(
                    'fee' => null,
                    'percentage' => null,
                ),
            );
            $result = $this->assign_default_deposit_withdraw_fees($result, $currency);
        }
        return $result;
    }

    public function parse_settlements($settlements, $market) {
        //
        // linear swap, coin-m swap, fetchSettlementHistory
        //
        //    array(
        //        array(
        //            "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
        //
        //    array(
        //        array(
        //            "symbol" => "FIL",
        //            "settlement_time" => 1652342400000,
        //            "clawback_ratio" => 0E-18,
        //            "list" => array(
        //                array(
        //                    "contract_code" => "FIL220513",
        //                    "settlement_price" => 7.016000000000000000,
        //                    "settlement_type" => "settlement"
        //                ),
        //                ...
        //            )
        //        ),
        //    )
        //
        $result = array();
        for ($i = 0; $i < count($settlements); $i++) {
            $settlement = $settlements[$i];
            $list = $this->safe_value($settlement, 'list');
            if ($list !== null) {
                $timestamp = $this->safe_integer($settlement, 'settlement_time');
                $timestampDetails = array(
                    'timestamp' => $timestamp,
                    'datetime' => $this->iso8601($timestamp),
                );
                for ($j = 0; $j < count($list); $j++) {
                    $item = $list[$j];
                    $parsedSettlement = $this->parse_settlement($item, $market);
                    $result[] = $this->extend($parsedSettlement, $timestampDetails);
                }
            } else {
                $result[] = $this->parse_settlement($settlements[$i], $market);
            }
        }
        return $result;
    }

    public function parse_settlement($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 = $this->safe_integer($settlement, 'settlement_time');
        $marketId = $this->safe_string($settlement, 'contract_code');
        return array(
            'info' => $settlement,
            'symbol' => $this->safe_symbol($marketId, $market),
            'price' => $this->safe_number($settlement, 'settlement_price'),
            'timestamp' => $timestamp,
            'datetime' => $this->iso8601($timestamp),
        );
    }

    public function fetch_liquidations(string $symbol, ?int $since = null, ?int $limit = null, $params = array ()) {
        /**
         * retrieves the public liquidations of a trading pair
         *
         * @see https://huobiapi.github.io/docs/usdt_swap/v1/en/#general-query-liquidation-orders-new
         * @see https://huobiapi.github.io/docs/coin_margined_swap/v1/en/#query-liquidation-orders-new
         * @see https://huobiapi.github.io/docs/dm/v1/en/#query-liquidation-order-information-new
         *
         * @param {string} $symbol unified CCXT $market $symbol
         * @param {int} [$since] the earliest time in ms to fetch liquidations for
         * @param {int} [$limit] the maximum number of liquidation structures to retrieve
         * @param {array} [$params] exchange specific parameters for the huobi api endpoint
         * @param {int} [$params->until] timestamp in ms of the latest liquidation
         * @param {int} [$params->tradeType] default 0, linear swap 0 => all liquidated orders, 5 => liquidated longs; 6 => liquidated shorts, inverse swap and future 0 => filled liquidated orders, 5 => liquidated close orders, 6 => liquidated open orders
         * @return {array} an array of ~@link https://docs.ccxt.com/#/?id=liquidation-structure liquidation structures~
         */
        $this->load_markets();
        $market = $this->market($symbol);
        $tradeType = $this->safe_integer($params, 'trade_type', 0);
        $request = array(
            'trade_type' => $tradeType,
        );
        if ($since !== null) {
            $request['start_time'] = $since;
        }
        list($request, $params) = $this->handle_until_option('end_time', $request, $params);
        $response = null;
        if ($market['swap']) {
            $request['contract'] = $market['id'];
            if ($market['linear']) {
                $response = $this->contractPublicGetLinearSwapApiV3SwapLiquidationOrders ($this->extend($request, $params));
            } else {
                $response = $this->contractPublicGetSwapApiV3SwapLiquidationOrders ($this->extend($request, $params));
            }
        } elseif ($market['future']) {
            $request['symbol'] = $market['id'];
            $response = $this->contractPublicGetApiV3ContractLiquidationOrders ($this->extend($request, $params));
        } else {
            throw new NotSupported($this->id . ' fetchLiquidations() does not support ' . $market['type'] . ' orders');
        }
        //
        //     {
        //         "code" => 200,
        //         "msg" => "",
        //         "data" => array(
        //             {
        //                 "query_id" => 452057,
        //                 "contract_code" => "BTC-USDT-211210",
        //                 "symbol" => "USDT",
        //                 "direction" => "sell",
        //                 "offset" => "close",
        //                 "volume" => 479.000000000000000000,
        //                 "price" => 51441.700000000000000000,
        //                 "created_at" => 1638593647864,
        //                 "amount" => 0.479000000000000000,
        //                 "trade_turnover" => 24640.574300000000000000,
        //                 "business_type" => "futures",
        //                 "pair" => "BTC-USDT"
        //             }
        //         ),
        //         "ts" => 1604312615051
        //     }
        //
        $data = $this->safe_list($response, 'data', array());
        return $this->parse_liquidations($data, $market, $since, $limit);
    }

    public function parse_liquidation($liquidation, ?array $market = null) {
        //
        //     {
        //         "query_id" => 452057,
        //         "contract_code" => "BTC-USDT-211210",
        //         "symbol" => "USDT",
        //         "direction" => "sell",
        //         "offset" => "close",
        //         "volume" => 479.000000000000000000,
        //         "price" => 51441.700000000000000000,
        //         "created_at" => 1638593647864,
        //         "amount" => 0.479000000000000000,
        //         "trade_turnover" => 24640.574300000000000000,
        //         "business_type" => "futures",
        //         "pair" => "BTC-USDT"
        //     }
        //
        $marketId = $this->safe_string($liquidation, 'contract_code');
        $timestamp = $this->safe_integer($liquidation, 'created_at');
        return $this->safe_liquidation(array(
            'info' => $liquidation,
            'symbol' => $this->safe_symbol($marketId, $market),
            'contracts' => $this->safe_number($liquidation, 'volume'),
            'contractSize' => $this->safe_number($market, 'contractSize'),
            'price' => $this->safe_number($liquidation, 'price'),
            'side' => $this->safe_string_lower($liquidation, 'direction'),
            'baseValue' => $this->safe_number($liquidation, 'amount'),
            'quoteValue' => $this->safe_number($liquidation, 'trade_turnover'),
            'timestamp' => $timestamp,
            'datetime' => $this->iso8601($timestamp),
        ));
    }

    public function close_position(string $symbol, ?string $side = null, $params = array ()): array {
        /**
         * closes open positions for a contract $market, requires 'amount' in $params, unlike other exchanges
         *
         * @see https://huobiapi.github.io/docs/usdt_swap/v1/en/#isolated-place-lightning-close-order  // USDT-M (isolated)
         * @see https://huobiapi.github.io/docs/usdt_swap/v1/en/#cross-place-lightning-close-position  // USDT-M (cross)
         * @see https://huobiapi.github.io/docs/coin_margined_swap/v1/en/#place-lightning-close-order  // Coin-M swap
         * @see https://huobiapi.github.io/docs/dm/v1/en/#place-flash-close-order                      // Coin-M futures
         *
         * @param {string} $symbol unified CCXT $market $symbol
         * @param {string} $side 'buy' or 'sell', the $side of the closing order, opposite $side side
         * @param {array} [$params] extra parameters specific to the okx api endpoint
         * @param {string} [$params->clientOrderId] client needs to provide unique API and have to maintain the API themselves afterwards. [1, 9223372036854775807]
         * @param {array} [$params->marginMode] 'cross' or 'isolated', required for linear markets
         *
         * EXCHANGE SPECIFIC PARAMETERS
         * @param {number} [$params->amount] order quantity
         * @param {string} [$params->order_price_type] 'lightning' by default, 'lightning_fok' => lightning fok type, 'lightning_ioc' => lightning ioc type 'market' by default, 'market' => $market order type, 'lightning_fok' => lightning
         * @return {array} ~@link https://docs.ccxt.com/#/?id=position-structure an order structure~
         */
        $this->load_markets();
        $market = $this->market($symbol);
        $clientOrderId = $this->safe_string($params, 'clientOrderId');
        if (!$market['contract']) {
            throw new BadRequest($this->id . ' closePosition() $symbol supports contract markets only');
        }
        $this->check_required_argument('closePosition', $side, 'side');
        $request = array(
            'contract_code' => $market['id'],
            'direction' => $side,
        );
        if ($clientOrderId !== null) {
            $request['client_order_id'] = $clientOrderId;
        }
        if ($market['inverse']) {
            $amount = $this->safe_string_2($params, 'volume', 'amount');
            if ($amount === null) {
                throw new ArgumentsRequired($this->id . ' closePosition () requires an extra argument $params["amount"] for inverse markets');
            }
            $request['volume'] = $this->amount_to_precision($symbol, $amount);
        }
        $params = $this->omit($params, array( 'clientOrderId', 'volume', 'amount' ));
        $response = null;
        if ($market['inverse']) {  // Coin-M
            if ($market['swap']) {
                $response = $this->contractPrivatePostSwapApiV1SwapLightningClosePosition ($this->extend($request, $params));
            } else {  // future
                $response = $this->contractPrivatePostApiV1LightningClosePosition ($this->extend($request, $params));
            }
        } else {  // USDT-M
            $marginMode = null;
            list($marginMode, $params) = $this->handle_margin_mode_and_params('closePosition', $params, 'cross');
            if ($marginMode === 'cross') {
                $response = $this->contractPrivatePostLinearSwapApiV1SwapCrossLightningClosePosition ($this->extend($request, $params));
            } else {  // isolated
                $response = $this->contractPrivatePostLinearSwapApiV1SwapLightningClosePosition ($this->extend($request, $params));
            }
        }
        return $this->parse_order($response, $market);
    }

    public function set_position_mode(bool $hedged, ?string $symbol = null, $params = array ()) {
        /**
         * set $hedged to true or false
         *
         * @see https://huobiapi.github.io/docs/usdt_swap/v1/en/#isolated-switch-position-mode
         * @see https://huobiapi.github.io/docs/usdt_swap/v1/en/#cross-switch-position-mode
         *
         * @param {bool} $hedged set to true to for $hedged mode, must be set separately for each $market in isolated margin mode, only valid for linear markets
         * @param {string} [$symbol] unified $market $symbol, required for isolated margin mode
         * @param {array} [$params] extra parameters specific to the exchange API endpoint
         * @param {string} [$params->marginMode] "cross" (default) or "isolated"
         * @return {array} $response from the exchange
         */
        $this->load_markets();
        $posMode = $hedged ? 'dual_side' : 'single_side';
        $market = null;
        if ($symbol !== null) {
            $market = $this->market($symbol);
        }
        $marginMode = null;
        list($marginMode, $params) = $this->handle_margin_mode_and_params('setPositionMode', $params, 'cross');
        $request = array(
            'position_mode' => $posMode,
        );
        $response = null;
        if (($market !== null) && ($market['inverse'])) {
            throw new BadRequest($this->id . ' setPositionMode can only be used for linear markets');
        }
        if ($marginMode === 'isolated') {
            if ($symbol === null) {
                throw new ArgumentsRequired($this->id . ' setPositionMode requires a $symbol argument for isolated margin mode');
            }
            $request['margin_account'] = $market['id'];
            $response = $this->contractPrivatePostLinearSwapApiV1SwapSwitchPositionMode ($this->extend($request, $params));
            //
            //    {
            //        "status" => "ok",
            //        "data" => array(
            //            {
            //                "margin_account" => "BTC-USDT",
            //                "position_mode" => "single_side"
            //            }
            //        ),
            //        "ts" => 1566899973811
            //    }
            //
        } else {
            $request['margin_account'] = 'USDT';
            $response = $this->contractPrivatePostLinearSwapApiV1SwapCrossSwitchPositionMode ($this->extend($request, $params));
            //
            //    {
            //        "status" => "ok",
            //        "data" => array(
            //            {
            //                "margin_account" => "USDT",
            //                "position_mode" => "single_side"
            //            }
            //        ),
            //        "ts" => 1566899973811
            //    }
            //
        }
        return $response;
    }
}
