UNPKG

astro-perp-ccxt-dev

Version:

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

5,152 lines 242 kB
'use strict';

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

// ----------------------------------------------------------------------------
//  ---------------------------------------------------------------------------
/**
 * @class kucoin
 * @augments Exchange
 */
class kucoin extends kucoin$1 {
    describe() {
        return this.deepExtend(super.describe(), {
            'id': 'kucoin',
            'name': 'KuCoin',
            'countries': ['SC'],
            'rateLimit': 10,
            'version': 'v2',
            'certified': true,
            'pro': true,
            'comment': 'Platform 2.0',
            'quoteJsonNumbers': false,
            'has': {
                'CORS': undefined,
                'spot': true,
                'margin': true,
                'swap': false,
                'future': false,
                'option': false,
                'borrowCrossMargin': true,
                'borrowIsolatedMargin': true,
                'cancelAllOrders': true,
                'cancelOrder': true,
                'closeAllPositions': false,
                'closePosition': false,
                'createDepositAddress': true,
                'createMarketBuyOrderWithCost': true,
                'createMarketOrderWithCost': true,
                'createMarketSellOrderWithCost': true,
                'createOrder': true,
                'createOrders': true,
                'createPostOnlyOrder': true,
                'createStopLimitOrder': true,
                'createStopMarketOrder': true,
                'createStopOrder': true,
                'createTriggerOrder': true,
                'editOrder': true,
                'fetchAccounts': true,
                'fetchBalance': true,
                'fetchBorrowInterest': true,
                'fetchBorrowRateHistories': true,
                'fetchBorrowRateHistory': true,
                'fetchClosedOrders': true,
                'fetchCrossBorrowRate': false,
                'fetchCrossBorrowRates': false,
                'fetchCurrencies': true,
                'fetchDepositAddress': true,
                'fetchDepositAddresses': false,
                'fetchDepositAddressesByNetwork': true,
                'fetchDeposits': true,
                'fetchDepositWithdrawFee': true,
                'fetchDepositWithdrawFees': true,
                'fetchFundingHistory': false,
                'fetchFundingRate': false,
                'fetchFundingRateHistory': false,
                'fetchFundingRates': false,
                'fetchIndexOHLCV': false,
                'fetchIsolatedBorrowRate': false,
                'fetchIsolatedBorrowRates': false,
                'fetchL3OrderBook': true,
                'fetchLedger': true,
                'fetchLeverageTiers': false,
                'fetchMarginAdjustmentHistory': false,
                'fetchMarginMode': false,
                'fetchMarketLeverageTiers': false,
                'fetchMarkets': true,
                'fetchMarkOHLCV': false,
                'fetchMarkPrice': true,
                'fetchMarkPrices': true,
                'fetchMyTrades': true,
                'fetchOHLCV': true,
                'fetchOpenInterest': false,
                'fetchOpenInterestHistory': false,
                'fetchOpenOrders': true,
                'fetchOrder': true,
                'fetchOrderBook': true,
                'fetchOrderBooks': false,
                'fetchOrdersByStatus': true,
                'fetchOrderTrades': true,
                'fetchPositionHistory': false,
                'fetchPositionMode': false,
                'fetchPositionsHistory': false,
                'fetchPremiumIndexOHLCV': false,
                'fetchStatus': true,
                'fetchTicker': true,
                'fetchTickers': true,
                'fetchTime': true,
                'fetchTrades': true,
                'fetchTradingFee': true,
                'fetchTradingFees': false,
                'fetchTransactionFee': true,
                'fetchTransfers': false,
                'fetchWithdrawals': true,
                'repayCrossMargin': true,
                'repayIsolatedMargin': true,
                'setLeverage': true,
                'setMarginMode': false,
                'setPositionMode': false,
                'signIn': false,
                'transfer': true,
                'withdraw': true,
            },
            'urls': {
                'logo': 'https://user-images.githubusercontent.com/51840849/87295558-132aaf80-c50e-11ea-9801-a2fb0c57c799.jpg',
                'referral': 'https://www.kucoin.com/ucenter/signup?rcode=E5wkqe',
                'api': {
                    'public': 'https://api.kucoin.com',
                    'private': 'https://api.kucoin.com',
                    'futuresPrivate': 'https://api-futures.kucoin.com',
                    'futuresPublic': 'https://api-futures.kucoin.com',
                    'webExchange': 'https://kucoin.com/_api',
                    'broker': 'https://api-broker.kucoin.com',
                    'earn': 'https://api.kucoin.com',
                },
                'www': 'https://www.kucoin.com',
                'doc': [
                    'https://docs.kucoin.com',
                ],
            },
            'requiredCredentials': {
                'apiKey': true,
                'secret': true,
                'password': true,
            },
            'api': {
                // level VIP0
                // Spot => 3000/30s => 100/s
                // Weight = x => 100/(100/x) = x
                // Futures Management Public => 2000/30s => 200/3/s
                // Weight = x => 100/(200/3/x) = x*1.5
                'public': {
                    'get': {
                        // spot trading
                        'currencies': 4.5,
                        'currencies/{currency}': 4.5,
                        'symbols': 6,
                        'market/orderbook/level1': 3,
                        'market/allTickers': 22.5,
                        'market/stats': 22.5,
                        'markets': 4.5,
                        'market/orderbook/level{level}_{limit}': 6,
                        'market/orderbook/level2_20': 3,
                        'market/orderbook/level2_100': 6,
                        'market/histories': 4.5,
                        'market/candles': 4.5,
                        'prices': 4.5,
                        'timestamp': 4.5,
                        'status': 4.5,
                        // margin trading
                        'mark-price/{symbol}/current': 3,
                        'mark-price/all-symbols': 3,
                        'margin/config': 25,
                        'announcements': 20, // 20W
                    },
                    'post': {
                        // ws
                        'bullet-public': 15, // 10PW
                    },
                },
                'private': {
                    'get': {
                        // account
                        'user-info': 30,
                        'accounts': 7.5,
                        'accounts/{accountId}': 7.5,
                        'accounts/ledgers': 3,
                        'hf/accounts/ledgers': 2,
                        'hf/margin/account/ledgers': 2,
                        'transaction-history': 3,
                        'sub/user': 30,
                        'sub-accounts/{subUserId}': 22.5,
                        'sub-accounts': 30,
                        'sub/api-key': 30,
                        // funding
                        'margin/account': 40,
                        'margin/accounts': 15,
                        'isolated/accounts': 15,
                        'deposit-addresses': 7.5,
                        'deposits': 7.5,
                        'hist-deposits': 7.5,
                        'withdrawals': 30,
                        'hist-withdrawals': 30,
                        'withdrawals/quotas': 30,
                        'accounts/transferable': 30,
                        'transfer-list': 30,
                        'base-fee': 3,
                        'trade-fees': 3,
                        // spot trading
                        'market/orderbook/level{level}': 3,
                        'market/orderbook/level2': 3,
                        'market/orderbook/level3': 3,
                        'hf/accounts/opened': 2,
                        'hf/orders/active': 2,
                        'hf/orders/active/symbols': 2,
                        'hf/margin/order/active/symbols': 2,
                        'hf/orders/done': 2,
                        'hf/orders/{orderId}': 2,
                        'hf/orders/client-order/{clientOid}': 2,
                        'hf/orders/dead-cancel-all/query': 2,
                        'hf/fills': 2,
                        'orders': 2,
                        'limit/orders': 3,
                        'orders/{orderId}': 2,
                        'order/client-order/{clientOid}': 3,
                        'fills': 10,
                        'limit/fills': 20,
                        'stop-order': 8,
                        'stop-order/{orderId}': 3,
                        'stop-order/queryOrderByClientOid': 3,
                        'oco/order/{orderId}': 2,
                        'oco/order/details/{orderId}': 2,
                        'oco/client-order/{clientOid}': 2,
                        'oco/orders': 2,
                        // margin trading
                        'hf/margin/orders/active': 4,
                        'hf/margin/orders/done': 10,
                        'hf/margin/orders/{orderId}': 4,
                        'hf/margin/orders/client-order/{clientOid}': 5,
                        'hf/margin/fills': 5,
                        'etf/info': 25,
                        'margin/currencies': 20,
                        'risk/limit/strategy': 20,
                        'isolated/symbols': 20,
                        'margin/symbols': 5,
                        'isolated/account/{symbol}': 50,
                        'margin/borrow': 15,
                        'margin/repay': 15,
                        'margin/interest': 20,
                        'project/list': 10,
                        'project/marketInterestRate': 7.5,
                        'redeem/orders': 10,
                        'purchase/orders': 10,
                        // broker
                        'broker/api/rebase/download': 3,
                        'migrate/user/account/status': 3,
                        // affiliate
                        'affiliate/inviter/statistics': 30,
                    },
                    'post': {
                        // account
                        'sub/user/created': 22.5,
                        'sub/api-key': 30,
                        'sub/api-key/update': 45,
                        // funding
                        'deposit-addresses': 30,
                        'withdrawals': 7.5,
                        'accounts/universal-transfer': 6,
                        'accounts/sub-transfer': 45,
                        'accounts/inner-transfer': 15,
                        'transfer-out': 30,
                        'transfer-in': 30,
                        // spot trading
                        'hf/orders': 1,
                        'hf/orders/test': 1,
                        'hf/orders/sync': 1,
                        'hf/orders/multi': 1,
                        'hf/orders/multi/sync': 1,
                        'hf/orders/alter': 3,
                        'hf/orders/dead-cancel-all': 2,
                        'orders': 2,
                        'orders/test': 2,
                        'orders/multi': 3,
                        'stop-order': 2,
                        'oco/order': 2,
                        // margin trading
                        'hf/margin/order': 5,
                        'hf/margin/order/test': 5,
                        'margin/order': 5,
                        'margin/order/test': 5,
                        'margin/borrow': 15,
                        'margin/repay': 10,
                        'purchase': 15,
                        'redeem': 15,
                        'lend/purchase/update': 10,
                        // ws
                        'bullet-private': 10,
                        'position/update-user-leverage': 5,
                        'deposit-address/create': 20,
                    },
                    'delete': {
                        // account
                        'sub/api-key': 45,
                        // funding
                        'withdrawals/{withdrawalId}': 30,
                        // spot trading
                        'hf/orders/{orderId}': 1,
                        'hf/orders/sync/{orderId}': 1,
                        'hf/orders/client-order/{clientOid}': 1,
                        'hf/orders/sync/client-order/{clientOid}': 1,
                        'hf/orders/cancel/{orderId}': 2,
                        'hf/orders': 2,
                        'hf/orders/cancelAll': 30,
                        'orders/{orderId}': 3,
                        'order/client-order/{clientOid}': 5,
                        'orders': 20,
                        'stop-order/{orderId}': 3,
                        'stop-order/cancelOrderByClientOid': 5,
                        'stop-order/cancel': 3,
                        'oco/order/{orderId}': 3,
                        'oco/client-order/{clientOid}': 3,
                        'oco/orders': 3,
                        // margin trading
                        'hf/margin/orders/{orderId}': 5,
                        'hf/margin/orders/client-order/{clientOid}': 5,
                        'hf/margin/orders': 10, // 10SW
                    },
                },
                'futuresPublic': {
                    'get': {
                        'contracts/active': 4.5,
                        'contracts/{symbol}': 4.5,
                        'ticker': 3,
                        'level2/snapshot': 4.5,
                        'level2/depth20': 7.5,
                        'level2/depth100': 15,
                        'trade/history': 7.5,
                        'kline/query': 4.5,
                        'interest/query': 7.5,
                        'index/query': 3,
                        'mark-price/{symbol}/current': 4.5,
                        'premium/query': 4.5,
                        'trade-statistics': 4.5,
                        'funding-rate/{symbol}/current': 3,
                        'contract/funding-rates': 7.5,
                        'timestamp': 3,
                        'status': 6,
                        // ?
                        'level2/message/query': 1.3953,
                    },
                    'post': {
                        // ws
                        'bullet-public': 15, // 10PW
                    },
                },
                'futuresPrivate': {
                    'get': {
                        // account
                        'transaction-history': 3,
                        // funding
                        'account-overview': 7.5,
                        'account-overview-all': 9,
                        'transfer-list': 30,
                        // futures
                        'orders': 3,
                        'stopOrders': 9,
                        'recentDoneOrders': 7.5,
                        'orders/{orderId}': 7.5,
                        'orders/byClientOid': 7.5,
                        'fills': 7.5,
                        'recentFills': 4.5,
                        'openOrderStatistics': 15,
                        'position': 3,
                        'positions': 3,
                        'margin/maxWithdrawMargin': 15,
                        'contracts/risk-limit/{symbol}': 7.5,
                        'funding-history': 7.5, // 5FW
                    },
                    'post': {
                        // funding
                        'transfer-out': 30,
                        'transfer-in': 30,
                        // futures
                        'orders': 3,
                        'orders/test': 3,
                        'orders/multi': 4.5,
                        'position/margin/auto-deposit-status': 6,
                        'margin/withdrawMargin': 15,
                        'position/margin/deposit-margin': 6,
                        'position/risk-limit-level/change': 6,
                        // ws
                        'bullet-private': 15, // 10FW
                    },
                    'delete': {
                        'orders/{orderId}': 1.5,
                        'orders/client-order/{clientOid}': 1.5,
                        'orders': 45,
                        'stopOrders': 22.5, // 15FW
                    },
                },
                'webExchange': {
                    'get': {
                        'currency/currency/chain-info': 1, // this is temporary from webApi
                    },
                },
                'broker': {
                    'get': {
                        'broker/nd/info': 2,
                        'broker/nd/account': 2,
                        'broker/nd/account/apikey': 2,
                        'broker/nd/rebase/download': 3,
                        'asset/ndbroker/deposit/list': 1,
                        'broker/nd/transfer/detail': 1,
                        'broker/nd/deposit/detail': 1,
                        'broker/nd/withdraw/detail': 1,
                    },
                    'post': {
                        'broker/nd/transfer': 1,
                        'broker/nd/account': 3,
                        'broker/nd/account/apikey': 3,
                        'broker/nd/account/update-apikey': 3,
                    },
                    'delete': {
                        'broker/nd/account/apikey': 3,
                    },
                },
                'earn': {
                    'get': {
                        'otc-loan/loan': 1,
                        'otc-loan/accounts': 1,
                        'earn/redeem-preview': 7.5,
                        'earn/saving/products': 7.5,
                        'earn/hold-assets': 7.5,
                        'earn/promotion/products': 7.5,
                        'earn/kcs-staking/products': 7.5,
                        'earn/staking/products': 7.5,
                        'earn/eth-staking/products': 7.5, // 5EW
                    },
                    'post': {
                        'earn/orders': 7.5, // 5EW
                    },
                    'delete': {
                        'earn/orders': 7.5, // 5EW
                    },
                },
            },
            'timeframes': {
                '1m': '1min',
                '3m': '3min',
                '5m': '5min',
                '15m': '15min',
                '30m': '30min',
                '1h': '1hour',
                '2h': '2hour',
                '4h': '4hour',
                '6h': '6hour',
                '8h': '8hour',
                '12h': '12hour',
                '1d': '1day',
                '1w': '1week',
                '1M': '1month',
            },
            'precisionMode': number.TICK_SIZE,
            'exceptions': {
                'exact': {
                    'The order does not exist.': errors.OrderNotFound,
                    'order not exist': errors.OrderNotFound,
                    'order not exist.': errors.OrderNotFound,
                    'order_not_exist': errors.OrderNotFound,
                    'order_not_exist_or_not_allow_to_cancel': errors.InvalidOrder,
                    'Order size below the minimum requirement.': errors.InvalidOrder,
                    'The withdrawal amount is below the minimum requirement.': errors.ExchangeError,
                    'Unsuccessful! Exceeded the max. funds out-transfer limit': errors.InsufficientFunds,
                    'The amount increment is invalid.': errors.BadRequest,
                    'The quantity is below the minimum requirement.': errors.InvalidOrder,
                    '400': errors.BadRequest,
                    '401': errors.AuthenticationError,
                    '403': errors.NotSupported,
                    '404': errors.NotSupported,
                    '405': errors.NotSupported,
                    '415': errors.NotSupported,
                    '429': errors.RateLimitExceeded,
                    '500': errors.ExchangeNotAvailable,
                    '503': errors.ExchangeNotAvailable,
                    '101030': errors.PermissionDenied,
                    '103000': errors.InvalidOrder,
                    '130101': errors.BadRequest,
                    '130102': errors.ExchangeError,
                    '130103': errors.OrderNotFound,
                    '130104': errors.ExchangeError,
                    '130105': errors.InsufficientFunds,
                    '130106': errors.NotSupported,
                    '130107': errors.ExchangeError,
                    '130108': errors.OrderNotFound,
                    '130201': errors.PermissionDenied,
                    '130202': errors.ExchangeError,
                    '130203': errors.InsufficientFunds,
                    '130204': errors.BadRequest,
                    '130301': errors.InsufficientFunds,
                    '130302': errors.PermissionDenied,
                    '130303': errors.NotSupported,
                    '130304': errors.NotSupported,
                    '130305': errors.NotSupported,
                    '130306': errors.NotSupported,
                    '130307': errors.NotSupported,
                    '130308': errors.InvalidOrder,
                    '130309': errors.InvalidOrder,
                    '130310': errors.ExchangeError,
                    '130311': errors.InvalidOrder,
                    '130312': errors.InvalidOrder,
                    '130313': errors.InvalidOrder,
                    '130314': errors.InvalidOrder,
                    '130315': errors.NotSupported,
                    '126000': errors.ExchangeError,
                    '126001': errors.NotSupported,
                    '126002': errors.ExchangeError,
                    '126003': errors.InvalidOrder,
                    '126004': errors.ExchangeError,
                    '126005': errors.PermissionDenied,
                    '126006': errors.ExchangeError,
                    '126007': errors.ExchangeError,
                    '126009': errors.ExchangeError,
                    '126010': errors.ExchangeError,
                    '126011': errors.ExchangeError,
                    '126013': errors.InsufficientFunds,
                    '126015': errors.ExchangeError,
                    '126021': errors.NotSupported,
                    '126022': errors.InvalidOrder,
                    '126027': errors.InvalidOrder,
                    '126028': errors.InvalidOrder,
                    '126029': errors.InvalidOrder,
                    '126030': errors.InvalidOrder,
                    '126033': errors.InvalidOrder,
                    '126034': errors.InvalidOrder,
                    '126036': errors.InvalidOrder,
                    '126037': errors.ExchangeError,
                    '126038': errors.ExchangeError,
                    '126039': errors.ExchangeError,
                    '126041': errors.ExchangeError,
                    '126042': errors.ExchangeError,
                    '126043': errors.OrderNotFound,
                    '126044': errors.InvalidOrder,
                    '126045': errors.NotSupported,
                    '126046': errors.NotSupported,
                    '126047': errors.PermissionDenied,
                    '126048': errors.PermissionDenied,
                    '135005': errors.ExchangeError,
                    '135018': errors.ExchangeError,
                    '200004': errors.InsufficientFunds,
                    '210014': errors.InvalidOrder,
                    '210021': errors.InsufficientFunds,
                    '230003': errors.InsufficientFunds,
                    '260000': errors.InvalidAddress,
                    '260100': errors.InsufficientFunds,
                    '300000': errors.InvalidOrder,
                    '400000': errors.BadSymbol,
                    '400001': errors.AuthenticationError,
                    '400002': errors.InvalidNonce,
                    '400003': errors.AuthenticationError,
                    '400004': errors.AuthenticationError,
                    '400005': errors.AuthenticationError,
                    '400006': errors.AuthenticationError,
                    '400007': errors.AuthenticationError,
                    '400008': errors.NotSupported,
                    '400100': errors.InsufficientFunds,
                    '400200': errors.InvalidOrder,
                    '400330': errors.InvalidOrder,
                    '400350': errors.InvalidOrder,
                    '400370': errors.InvalidOrder,
                    '400400': errors.BadRequest,
                    '400401': errors.AuthenticationError,
                    '400500': errors.InvalidOrder,
                    '400600': errors.BadSymbol,
                    '400760': errors.InvalidOrder,
                    '401000': errors.BadRequest,
                    '408000': errors.BadRequest,
                    '411100': errors.AccountSuspended,
                    '415000': errors.BadRequest,
                    '400303': errors.PermissionDenied,
                    '500000': errors.ExchangeNotAvailable,
                    '260220': errors.InvalidAddress,
                    '600100': errors.InsufficientFunds,
                    '600101': errors.InvalidOrder,
                    '900014': errors.BadRequest, // {"code":"900014","msg":"Invalid chainId"}
                },
                'broad': {
                    'Exceeded the access frequency': errors.RateLimitExceeded,
                    'require more permission': errors.PermissionDenied,
                },
            },
            'fees': {
                'trading': {
                    'tierBased': true,
                    'percentage': true,
                    'taker': this.parseNumber('0.001'),
                    'maker': this.parseNumber('0.001'),
                    'tiers': {
                        'taker': [
                            [this.parseNumber('0'), this.parseNumber('0.001')],
                            [this.parseNumber('50'), this.parseNumber('0.001')],
                            [this.parseNumber('200'), this.parseNumber('0.0009')],
                            [this.parseNumber('500'), this.parseNumber('0.0008')],
                            [this.parseNumber('1000'), this.parseNumber('0.0007')],
                            [this.parseNumber('2000'), this.parseNumber('0.0007')],
                            [this.parseNumber('4000'), this.parseNumber('0.0006')],
                            [this.parseNumber('8000'), this.parseNumber('0.0005')],
                            [this.parseNumber('15000'), this.parseNumber('0.00045')],
                            [this.parseNumber('25000'), this.parseNumber('0.0004')],
                            [this.parseNumber('40000'), this.parseNumber('0.00035')],
                            [this.parseNumber('60000'), this.parseNumber('0.0003')],
                            [this.parseNumber('80000'), this.parseNumber('0.00025')],
                        ],
                        'maker': [
                            [this.parseNumber('0'), this.parseNumber('0.001')],
                            [this.parseNumber('50'), this.parseNumber('0.0009')],
                            [this.parseNumber('200'), this.parseNumber('0.0007')],
                            [this.parseNumber('500'), this.parseNumber('0.0005')],
                            [this.parseNumber('1000'), this.parseNumber('0.0003')],
                            [this.parseNumber('2000'), this.parseNumber('0')],
                            [this.parseNumber('4000'), this.parseNumber('0')],
                            [this.parseNumber('8000'), this.parseNumber('0')],
                            [this.parseNumber('15000'), this.parseNumber('-0.00005')],
                            [this.parseNumber('25000'), this.parseNumber('-0.00005')],
                            [this.parseNumber('40000'), this.parseNumber('-0.00005')],
                            [this.parseNumber('60000'), this.parseNumber('-0.00005')],
                            [this.parseNumber('80000'), this.parseNumber('-0.00005')],
                        ],
                    },
                },
                'funding': {
                    'tierBased': false,
                    'percentage': false,
                    'withdraw': {},
                    'deposit': {},
                },
            },
            'commonCurrencies': {
                'BIFI': 'BIFIF',
                'VAI': 'VAIOT',
                'WAX': 'WAXP',
                'ALT': 'APTOSLAUNCHTOKEN',
                'KALT': 'ALT',
                'FUD': 'FTX Users\' Debt',
            },
            'options': {
                'hf': undefined,
                'version': 'v1',
                'symbolSeparator': '-',
                'fetchMyTradesMethod': 'private_get_fills',
                'timeDifference': 0,
                'adjustForTimeDifference': false,
                'fetchCurrencies': {
                    'webApiEnable': true,
                    'webApiRetries': 1,
                    'webApiMuteFailure': true,
                },
                'fetchMarkets': {
                    'fetchTickersFees': true,
                },
                'withdraw': {
                    'includeFee': false,
                },
                // endpoint versions
                'versions': {
                    'public': {
                        'GET': {
                            // spot trading
                            'currencies': 'v3',
                            'currencies/{currency}': 'v3',
                            'symbols': 'v2',
                            'mark-price/all-symbols': 'v3',
                            'announcements': 'v3',
                        },
                    },
                    'private': {
                        'GET': {
                            // account
                            'user-info': 'v2',
                            'hf/margin/account/ledgers': 'v3',
                            'sub/user': 'v2',
                            'sub-accounts': 'v2',
                            // funding
                            'margin/accounts': 'v3',
                            'isolated/accounts': 'v3',
                            // 'deposit-addresses': 'v2',
                            'deposit-addresses': 'v1',
                            // spot trading
                            'market/orderbook/level2': 'v3',
                            'market/orderbook/level3': 'v3',
                            'market/orderbook/level{level}': 'v3',
                            'oco/order/{orderId}': 'v3',
                            'oco/order/details/{orderId}': 'v3',
                            'oco/client-order/{clientOid}': 'v3',
                            'oco/orders': 'v3',
                            // margin trading
                            'hf/margin/orders/active': 'v3',
                            'hf/margin/order/active/symbols': 'v3',
                            'hf/margin/orders/done': 'v3',
                            'hf/margin/orders/{orderId}': 'v3',
                            'hf/margin/orders/client-order/{clientOid}': 'v3',
                            'hf/margin/fills': 'v3',
                            'etf/info': 'v3',
                            'margin/currencies': 'v3',
                            'margin/borrow': 'v3',
                            'margin/repay': 'v3',
                            'margin/interest': 'v3',
                            'project/list': 'v3',
                            'project/marketInterestRate': 'v3',
                            'redeem/orders': 'v3',
                            'purchase/orders': 'v3',
                            'migrate/user/account/status': 'v3',
                            'margin/symbols': 'v3',
                            'affiliate/inviter/statistics': 'v2',
                            'asset/ndbroker/deposit/list': 'v1',
                        },
                        'POST': {
                            // account
                            'sub/user/created': 'v2',
                            // funding
                            'accounts/universal-transfer': 'v3',
                            'accounts/sub-transfer': 'v2',
                            'accounts/inner-transfer': 'v2',
                            'transfer-out': 'v3',
                            'deposit-address/create': 'v3',
                            // spot trading
                            'oco/order': 'v3',
                            // margin trading
                            'hf/margin/order': 'v3',
                            'hf/margin/order/test': 'v3',
                            'margin/borrow': 'v3',
                            'margin/repay': 'v3',
                            'purchase': 'v3',
                            'redeem': 'v3',
                            'lend/purchase/update': 'v3',
                            'position/update-user-leverage': 'v3',
                            'withdrawals': 'v3',
                        },
                        'DELETE': {
                            // account
                            // funding
                            // spot trading
                            'hf/margin/orders/{orderId}': 'v3',
                            'hf/margin/orders/client-order/{clientOid}': 'v3',
                            'hf/margin/orders': 'v3',
                            'oco/order/{orderId}': 'v3',
                            'oco/client-order/{clientOid}': 'v3',
                            'oco/orders': 'v3',
                            // margin trading
                        },
                    },
                    'futuresPrivate': {
                        'POST': {
                            'transfer-out': 'v3',
                        },
                    },
                },
                'partner': {
                    // the support for spot and future exchanges as separate settings
                    'spot': {
                        'id': 'ccxt',
                        'key': '9e58cc35-5b5e-4133-92ec-166e3f077cb8',
                    },
                    'future': {
                        'id': 'ccxtfutures',
                        'key': '1b327198-f30c-4f14-a0ac-918871282f15',
                    },
                    // exchange-wide settings are also supported
                    // 'id': 'ccxt'
                    // 'key': '9e58cc35-5b5e-4133-92ec-166e3f077cb8',
                },
                'accountsByType': {
                    'spot': 'trade',
                    'margin': 'margin',
                    'cross': 'margin',
                    'isolated': 'isolated',
                    'main': 'main',
                    'funding': 'main',
                    'future': 'contract',
                    'swap': 'contract',
                    'mining': 'pool',
                    'hf': 'trade_hf',
                },
                'networks': {
                    'BRC20': 'btc',
                    'BTCNATIVESEGWIT': 'bech32',
                    'ERC20': 'eth',
                    'TRC20': 'trx',
                    'HRC20': 'heco',
                    'MATIC': 'matic',
                    'KCC': 'kcc',
                    'SOL': 'sol',
                    'ALGO': 'algo',
                    'EOS': 'eos',
                    'BEP20': 'bsc',
                    'BEP2': 'bnb',
                    'ARBONE': 'arbitrum',
                    'AVAXX': 'avax',
                    'AVAXC': 'avaxc',
                    'TLOS': 'tlos',
                    'CFX': 'cfx',
                    'ACA': 'aca',
                    'OP': 'optimism',
                    'ONT': 'ont',
                    'GLMR': 'glmr',
                    'CSPR': 'cspr',
                    'KLAY': 'klay',
                    'XRD': 'xrd',
                    'RVN': 'rvn',
                    'NEAR': 'near',
                    'APT': 'aptos',
                    'ETHW': 'ethw',
                    'TON': 'ton',
                    'BCH': 'bch',
                    'BSV': 'bchsv',
                    'BCHA': 'bchabc',
                    'OSMO': 'osmo',
                    'NANO': 'nano',
                    'XLM': 'xlm',
                    'VET': 'vet',
                    'IOST': 'iost',
                    'ZIL': 'zil',
                    'XRP': 'xrp',
                    'TOMO': 'tomo',
                    'XMR': 'xmr',
                    'COTI': 'coti',
                    'XTZ': 'xtz',
                    'ADA': 'ada',
                    'WAX': 'waxp',
                    'THETA': 'theta',
                    'ONE': 'one',
                    'IOTEX': 'iotx',
                    'NULS': 'nuls',
                    'KSM': 'ksm',
                    'LTC': 'ltc',
                    'WAVES': 'waves',
                    'DOT': 'dot',
                    'STEEM': 'steem',
                    'QTUM': 'qtum',
                    'DOGE': 'doge',
                    'FIL': 'fil',
                    'XYM': 'xym',
                    'FLUX': 'flux',
                    'ATOM': 'atom',
                    'XDC': 'xdc',
                    'KDA': 'kda',
                    'ICP': 'icp',
                    'CELO': 'celo',
                    'LSK': 'lsk',
                    'VSYS': 'vsys',
                    'KAR': 'kar',
                    'XCH': 'xch',
                    'FLOW': 'flow',
                    'BAND': 'band',
                    'EGLD': 'egld',
                    'HBAR': 'hbar',
                    'XPR': 'xpr',
                    'AR': 'ar',
                    'FTM': 'ftm',
                    'KAVA': 'kava',
                    'KMA': 'kma',
                    'XEC': 'xec',
                    'IOTA': 'iota',
                    'HNT': 'hnt',
                    'ASTR': 'astr',
                    'PDEX': 'pdex',
                    'METIS': 'metis',
                    'ZEC': 'zec',
                    'POKT': 'pokt',
                    'OASYS': 'oas',
                    'OASIS': 'oasis',
                    'ETC': 'etc',
                    'AKT': 'akt',
                    'FSN': 'fsn',
                    'SCRT': 'scrt',
                    'CFG': 'cfg',
                    'ICX': 'icx',
                    'KMD': 'kmd',
                    'NEM': 'NEM',
                    'STX': 'stx',
                    'DGB': 'dgb',
                    'DCR': 'dcr',
                    'CKB': 'ckb',
                    'ELA': 'ela',
                    'HYDRA': 'hydra',
                    'BTM': 'btm',
                    'KARDIA': 'kai',
                    'SXP': 'sxp',
                    'NEBL': 'nebl',
                    'ZEN': 'zen',
                    'SDN': 'sdn',
                    'LTO': 'lto',
                    'WEMIX': 'wemix',
                    // 'BOBA': 'boba', // tbd
                    'EVER': 'ever',
                    'BNC': 'bnc',
                    'BNCDOT': 'bncdot',
                    // 'CMP': 'cmp', // todo: after consensus
                    'AION': 'aion',
                    'GRIN': 'grin',
                    'LOKI': 'loki',
                    'QKC': 'qkc',
                    'TT': 'TT',
                    'PIVX': 'pivx',
                    'SERO': 'sero',
                    'METER': 'meter',
                    'STATEMINE': 'statemine',
                    'DVPN': 'dvpn',
                    'XPRT': 'xprt',
                    'MOVR': 'movr',
                    'ERGO': 'ergo',
                    'ABBC': 'abbc',
                    'DIVI': 'divi',
                    'PURA': 'pura',
                    'DFI': 'dfi',
                    // 'NEO': 'neo', // tbd neo legacy
                    'NEON3': 'neon3',
                    'DOCK': 'dock',
                    'TRUE': 'true',
                    'CS': 'cs',
                    'ORAI': 'orai',
                    'BASE': 'base',
                    // below will be uncommented after consensus
                    // 'BITCOINDIAMON': 'bcd',
                    // 'BITCOINGOLD': 'btg',
                    // 'HTR': 'htr',
                    // 'DEROHE': 'derohe',
                    // 'NDAU': 'ndau',
                    // 'HPB': 'hpb',
                    // 'AXE': 'axe',
                    // 'BITCOINPRIVATE': 'btcp',
                    // 'EDGEWARE': 'edg',
                    // 'JUPITER': 'jup',
                    // 'VELAS': 'vlx', // vlxevm is different
                    // // 'terra' luna lunc TBD
                    // 'DIGITALBITS': 'xdb',
                    // // fra is fra-emv on kucoin
                    // 'PASTEL': 'psl',
                    // // sysevm
                    // 'CONCORDIUM': 'ccd',
                    // 'AURORA': 'aurora',
                    // 'PHA': 'pha', // a.k.a. khala
                    // 'PAL': 'pal',
                    // 'RSK': 'rbtc',
                    // 'NIX': 'nix',
                    // 'NIM': 'nim',
                    // 'NRG': 'nrg',
                    // 'RFOX': 'rfox',
                    // 'PIONEER': 'neer',
                    // 'PIXIE': 'pix',
                    // 'ALEPHZERO': 'azero',
                    // 'ACHAIN': 'act', // actevm is different
                    // 'BOSCOIN': 'bos',
                    // 'ELECTRONEUM': 'etn',
                    // 'GOCHAIN': 'go',
                    // 'SOPHIATX': 'sphtx',
                    // 'WANCHAIN': 'wan',
                    // 'ZEEPIN': 'zpt',
                    // 'MATRIXAI': 'man',
                    // 'METADIUM': 'meta',
                    // 'METAHASH': 'mhc',
                    // // eosc --"eosforce" tbd
                    // 'IOTCHAIN': 'itc',
                    // 'CONTENTOS': 'cos',
                    // 'CPCHAIN': 'cpc',
                    // 'INTCHAIN': 'int',
                    // // 'DASH': 'dash', tbd digita-cash
                    // 'WALTONCHAIN': 'wtc',
                    // 'CONSTELLATION': 'dag',
                    // 'ONELEDGER': 'olt',
                    // 'AIRDAO': 'amb', // a.k.a. AMBROSUS
                    // 'ENERGYWEB': 'ewt',
                    // 'WAVESENTERPRISE': 'west',
                    // 'HYPERCASH': 'hc',
                    // 'ENECUUM': 'enq',
                    // 'HAVEN': 'xhv',
                    // 'CHAINX': 'pcx',
                    // // 'FLUXOLD': 'zel', // zel seems old chain (with uppercase FLUX in kucoin UI and with id 'zel')
                    // 'BUMO': 'bu',
                    // 'DEEPONION': 'onion',
                    // 'ULORD': 'ut',
                    // 'ASCH': 'xas',
                    // 'SOLARIS': 'xlr',
                    // 'APOLLO': 'apl',
                    // 'PIRATECHAIN': 'arrr',
                    // 'ULTRA': 'uos',
                    // 'EMONEY': 'ngm',
                    // 'AURORACHAIN': 'aoa',
                    // 'KLEVER': 'klv',
                    // undetermined: xns(insolar), rhoc, luk (luniverse), kts (klimatas), bchn (bitcoin cash node), god (shallow entry), lit (litmus),
                },
                'marginModes': {
                    'cross': 'MARGIN_TRADE',
                    'isolated': 'MARGIN_ISOLATED_TRADE',
                    'spot': 'TRADE',
                },
            },
            'features': {
                'spot': {
                    'sandbox': false,
                    'createOrder': {
                        'marginMode': true,
                        'triggerPrice': true,
                        'triggerPriceType': undefined,
                        'triggerDirection': false,
                        'stopLossPrice': true,
                        'takeProfitPrice': true,
                        'attachedStopLossTakeProfit': undefined,
                        'timeInForce': {
                            'IOC': true,
                            'FOK': true,
                            'PO': true,
                            'GTD': true,
                        },
                        'hedged': false,
                        'trailing': false,
                        'leverage': false,
                        'marketBuyByCost': true,
                        'marketBuyRequiresPrice': false,
                        'selfTradePrevention': true,
                        'iceberg': true, // todo implement
                    },
                    'createOrders': {
                        'max': 5,
                    },
                    'fetchMyTrades': {
                        'marginMode': true,
                        'limit': undefined,
                        'daysBack': undefined,
                        'untilDays': 7,
                        'symbolRequired': true,
                    },
                    'fetchOrder': {
                        'marginMode': false,
                        'trigger': true,
                        'trailing': false,
                        'symbolRequired': true,
                    },
                    'fetchOpenOrders': {
                        'marginMode': true,
                        'limit': 500,
                        'trigger': true,
                        'trailing': false,
                        'symbolRequired': true,
                    },
                    'fetchOrders': undefined,
                    'fetchClosedOrders': {
                        'marginMode': true,
                        'limit': 500,
                        'daysBack': undefined,
                        'daysBackCanceled': undefined,
                        'untilDays': 7,
                        'trigger': true,
                        'trailing': false,
                        'symbolRequired': true,
                    },
                    'fetchOHLCV': {
                        'limit': 1500,
                    },
                },
                'swap': {
                    'linear': undefined,
                    'inverse': undefined,
                },
                'future': {
                    'linear': undefined,
                    'inverse': undefined,
                },
            },
        });
    }
    nonce() {
        return this.milliseconds() - this.options['timeDifference'];
    }
    /**
     * @method
     * @name kucoin#fetchTime
     * @description fetches the current integer timestamp in milliseconds from the exchange server
     * @see https://docs.kucoin.com/#server-time
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {int} the current integer timestamp in milliseconds from the exchange server
     */
    async fetchTime(params = {}) {
        const response = await this.publicGetTimestamp(params);
        //
        //     {
        //         "code":"200000",
        //         "msg":"success",
        //         "data":1546837113087
        //     }
        //
        return this.safeInteger(response, 'data');
    }
    /**
     * @method
     * @name kucoin#fetchStatus
     * @description the latest known information on the availability of the exchange API
     * @see https://docs.kucoin.com/#service-status
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {object} a [status structure]{@link https://docs.ccxt.com/#/?id=exchange-status-structure}
     */
    async fetchStatus(params = {}) {
        const response = await this.publicGetStatus(params);
        //
        //     {
        //         "code":"200000",
        //         "data":{
        //             "status":"open", //open, close, cancelonly
        //             "msg":"upgrade match engine" //remark for operation
        //         }
        //     }
        //
        const data = this.safeDict(response, 'data', {});
        const status = this.safeString(data, 'status');
        return {
            'status': (status === 'open') ? 'ok' : 'maintenance',
            'updated': undefined,
            'eta': undefined,
            'url': undefined,
            'info': response,
        };
    }
    /**
     * @method
     * @name kucoin#fetchMarkets
     * @description retrieves data on all markets for kucoin
     * @see https://docs.kucoin.com/#get-symbols-list-deprecated
     * @see https://docs.kucoin.com/#get-all-tickers
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {object[]} an array of objects representing market data
     */
    async fetchMarkets(params = {}) {
        let fetchTickersFees = undefined;
        [fetchTickersFees, params] = this.handleOptionAndParams(params, 'fetchMarkets', 'fetchTickersFees', true);
        const promises = [];
        promises.push(this.publicGetSymbols(params));
        //
        //     {
        //         "code": "200000",
        //         "data": [
        //             {
        //                 "symbol": "XLM-USDT",
        //                 "name": "XLM-USDT",
        //                 "baseCurrency": "XLM",
        //                 "quoteCurrency": "USDT",
        //                 "feeCurrency": "USDT",
        //                 "market": "USDS",
        //                 "baseMinSize": "0.1",
        //                 "quoteMinSize": "0.01",
        //                 "baseMaxSize": "10000000000",
        //                 "quoteMaxSize": "99999999",
        //                 "baseIncrement": "0.0001",
        //                 "quoteIncrement": "0.000001",
        //                 "priceIncrement": "0.000001",
        //                 "priceLimitRate": "0.1",
        //                 "isMarginEnabled": true,
        //                 "enableTrading": true
        //             },
        //
        const credentialsSet = this.checkRequiredCredentials(false);
        const requestMarginables = credentialsSet && this.safeBool(params, 'marginables', true);
        if (requestMarginables) {
            promises.push(this.privateGetMarginSymbols(params)); // cross margin symbols
            //
            //    {
            //        "code": "200000",
            //        "data": {
            //            "timestamp": 1719393213421,
            //            "items": [
            //                {
            //                    // same object as in market, with one additional field:
            //                    "minFunds": "0.1"
            //                },
            //
            promises.push(this.privateGetIsolatedSymbols(params)); // isolated margin symbols
            //
            //    {
            //        "code": "200000",
            //        "data": [
            //            {
            //                "symbol": "NKN-USDT",
            //                "symbolName": "NKN-USDT",
            //                "baseCurrency": "NKN",
            //                "quoteCurrency": "USDT",
            //                "maxLeverage": 5,
            //                "flDebtRatio": "0.97",
            //                "tradeEnable": true,
            //                "autoRenewMaxDebtRatio": "0.96",
            //                "baseBorrowEnable": true,
            //                "quoteBorrowEnable": true,
            //                "baseTransferInEnable": true,
            //                "quoteTransferInEnable": true,
            //                "baseBorrowCoefficient": "1",
            //                "quoteBorrowCoefficient": "1"
            //            },
            //
        }
        if (fetchTickersFees) {
            promises.push(this.publicGetMarketAllTickers(params));
            //
            //     {
            //         "code": "200000",
            //         "data": {
            //             "time":1602832092060,
            //             "ticker":[
            //                 {
            //                     "symbol": "BTC-USDT",   // symbol
            //                     "symbolName":"BTC-USDT", // Name of trading pairs, it would change after renaming
            //                     "buy": "11328.9",   // bestAsk
            //                     "sell": "11329",    // bestBid
            //                     "changeRate": "-0.0055",    // 24h change rate
            //                     "changePrice": "-63.6", // 24h change price
            //                     "high": "11610",    // 24h highest price
            //                     "low": "11200", // 24h lowest price
            //                     "vol": "2282.70993217", // 24h volume,the aggregated trading volume in BTC
            //                     "volValue": "25984946.157790431",   // 24h total, the trading volume in quote currency of last 24 hours
            //                     "last": "11328.9",  // last price
            //                     "averagePrice": "11360.66065903",   // 24h average transaction price yesterday
            //                     "takerFeeRate": "0.001",    // Basic Taker Fee
            //                     "makerFeeRate": "0.001",    // Basic Maker Fee
            //                     "takerCoefficient": "1",    // Taker Fee Coefficient
            //                     "makerCoefficient": "1" // Maker Fee Coefficient
            //                 }
            //
        }
        if (credentialsSet) {
            // load migration status for account
            promises.push(this.loadMigrationStatus());
        }
        const responses = await Promise.all(promises);
        const symbolsData = this.safeList(responses[0], 'data');
        const crossData = requestMarginables ? this.safeDict(responses[1], 'data', {}) : {};
        const crossItems = this.safeList(crossData, 'items', []);
        const crossById = this.indexBy(crossItems, 'symbol');
        const isolatedData = requestMarginables ? responses[2] : {};
        const isolatedItems = this.safeList(isolatedData, 'data', []);
        const isolatedById = this.indexBy(isolatedItems, 'symbol');
        const tickersIdx = requestMarginables ? 3 : 1;
        const tickersResponse = this.safeDict(responses, tickersIdx, {});
        const tickerItems = this.safeList(this.safeDict(tickersResponse, 'data', {}), 'ticker', []);
        const tickersById = this.indexBy(tickerItems, 'symbol');
        const result = [];
        for (let i = 0; i < symbolsData.length; i++) {
            const market = symbolsData[i];
            const id = this.safeString(market, 'symbol');
            const [baseId, quoteId] = id.split('-');
            const base = this.safeCurrencyCode(baseId);
            const quote = this.safeCurrencyCode(quoteId);
            // const quoteIncrement = this.safeNumber (market, 'quoteIncrement');
            const ticker = this.safeDict(tickersById, id, {});
            const makerFeeRate = this.safeString(ticker, 'makerFeeRate');
            const takerFeeRate = this.safeString(ticker, 'takerFeeRate');
            const makerCoefficient = this.safeString(ticker, 'makerCoefficient');
            const takerCoefficient = this.safeString(ticker, 'takerCoefficient');
            const hasCrossMargin = (id in crossById);
            const hasIsolatedMargin = (id in isolatedById);
            const isMarginable = this.safeBool(market, 'isMarginEnabled', false) || hasCrossMargin || hasIsolatedMargin;
            result.push({
                'id': id,
                'symbol': base + '/' + quote,
                'base': base,
                'quote': quote,
                'settle': undefined,
                'baseId': baseId,
                'quoteId': quoteId,
                'settleId': undefined,
                'type': 'spot',
                'spot': true,
                'margin': isMarginable,
                'marginModes': {
                    'cross': hasCrossMargin,
                    'isolated': hasIsolatedMargin,
                },
                'swap': false,
                'future': false,
                'option': false,
                'active': this.safeBool(market, 'enableTrading'),
                'contract': false,
                'linear': undefined,
                'inverse': undefined,
                'taker': this.parseNumber(Precise["default"].stringMul(takerFeeRate, takerCoefficient)),
                'maker': this.parseNumber(Precise["default"].stringMul(makerFeeRate, makerCoefficient)),
                'contractSize': undefined,
                'expiry': undefined,
                'expiryDatetime': undefined,
                'strike': undefined,
                'optionType': undefined,
                'precision': {
                    'amount': this.safeNumber(market, 'baseIncrement'),
                    'price': this.safeNumber(market, 'priceIncrement'),
                },
                'limits': {
                    'leverage': {
                        'min': undefined,
                        'max': undefined,
                    },
                    'amount': {
                        'min': this.safeNumber(market, 'baseMinSize'),
                        'max': this.safeNumber(market, 'baseMaxSize'),
                    },
                    'price': {
                        'min': undefined,
                        'max': undefined,
                    },
                    'cost': {
                        'min': this.safeNumber(market, 'quoteMinSize'),
                        'max': this.safeNumber(market, 'quoteMaxSize'),
                    },
                },
                'created': undefined,
                'info': market,
            });
        }
        if (this.options['adjustForTimeDifference']) {
            await this.loadTimeDifference();
        }
        return result;
    }
    /**
     * @method
     * @name kucoin#loadMigrationStatus
     * @param {boolean} force load account state for non hf
     * @description loads the migration status for the account (hf or not)
     * @see https://www.kucoin.com/docs/rest/spot-trading/spot-hf-trade-pro-account/get-user-type
     * @returns {any} ignore
     */
    async loadMigrationStatus(force = false) {
        if (!('hf' in this.options) || (this.options['hf'] === undefined) || force) {
            const result = await this.privateGetHfAccountsOpened();
            this.options['hf'] = this.safeBool(result, 'data');
        }
        return true;
    }
    handleHfAndParams(params = {}) {
        const migrated = this.safeBool(this.options, 'hf', false);
        let loadedHf = undefined;
        if (migrated !== undefined) {
            if (migrated) {
                loadedHf = true;
            }
            else {
                loadedHf = false;
            }
        }
        const hf = this.safeBool(params, 'hf', loadedHf);
        params = this.omit(params, 'hf');
        return [hf, params];
    }
    /**
     * @method
     * @name kucoin#fetchCurrencies
     * @description fetches all available currencies on an exchange
     * @see https://docs.kucoin.com/#get-currencies
     * @param {object} params extra parameters specific to the exchange API endpoint
     * @returns {object} an associative dictionary of currencies
     */
    async fetchCurrencies(params = {}) {
        const response = await this.publicGetCurrencies(params);
        //
        //    {
        //        "code":"200000",
        //        "data":[
        //           {
        //              "currency":"CSP",
        //              "name":"CSP",
        //              "fullName":"Caspian",
        //              "precision":8,
        //              "confirms":null,
        //              "contractAddress":null,
        //              "isMarginEnabled":false,
        //              "isDebitEnabled":false,
        //              "chains":[
        //                 {
        //                    "chainName":"ERC20",
        //                    "chainId": "eth"
        //                    "withdrawalMinSize":"2999",
        //                    "depositMinSize":null,
        //                    "withdrawFeeRate":"0",
        //                    "withdrawalMinFee":"2999",
        //                    "isWithdrawEnabled":false,
        //                    "isDepositEnabled":false,
        //                    "confirms":12,
        //                    "preConfirms":12,
        //                    "withdrawPrecision": 8,
        //                    "maxWithdraw": null,
        //                    "maxDeposit": null,
        //                    "needTag": false,
        //                    "contractAddress":"0xa6446d655a0c34bc4f05042ee88170d056cbaf45",
        //                    "depositFeeRate": "0.001", // present for some currencies/networks
        //                 }
        //              ]
        //           },
        //        ]
        //    }
        //
        const currenciesData = this.safeList(response, 'data', []);
        const brokenCurrencies = this.safeList(this.options, 'brokenCurrencies', ['00', 'OPEN_ERROR', 'HUF', 'BDT']);
        const otherFiats = this.safeList(this.options, 'fiats', ['KWD', 'IRR', 'PKR']);
        const result = {};
        for (let i = 0; i < currenciesData.length; i++) {
            const entry = currenciesData[i];
            const id = this.safeString(entry, 'currency');
            if (this.inArray(id, brokenCurrencies)) {
                continue; // skip buggy entries: https://t.me/KuCoin_API/217798
            }
            const code = this.safeCurrencyCode(id);
            const networks = {};
            const chains = this.safeList(entry, 'chains', []);
            const chainsLength = chains.length;
            for (let j = 0; j < chainsLength; j++) {
                const chain = chains[j];
                const chainId = this.safeString(chain, 'chainId');
                const networkCode = this.networkIdToCode(chainId, code);
                networks[networkCode] = {
                    'info': chain,
                    'id': chainId,
                    'name': this.safeString(chain, 'chainName'),
                    'code': networkCode,
                    'active': undefined,
                    'fee': this.safeNumber(chain, 'withdrawalMinFee'),
                    'deposit': this.safeBool(chain, 'isDepositEnabled'),
                    'withdraw': this.safeBool(chain, 'isWithdrawEnabled'),
                    'precision': this.parseNumber(this.parsePrecision(this.safeString(chain, 'withdrawPrecision'))),
                    'limits': {
                        'withdraw': {
                            'min': this.safeNumber(chain, 'withdrawalMinSize'),
                            'max': this.safeNumber(chain, 'maxWithdraw'),
                        },
                        'deposit': {
                            'min': this.safeNumber(chain, 'depositMinSize'),
                            'max': this.safeNumber(chain, 'maxDeposit'),
                        },
                    },
                };
            }
            // kucoin has determined 'fiat' currencies with below logic
            const rawPrecision = this.safeString(entry, 'precision');
            const precision = this.parseNumber(this.parsePrecision(rawPrecision));
            const isFiat = this.inArray(id, otherFiats) || ((rawPrecision === '2') && (chainsLength === 0));
            result[code] = this.safeCurrencyStructure({
                'id': id,
                'name': this.safeString(entry, 'fullName'),
                'code': code,
                'type': isFiat ? 'fiat' : 'crypto',
                'precision': precision,
                'info': entry,
                'networks': networks,
                'deposit': undefined,
                'withdraw': undefined,
                'active': undefined,
                'fee': undefined,
                'limits': undefined,
            });
        }
        return result;
    }
    /**
     * @method
     * @name kucoin#fetchAccounts
     * @description fetch all the accounts associated with a profile
     * @see https://docs.kucoin.com/#list-accounts
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {object} a dictionary of [account structures]{@link https://docs.ccxt.com/#/?id=account-structure} indexed by the account type
     */
    async fetchAccounts(params = {}) {
        const response = await this.privateGetAccounts(params);
        //
        //     {
        //         "code": "200000",
        //         "data": [
        //             {
        //                 "balance": "0.00009788",
        //                 "available": "0.00009788",
        //                 "holds": "0",
        //                 "currency": "BTC",
        //                 "id": "5c6a4fd399a1d81c4f9cc4d0",
        //                 "type": "trade"
        //             },
        //             {
        //                 "balance": "0.00000001",
        //                 "available": "0.00000001",
        //                 "holds": "0",
        //                 "currency": "ETH",
        //                 "id": "5c6a49ec99a1d819392e8e9f",
        //                 "type": "trade"
        //             }
        //         ]
        //     }
        //
        const data = this.safeList(response, 'data', []);
        const result = [];
        for (let i = 0; i < data.length; i++) {
            const account = data[i];
            const accountId = this.safeString(account, 'id');
            const currencyId = this.safeString(account, 'currency');
            const code = this.safeCurrencyCode(currencyId);
            const type = this.safeString(account, 'type'); // main or trade
            result.push({
                'id': accountId,
                'type': type,
                'currency': code,
                'code': code,
                'info': account,
            });
        }
        return result;
    }
    /**
     * @method
     * @name kucoin#fetchTransactionFee
     * @description *DEPRECATED* please use fetchDepositWithdrawFee instead
     * @see https://docs.kucoin.com/#get-withdrawal-quotas
     * @param {string} code unified currency code
     * @param {object} params extra parameters specific to the exchange API endpoint
     * @returns {object} a [fee structure]{@link https://docs.ccxt.com/#/?id=fee-structure}
     */
    async fetchTransactionFee(code, params = {}) {
        await this.loadMarkets();
        const currency = this.currency(code);
        const request = {
            'currency': currency['id'],
        };
        let networkCode = undefined;
        [networkCode, params] = this.handleNetworkCodeAndParams(params);
        if (networkCode !== undefined) {
            request['chain'] = this.networkCodeToId(networkCode).toLowerCase();
        }
        const response = await this.privateGetWithdrawalsQuotas(this.extend(request, params));
        const data = this.safeDict(response, 'data', {});
        const withdrawFees = {};
        withdrawFees[code] = this.safeNumber(data, 'withdrawMinFee');
        return {
            'info': response,
            'withdraw': withdrawFees,
            'deposit': {},
        };
    }
    /**
     * @method
     * @name kucoin#fetchDepositWithdrawFee
     * @description fetch the fee for deposits and withdrawals
     * @see https://docs.kucoin.com/#get-withdrawal-quotas
     * @param {string} code unified currency code
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @param {string} [params.network] The chain of currency. This only apply for multi-chain currency, and there is no need for single chain currency; you can query the chain through the response of the GET /api/v2/currencies/{currency} interface
     * @returns {object} a [fee structure]{@link https://docs.ccxt.com/#/?id=fee-structure}
     */
    async fetchDepositWithdrawFee(code, params = {}) {
        await this.loadMarkets();
        const currency = this.currency(code);
        const request = {
            'currency': currency['id'],
        };
        let networkCode = undefined;
        [networkCode, params] = this.handleNetworkCodeAndParams(params);
        if (networkCode !== undefined) {
            request['chain'] = this.networkCodeToId(networkCode).toLowerCase();
        }
        const response = await this.privateGetWithdrawalsQuotas(this.extend(request, params));
        //
        //    {
        //        "code": "200000",
        //        "data": {
        //            "currency": "USDT",
        //            "limitBTCAmount": "1.00000000",
        //            "usedBTCAmount": "0.00000000",
        //            "remainAmount": "16548.072149",
        //            "availableAmount": "0",
        //            "withdrawMinFee": "25",
        //            "innerWithdrawMinFee": "0",
        //            "withdrawMinSize": "50",
        //            "isWithdrawEnabled": true,
        //            "precision": 6,
        //            "chain": "ERC20"
        //        }
        //    }
        //
        const data = this.safeDict(response, 'data');
        return this.parseDepositWithdrawFee(data, currency);
    }
    parseDepositWithdrawFee(fee, currency = undefined) {
        //
        //    {
        //        "currency": "USDT",
        //        "limitBTCAmount": "1.00000000",
        //        "usedBTCAmount": "0.00000000",
        //        "remainAmount": "16548.072149",
        //        "availableAmount": "0",
        //        "withdrawMinFee": "25",
        //        "innerWithdrawMinFee": "0",
        //        "withdrawMinSize": "50",
        //        "isWithdrawEnabled": true,
        //        "precision": 6,
        //        "chain": "ERC20"
        //    }
        //
        if ('chains' in fee) {
            // if data obtained through `currencies` endpoint
            const resultNew = {
                'info': fee,
                'withdraw': {
                    'fee': undefined,
                    'percentage': false,
                },
                'deposit': {
                    'fee': undefined,
                    'percentage': undefined,
                },
                'networks': {},
            };
            const chains = this.safeList(fee, 'chains', []);
            for (let i = 0; i < chains.length; i++) {
                const chain = chains[i];
                const networkCodeNew = this.networkIdToCode(this.safeString(chain, 'chainId'), this.safeString(currency, 'code'));
                resultNew['networks'][networkCodeNew] = {
                    'withdraw': {
                        'fee': this.safeNumber(chain, 'withdrawMinFee'),
                        'percentage': false,
                    },
                    'deposit': {
                        'fee': undefined,
                        'percentage': undefined,
                    },
                };
            }
            return resultNew;
        }
        const minWithdrawFee = this.safeNumber(fee, 'withdrawMinFee');
        const result = {
            'info': fee,
            'withdraw': {
                'fee': minWithdrawFee,
                'percentage': false,
            },
            'deposit': {
                'fee': undefined,
                'percentage': undefined,
            },
            'networks': {},
        };
        const networkId = this.safeString(fee, 'chain');
        const networkCode = this.networkIdToCode(networkId, this.safeString(currency, 'code'));
        result['networks'][networkCode] = {
            'withdraw': minWithdrawFee,
            'deposit': {
                'fee': undefined,
                'percentage': undefined,
            },
        };
        return result;
    }
    isFuturesMethod(methodName, params) {
        //
        // Helper
        // @methodName (string): The name of the method
        // @params (dict): The parameters passed into {methodName}
        // @return: true if the method used is meant for futures trading, false otherwise
        //
        const defaultType = this.safeString2(this.options, methodName, 'defaultType', 'trade');
        const requestedType = this.safeString(params, 'type', defaultType);
        const accountsByType = this.safeDict(this.options, 'accountsByType');
        const type = this.safeString(accountsByType, requestedType);
        if (type === undefined) {
            const keys = Object.keys(accountsByType);
            throw new errors.ExchangeError(this.id + ' isFuturesMethod() type must be one of ' + keys.join(', '));
        }
        params = this.omit(params, 'type');
        return (type === 'contract') || (type === 'future') || (type === 'futures'); // * (type === 'futures') deprecated, use (type === 'future')
    }
    parseTicker(ticker, market = undefined) {
        //
        //     {
        //         "symbol": "BTC-USDT",   // symbol
        //         "symbolName":"BTC-USDT", // Name of trading pairs, it would change after renaming
        //         "buy": "11328.9",   // bestAsk
        //         "sell": "11329",    // bestBid
        //         "changeRate": "-0.0055",    // 24h change rate
        //         "changePrice": "-63.6", // 24h change price
        //         "high": "11610",    // 24h highest price
        //         "low": "11200", // 24h lowest price
        //         "vol": "2282.70993217", // 24h volume,the aggregated trading volume in BTC
        //         "volValue": "25984946.157790431",   // 24h total, the trading volume in quote currency of last 24 hours
        //         "last": "11328.9",  // last price
        //         "averagePrice": "11360.66065903",   // 24h average transaction price yesterday
        //         "takerFeeRate": "0.001",    // Basic Taker Fee
        //         "makerFeeRate": "0.001",    // Basic Maker Fee
        //         "takerCoefficient": "1",    // Taker Fee Coefficient
        //         "makerCoefficient": "1" // Maker Fee Coefficient
        //     }
        //
        //     {
        //         "trading": true,
        //         "symbol": "KCS-BTC",
        //         "buy": 0.00011,
        //         "sell": 0.00012,
        //         "sort": 100,
        //         "volValue": 3.13851792584,   //total
        //         "baseCurrency": "KCS",
        //         "market": "BTC",
        //         "quoteCurrency": "BTC",
        //         "symbolCode": "KCS-BTC",
        //         "datetime": 1548388122031,
        //         "high": 0.00013,
        //         "vol": 27514.34842,
        //         "low": 0.0001,
        //         "changePrice": -1.0e-5,
        //         "changeRate": -0.0769,
        //         "lastTradedPrice": 0.00012,
        //         "board": 0,
        //         "mark": 0
        //     }
        //
        // market/ticker ws subscription
        //
        //     {
        //         "bestAsk": "62258.9",
        //         "bestAskSize": "0.38579986",
        //         "bestBid": "62258.8",
        //         "bestBidSize": "0.0078381",
        //         "price": "62260.7",
        //         "sequence": "1621383297064",
        //         "size": "0.00002841",
        //         "time": 1634641777363
        //     }
        //
        let percentage = this.safeString(ticker, 'changeRate');
        if (percentage !== undefined) {
            percentage = Precise["default"].stringMul(percentage, '100');
        }
        let last = this.safeString2(ticker, 'last', 'lastTradedPrice');
        last = this.safeString(ticker, 'price', last);
        const marketId = this.safeString(ticker, 'symbol');
        market = this.safeMarket(marketId, market, '-');
        const symbol = market['symbol'];
        const baseVolume = this.safeString(ticker, 'vol');
        const quoteVolume = this.safeString(ticker, 'volValue');
        const timestamp = this.safeIntegerN(ticker, ['time', 'datetime', 'timePoint']);
        return this.safeTicker({
            'symbol': symbol,
            'timestamp': timestamp,
            'datetime': this.iso8601(timestamp),
            'high': this.safeString(ticker, 'high'),
            'low': this.safeString(ticker, 'low'),
            'bid': this.safeString2(ticker, 'buy', 'bestBid'),
            'bidVolume': this.safeString(ticker, 'bestBidSize'),
            'ask': this.safeString2(ticker, 'sell', 'bestAsk'),
            'askVolume': this.safeString(ticker, 'bestAskSize'),
            'vwap': undefined,
            'open': this.safeString(ticker, 'open'),
            'close': last,
            'last': last,
            'previousClose': undefined,
            'change': this.safeString(ticker, 'changePrice'),
            'percentage': percentage,
            'average': this.safeString(ticker, 'averagePrice'),
            'baseVolume': baseVolume,
            'quoteVolume': quoteVolume,
            'markPrice': this.safeString(ticker, 'value'),
            'info': ticker,
        }, market);
    }
    /**
     * @method
     * @name kucoin#fetchTickers
     * @description fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market
     * @see https://docs.kucoin.com/#get-all-tickers
     * @param {string[]|undefined} symbols unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {object} a dictionary of [ticker structures]{@link https://docs.ccxt.com/#/?id=ticker-structure}
     */
    async fetchTickers(symbols = undefined, params = {}) {
        await this.loadMarkets();
        symbols = this.marketSymbols(symbols);
        const response = await this.publicGetMarketAllTickers(params);
        //
        //     {
        //         "code": "200000",
        //         "data": {
        //             "time":1602832092060,
        //             "ticker":[
        //                 {
        //                     "symbol": "BTC-USDT",   // symbol
        //                     "symbolName":"BTC-USDT", // Name of trading pairs, it would change after renaming
        //                     "buy": "11328.9",   // bestAsk
        //                     "sell": "11329",    // bestBid
        //                     "changeRate": "-0.0055",    // 24h change rate
        //                     "changePrice": "-63.6", // 24h change price
        //                     "high": "11610",    // 24h highest price
        //                     "low": "11200", // 24h lowest price
        //                     "vol": "2282.70993217", // 24h volume,the aggregated trading volume in BTC
        //                     "volValue": "25984946.157790431",   // 24h total, the trading volume in quote currency of last 24 hours
        //                     "last": "11328.9",  // last price
        //                     "averagePrice": "11360.66065903",   // 24h average transaction price yesterday
        //                     "takerFeeRate": "0.001",    // Basic Taker Fee
        //                     "makerFeeRate": "0.001",    // Basic Maker Fee
        //                     "takerCoefficient": "1",    // Taker Fee Coefficient
        //                     "makerCoefficient": "1" // Maker Fee Coefficient
        //                 }
        //             ]
        //         }
        //     }
        //
        const data = this.safeDict(response, 'data', {});
        const tickers = this.safeList(data, 'ticker', []);
        const time = this.safeInteger(data, 'time');
        const result = {};
        for (let i = 0; i < tickers.length; i++) {
            tickers[i]['time'] = time;
            const ticker = this.parseTicker(tickers[i]);
            const symbol = this.safeString(ticker, 'symbol');
            if (symbol !== undefined) {
                result[symbol] = ticker;
            }
        }
        return this.filterByArrayTickers(result, 'symbol', symbols);
    }
    /**
     * @method
     * @name kucoin#fetchMarkPrices
     * @description fetches the mark price for multiple markets
     * @see https://www.kucoin.com/docs/rest/margin-trading/margin-info/get-all-margin-trading-pairs-mark-prices
     * @param {string[]} [symbols] unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {object} a dictionary of [ticker structures]{@link https://docs.ccxt.com/#/?id=ticker-structure}
     */
    async fetchMarkPrices(symbols = undefined, params = {}) {
        await this.loadMarkets();
        symbols = this.marketSymbols(symbols);
        const response = await this.publicGetMarkPriceAllSymbols(params);
        const data = this.safeList(response, 'data', []);
        return this.parseTickers(data);
    }
    /**
     * @method
     * @name kucoin#fetchTicker
     * @description fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
     * @see https://docs.kucoin.com/#get-24hr-stats
     * @param {string} symbol unified symbol of the market to fetch the ticker for
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
     */
    async fetchTicker(symbol, params = {}) {
        await this.loadMarkets();
        const market = this.market(symbol);
        const request = {
            'symbol': market['id'],
        };
        const response = await this.publicGetMarketStats(this.extend(request, params));
        //
        //     {
        //         "code": "200000",
        //         "data": {
        //             "time": 1602832092060,  // time
        //             "symbol": "BTC-USDT",   // symbol
        //             "buy": "11328.9",   // bestAsk
        //             "sell": "11329",    // bestBid
        //             "changeRate": "-0.0055",    // 24h change rate
        //             "changePrice": "-63.6", // 24h change price
        //             "high": "11610",    // 24h highest price
        //             "low": "11200", // 24h lowest price
        //             "vol": "2282.70993217", // 24h volume,the aggregated trading volume in BTC
        //             "volValue": "25984946.157790431",   // 24h total, the trading volume in quote currency of last 24 hours
        //             "last": "11328.9",  // last price
        //             "averagePrice": "11360.66065903",   // 24h average transaction price yesterday
        //             "takerFeeRate": "0.001",    // Basic Taker Fee
        //             "makerFeeRate": "0.001",    // Basic Maker Fee
        //             "takerCoefficient": "1",    // Taker Fee Coefficient
        //             "makerCoefficient": "1" // Maker Fee Coefficient
        //         }
        //     }
        //
        const data = this.safeDict(response, 'data', {});
        return this.parseTicker(data, market);
    }
    /**
     * @method
     * @name kucoin#fetchMarkPrice
     * @description fetches the mark price for a specific market
     * @see https://www.kucoin.com/docs/rest/margin-trading/margin-info/get-mark-price
     * @param {string} symbol unified symbol of the market to fetch the ticker for
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
     */
    async fetchMarkPrice(symbol, params = {}) {
        await this.loadMarkets();
        const market = this.market(symbol);
        const request = {
            'symbol': market['id'],
        };
        const response = await this.publicGetMarkPriceSymbolCurrent(this.extend(request, params));
        //
        const data = this.safeDict(response, 'data', {});
        return this.parseTicker(data, market);
    }
    parseOHLCV(ohlcv, market = undefined) {
        //
        //     [
        //         "1545904980",             // Start time of the candle cycle
        //         "0.058",                  // opening price
        //         "0.049",                  // closing price
        //         "0.058",                  // highest price
        //         "0.049",                  // lowest price
        //         "0.018",                  // base volume
        //         "0.000945",               // quote volume
        //     ]
        //
        return [
            this.safeTimestamp(ohlcv, 0),
            this.safeNumber(ohlcv, 1),
            this.safeNumber(ohlcv, 3),
            this.safeNumber(ohlcv, 4),
            this.safeNumber(ohlcv, 2),
            this.safeNumber(ohlcv, 5),
        ];
    }
    /**
     * @method
     * @name kucoin#fetchOHLCV
     * @description fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
     * @see https://docs.kucoin.com/#get-klines
     * @param {string} symbol unified symbol of the market to fetch OHLCV data for
     * @param {string} timeframe the length of time each candle represents
     * @param {int} [since] timestamp in ms of the earliest candle to fetch
     * @param {int} [limit] the maximum amount of candles to fetch
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
     * @returns {int[][]} A list of candles ordered as timestamp, open, high, low, close, volume
     */
    async fetchOHLCV(symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
        await this.loadMarkets();
        let paginate = false;
        [paginate, params] = this.handleOptionAndParams(params, 'fetchOHLCV', 'paginate');
        if (paginate) {
            return await this.fetchPaginatedCallDeterministic('fetchOHLCV', symbol, since, limit, timeframe, params, 1500);
        }
        const market = this.market(symbol);
        const marketId = market['id'];
        const request = {
            'symbol': marketId,
            'type': this.safeString(this.timeframes, timeframe, timeframe),
        };
        const duration = this.parseTimeframe(timeframe) * 1000;
        let endAt = this.milliseconds(); // required param
        if (since !== undefined) {
            request['startAt'] = this.parseToInt(Math.floor(since / 1000));
            if (limit === undefined) {
                // https://docs.kucoin.com/#get-klines
                // https://docs.kucoin.com/#details
                // For each query, the system would return at most 1500 pieces of data.
                // To obtain more data, please page the data by time.
                limit = this.safeInteger(this.options, 'fetchOHLCVLimit', 1500);
            }
            endAt = this.sum(since, limit * duration);
        }
        else if (limit !== undefined) {
            since = endAt - limit * duration;
            request['startAt'] = this.parseToInt(Math.floor(since / 1000));
        }
        request['endAt'] = this.parseToInt(Math.floor(endAt / 1000));
        const response = await this.publicGetMarketCandles(this.extend(request, params));
        //
        //     {
        //         "code":"200000",
        //         "data":[
        //             ["1591517700","0.025078","0.025069","0.025084","0.025064","18.9883256","0.4761861079404"],
        //             ["1591516800","0.025089","0.025079","0.025089","0.02506","99.4716622","2.494143499081"],
        //             ["1591515900","0.025079","0.02509","0.025091","0.025068","59.83701271","1.50060885172798"],
        //         ]
        //     }
        //
        const data = this.safeList(response, 'data', []);
        return this.parseOHLCVs(data, market, timeframe, since, limit);
    }
    /**
     * @method
     * @name kucoin#createDepositAddress
     * @see https://www.kucoin.com/docs/rest/funding/deposit/create-deposit-address-v3-
     * @description create a currency deposit address
     * @param {string} code unified currency code of the currency for the deposit address
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @param {string} [params.network] the blockchain network name
     * @returns {object} an [address structure]{@link https://docs.ccxt.com/#/?id=address-structure}
     */
    async createDepositAddress(code, params = {}) {
        await this.loadMarkets();
        const currency = this.currency(code);
        const request = {
            'currency': currency['id'],
        };
        let networkCode = undefined;
        [networkCode, params] = this.handleNetworkCodeAndParams(params);
        if (networkCode !== undefined) {
            request['chain'] = this.networkCodeToId(networkCode); // docs mention "chain-name", but seems "chain-id" is used, like in "fetchDepositAddress"
        }
        const response = await this.privatePostDepositAddressCreate(this.extend(request, params));
        // {"code":"260000","msg":"Deposit address already exists."}
        //
        //   {
        //     "code": "200000",
        //     "data": {
        //       "address": "0x2336d1834faab10b2dac44e468f2627138417431",
        //       "memo": null,
        //       "chainId": "bsc",
        //       "to": "MAIN",
        //       "expirationDate": 0,
        //       "currency": "BNB",
        //       "chainName": "BEP20"
        //     }
        //   }
        //
        const data = this.safeDict(response, 'data', {});
        return this.parseDepositAddress(data, currency);
    }
    /**
     * @method
     * @name kucoin#fetchDepositAddress
     * @description fetch the deposit address for a currency associated with this account
     * @see https://docs.kucoin.com/#get-deposit-addresses-v2
     * @param {string} code unified currency code
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @param {string} [params.network] the blockchain network name
     * @returns {object} an [address structure]{@link https://docs.ccxt.com/#/?id=address-structure}
     */
    async fetchDepositAddress(code, params = {}) {
        await this.loadMarkets();
        const currency = this.currency(code);
        const request = {
            'currency': currency['id'],
            // for USDT - OMNI, ERC20, TRC20, default is ERC20
            // for BTC - Native, Segwit, TRC20, the parameters are bech32, btc, trx, default is Native
            // 'chain': 'ERC20', // optional
        };
        let networkCode = undefined;
        [networkCode, params] = this.handleNetworkCodeAndParams(params);
        if (networkCode !== undefined) {
            request['chain'] = this.networkCodeToId(networkCode).toLowerCase();
        }
        const version = this.options['versions']['private']['GET']['deposit-addresses'];
        this.options['versions']['private']['GET']['deposit-addresses'] = 'v1';
        const response = await this.privateGetDepositAddresses(this.extend(request, params));
        // BCH {"code":"200000","data":{"address":"bitcoincash:qza3m4nj9rx7l9r0cdadfqxts6f92shvhvr5ls4q7z","memo":""}}
        // BTC {"code":"200000","data":{"address":"36SjucKqQpQSvsak9A7h6qzFjrVXpRNZhE","memo":""}}
        this.options['versions']['private']['GET']['deposit-addresses'] = version;
        const data = this.safeValue(response, 'data');
        if (data === undefined) {
            throw new errors.ExchangeError(this.id + ' fetchDepositAddress() returned an empty response, you might try to run createDepositAddress() first and try again');
        }
        return this.parseDepositAddress(data, currency);
    }
    parseDepositAddress(depositAddress, currency = undefined) {
        let address = this.safeString(depositAddress, 'address');
        // BCH/BSV is returned with a "bitcoincash:" prefix, which we cut off here and only keep the address
        if (address !== undefined) {
            address = address.replace('bitcoincash:', '');
        }
        let code = undefined;
        if (currency !== undefined) {
            code = this.safeCurrencyCode(currency['id']);
            if (code !== 'NIM') {
                // contains spaces
                this.checkAddress(address);
            }
        }
        return {
            'info': depositAddress,
            'currency': code,
            'network': this.networkIdToCode(this.safeString(depositAddress, 'chainId')),
            'address': address,
            'tag': this.safeString(depositAddress, 'memo'),
        };
    }
    /**
     * @method
     * @name kucoin#fetchDepositAddressesByNetwork
     * @see https://docs.kucoin.com/#get-deposit-addresses-v2
     * @description fetch the deposit address for a currency associated with this account
     * @param {string} code unified currency code
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {object} an array of [address structures]{@link https://docs.ccxt.com/#/?id=address-structure}
     */
    async fetchDepositAddressesByNetwork(code, params = {}) {
        await this.loadMarkets();
        const currency = this.currency(code);
        const request = {
            'currency': currency['id'],
        };
        const version = this.options['versions']['private']['GET']['deposit-addresses'];
        this.options['versions']['private']['GET']['deposit-addresses'] = 'v2';
        const response = await this.privateGetDepositAddresses(this.extend(request, params));
        //
        //     {
        //         "code": "200000",
        //         "data": [
        //             {
        //                 "address": "fr1qvus7d4d5fgxj5e7zvqe6yhxd7txm95h2and69r",
        //                 "memo": "",
        //                 "chain": "BTC-Segwit",
        //                 "contractAddress": ""
        //             },
        //             {"address":"37icNMEWbiF8ZkwUMxmfzMxi2A1MQ44bMn","memo":"","chain":"BTC","contractAddress":""},
        //             {"address":"Deposit temporarily blocked","memo":"","chain":"TRC20","contractAddress":""}
        //         ]
        //     }
        //
        this.options['versions']['private']['GET']['deposit-addresses'] = version;
        const chains = this.safeList(response, 'data', []);
        const parsed = this.parseDepositAddresses(chains, [currency['code']], false, {
            'currency': currency['code'],
        });
        return this.indexBy(parsed, 'network');
    }
    /**
     * @method
     * @name kucoin#fetchOrderBook
     * @description fetches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
     * @see https://www.kucoin.com/docs/rest/spot-trading/market-data/get-part-order-book-aggregated-
     * @see https://www.kucoin.com/docs/rest/spot-trading/market-data/get-full-order-book-aggregated-
     * @param {string} symbol unified symbol of the market to fetch the order book for
     * @param {int} [limit] the maximum amount of order book entries to return
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols
     */
    async fetchOrderBook(symbol, limit = undefined, params = {}) {
        await this.loadMarkets();
        const market = this.market(symbol);
        const level = this.safeInteger(params, 'level', 2);
        const request = { 'symbol': market['id'] };
        const isAuthenticated = this.checkRequiredCredentials(false);
        let response = undefined;
        if (!isAuthenticated || limit !== undefined) {
            if (level === 2) {
                request['level'] = level;
                if (limit !== undefined) {
                    if ((limit === 20) || (limit === 100)) {
                        request['limit'] = limit;
                    }
                    else {
                        throw new errors.ExchangeError(this.id + ' fetchOrderBook() limit argument must be 20 or 100');
                    }
                }
                request['limit'] = limit ? limit : 100;
            }
            response = await this.publicGetMarketOrderbookLevelLevelLimit(this.extend(request, params));
        }
        else {
            response = await this.privateGetMarketOrderbookLevel2(this.extend(request, params));
        }
        //
        // public (v1) market/orderbook/level2_20 and market/orderbook/level2_100
        //
        //     {
        //         "sequence": "3262786978",
        //         "time": 1550653727731,
        //         "bids": [
        //             ["6500.12", "0.45054140"],
        //             ["6500.11", "0.45054140"],
        //         ],
        //         "asks": [
        //             ["6500.16", "0.57753524"],
        //             ["6500.15", "0.57753524"],
        //         ]
        //     }
        //
        // private (v3) market/orderbook/level2
        //
        //     {
        //         "sequence": "3262786978",
        //         "time": 1550653727731,
        //         "bids": [
        //             ["6500.12", "0.45054140"],
        //             ["6500.11", "0.45054140"],
        //         ],
        //         "asks": [
        //             ["6500.16", "0.57753524"],
        //             ["6500.15", "0.57753524"],
        //         ]
        //     }
        //
        const data = this.safeDict(response, 'data', {});
        const timestamp = this.safeInteger(data, 'time');
        const orderbook = this.parseOrderBook(data, market['symbol'], timestamp, 'bids', 'asks', level - 2, level - 1);
        orderbook['nonce'] = this.safeInteger(data, 'sequence');
        return orderbook;
    }
    handleTriggerPrices(params) {
        const triggerPrice = this.safeValue2(params, 'triggerPrice', 'stopPrice');
        const stopLossPrice = this.safeValue(params, 'stopLossPrice');
        const takeProfitPrice = this.safeValue(params, 'takeProfitPrice');
        const isStopLoss = stopLossPrice !== undefined;
        const isTakeProfit = takeProfitPrice !== undefined;
        if ((isStopLoss && isTakeProfit) || (triggerPrice && stopLossPrice) || (triggerPrice && isTakeProfit)) {
            throw new errors.ExchangeError(this.id + ' createOrder() - you should use either triggerPrice or stopLossPrice or takeProfitPrice');
        }
        return [triggerPrice, stopLossPrice, takeProfitPrice];
    }
    /**
     * @method
     * @name kucoin#createOrder
     * @description Create an order on the exchange
     * @see https://docs.kucoin.com/spot#place-a-new-order
     * @see https://docs.kucoin.com/spot#place-a-new-order-2
     * @see https://docs.kucoin.com/spot#place-a-margin-order
     * @see https://docs.kucoin.com/spot-hf/#place-hf-order
     * @see https://www.kucoin.com/docs/rest/spot-trading/orders/place-order-test
     * @see https://www.kucoin.com/docs/rest/margin-trading/orders/place-margin-order-test
     * @see https://www.kucoin.com/docs/rest/spot-trading/spot-hf-trade-pro-account/sync-place-hf-order
     * @param {string} symbol Unified CCXT market symbol
     * @param {string} type 'limit' or 'market'
     * @param {string} side 'buy' or 'sell'
     * @param {float} amount the amount of currency to trade
     * @param {float} [price] the price at which the order is to be fulfilled, in units of the quote currency, ignored in market orders
     * @param {object} [params]  extra parameters specific to the exchange API endpoint
     * @param {float} [params.triggerPrice] The price at which a trigger order is triggered at
     * @param {string} [params.marginMode] 'cross', // cross (cross mode) and isolated (isolated mode), set to cross by default, the isolated mode will be released soon, stay tuned
     * @param {string} [params.timeInForce] GTC, GTT, IOC, or FOK, default is GTC, limit orders only
     * @param {string} [params.postOnly] Post only flag, invalid when timeInForce is IOC or FOK
     *
     * EXCHANGE SPECIFIC PARAMETERS
     * @param {string} [params.clientOid] client order id, defaults to uuid if not passed
     * @param {string} [params.remark] remark for the order, length cannot exceed 100 utf8 characters
     * @param {string} [params.tradeType] 'TRADE', // TRADE, MARGIN_TRADE // not used with margin orders
     * limit orders ---------------------------------------------------
     * @param {float} [params.cancelAfter] long, // cancel after n seconds, requires timeInForce to be GTT
     * @param {bool} [params.hidden] false, // Order will not be displayed in the order book
     * @param {bool} [params.iceberg] false, // Only a portion of the order is displayed in the order book
     * @param {string} [params.visibleSize] this.amountToPrecision (symbol, visibleSize), // The maximum visible size of an iceberg order
     * market orders --------------------------------------------------
     * @param {string} [params.funds] // Amount of quote currency to use
     * stop orders ----------------------------------------------------
     * @param {string} [params.stop]  Either loss or entry, the default is loss. Requires triggerPrice to be defined
     * margin orders --------------------------------------------------
     * @param {float} [params.leverage] Leverage size of the order
     * @param {string} [params.stp] '', // self trade prevention, CN, CO, CB or DC
     * @param {bool} [params.autoBorrow] false, // The system will first borrow you funds at the optimal interest rate and then place an order for you
     * @param {bool} [params.hf] false, // true for hf order
     * @param {bool} [params.test] set to true to test an order, no order will be created but the request will be validated
     * @param {bool} [params.sync] set to true to use the hf sync call
     * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
     */
    async createOrder(symbol, type, side, amount, price = undefined, params = {}) {
        await this.loadMarkets();
        const market = this.market(symbol);
        const testOrder = this.safeBool(params, 'test', false);
        params = this.omit(params, 'test');
        let hf = undefined;
        [hf, params] = this.handleHfAndParams(params);
        let useSync = false;
        [useSync, params] = this.handleOptionAndParams(params, 'createOrder', 'sync', false);
        const [triggerPrice, stopLossPrice, takeProfitPrice] = this.handleTriggerPrices(params);
        const tradeType = this.safeString(params, 'tradeType'); // keep it for backward compatibility
        const isTriggerOrder = (triggerPrice || stopLossPrice || takeProfitPrice);
        const marginResult = this.handleMarginModeAndParams('createOrder', params);
        const marginMode = this.safeString(marginResult, 0);
        const isMarginOrder = tradeType === 'MARGIN_TRADE' || marginMode !== undefined;
        // don't omit anything before calling createOrderRequest
        const orderRequest = this.createOrderRequest(symbol, type, side, amount, price, params);
        let response = undefined;
        if (testOrder) {
            if (isMarginOrder) {
                response = await this.privatePostMarginOrderTest(orderRequest);
            }
            else if (hf) {
                response = await this.privatePostHfOrdersTest(orderRequest);
            }
            else {
                response = await this.privatePostOrdersTest(orderRequest);
            }
        }
        else if (isTriggerOrder) {
            response = await this.privatePostStopOrder(orderRequest);
        }
        else if (isMarginOrder) {
            response = await this.privatePostMarginOrder(orderRequest);
        }
        else if (useSync) {
            response = await this.privatePostHfOrdersSync(orderRequest);
        }
        else if (hf) {
            response = await this.privatePostHfOrders(orderRequest);
        }
        else {
            response = await this.privatePostOrders(orderRequest);
        }
        //
        //     {
        //         "code": "200000",
        //         "data": {
        //             "orderId": "5bd6e9286d99522a52e458de"
        //         }
        //    }
        //
        const data = this.safeDict(response, 'data', {});
        return this.parseOrder(data, market);
    }
    /**
     * @method
     * @name kucoin#createMarketOrderWithCost
     * @description create a market order by providing the symbol, side and cost
     * @see https://www.kucoin.com/docs/rest/spot-trading/orders/place-order
     * @param {string} symbol unified symbol of the market to create an order in
     * @param {string} side 'buy' or 'sell'
     * @param {float} cost how much you want to trade in units of the quote currency
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
     */
    async createMarketOrderWithCost(symbol, side, cost, params = {}) {
        await this.loadMarkets();
        const req = {
            'cost': cost,
        };
        return await this.createOrder(symbol, 'market', side, cost, undefined, this.extend(req, params));
    }
    /**
     * @method
     * @name kucoin#createMarketBuyOrderWithCost
     * @description create a market buy order by providing the symbol and cost
     * @see https://www.kucoin.com/docs/rest/spot-trading/orders/place-order
     * @param {string} symbol unified symbol of the market to create an order in
     * @param {float} cost how much you want to trade in units of the quote currency
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
     */
    async createMarketBuyOrderWithCost(symbol, cost, params = {}) {
        await this.loadMarkets();
        return await this.createMarketOrderWithCost(symbol, 'buy', cost, params);
    }
    /**
     * @method
     * @name kucoin#createMarketSellOrderWithCost
     * @description create a market sell order by providing the symbol and cost
     * @see https://www.kucoin.com/docs/rest/spot-trading/orders/place-order
     * @param {string} symbol unified symbol of the market to create an order in
     * @param {float} cost how much you want to trade in units of the quote currency
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
     */
    async createMarketSellOrderWithCost(symbol, cost, params = {}) {
        await this.loadMarkets();
        return await this.createMarketOrderWithCost(symbol, 'sell', cost, params);
    }
    /**
     * @method
     * @name kucoin#createOrders
     * @description create a list of trade orders
     * @see https://www.kucoin.com/docs/rest/spot-trading/orders/place-multiple-orders
     * @see https://www.kucoin.com/docs/rest/spot-trading/spot-hf-trade-pro-account/place-multiple-hf-orders
     * @see https://www.kucoin.com/docs/rest/spot-trading/spot-hf-trade-pro-account/sync-place-multiple-hf-orders
     * @param {Array} orders list of orders to create, each object should contain the parameters required by createOrder, namely symbol, type, side, amount, price and params
     * @param {object} [params]  extra parameters specific to the exchange API endpoint
     * @param {bool} [params.hf] false, // true for hf orders
     * @param {bool} [params.sync] false, // true to use the hf sync call
     * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
     */
    async createOrders(orders, params = {}) {
        await this.loadMarkets();
        const ordersRequests = [];
        let symbol = undefined;
        for (let i = 0; i < orders.length; i++) {
            const rawOrder = orders[i];
            const marketId = this.safeString(rawOrder, 'symbol');
            if (symbol === undefined) {
                symbol = marketId;
            }
            else {
                if (symbol !== marketId) {
                    throw new errors.BadRequest(this.id + ' createOrders() requires all orders to have the same symbol');
                }
            }
            const type = this.safeString(rawOrder, 'type');
            if (type !== 'limit') {
                throw new errors.BadRequest(this.id + ' createOrders() only supports limit orders');
            }
            const side = this.safeString(rawOrder, 'side');
            const amount = this.safeValue(rawOrder, 'amount');
            const price = this.safeValue(rawOrder, 'price');
            const orderParams = this.safeValue(rawOrder, 'params', {});
            const orderRequest = this.createOrderRequest(marketId, type, side, amount, price, orderParams);
            ordersRequests.push(orderRequest);
        }
        const market = this.market(symbol);
        const request = {
            'symbol': market['id'],
            'orderList': ordersRequests,
        };
        let hf = undefined;
        [hf, params] = this.handleHfAndParams(params);
        let useSync = false;
        [useSync, params] = this.handleOptionAndParams(params, 'createOrders', 'sync', false);
        let response = undefined;
        if (useSync) {
            response = await this.privatePostHfOrdersMultiSync(this.extend(request, params));
        }
        else if (hf) {
            response = await this.privatePostHfOrdersMulti(this.extend(request, params));
        }
        else {
            response = await this.privatePostOrdersMulti(this.extend(request, params));
        }
        //
        // {
        //     "code": "200000",
        //     "data": {
        //        "data": [
        //           {
        //              "symbol": "LTC-USDT",
        //              "type": "limit",
        //              "side": "sell",
        //              "price": "90",
        //              "size": "0.1",
        //              "funds": null,
        //              "stp": "",
        //              "stop": "",
        //              "stopPrice": null,
        //              "timeInForce": "GTC",
        //              "cancelAfter": 0,
        //              "postOnly": false,
        //              "hidden": false,
        //              "iceberge": false,
        //              "iceberg": false,
        //              "visibleSize": null,
        //              "channel": "API",
        //              "id": "6539148443fcf500079d15e5",
        //              "status": "success",
        //              "failMsg": null,
        //              "clientOid": "5c4c5398-8ab2-4b4e-af8a-e2d90ad2488f"
        //           },
        // }
        //
        let data = this.safeDict(response, 'data', {});
        data = this.safeList(data, 'data', []);
        return this.parseOrders(data);
    }
    marketOrderAmountToPrecision(symbol, amount) {
        const market = this.market(symbol);
        const result = this.decimalToPrecision(amount, number.TRUNCATE, market['info']['quoteIncrement'], this.precisionMode, this.paddingMode);
        if (result === '0') {
            throw new errors.InvalidOrder(this.id + ' amount of ' + market['symbol'] + ' must be greater than minimum amount precision of ' + this.numberToString(market['precision']['amount']));
        }
        return result;
    }
    createOrderRequest(symbol, type, side, amount, price = undefined, params = {}) {
        const market = this.market(symbol);
        // required param, cannot be used twice
        const clientOrderId = this.safeString2(params, 'clientOid', 'clientOrderId', this.uuid());
        params = this.omit(params, ['clientOid', 'clientOrderId']);
        const request = {
            'clientOid': clientOrderId,
            'side': side,
            'symbol': market['id'],
            'type': type, // limit or market
        };
        const quoteAmount = this.safeNumber2(params, 'cost', 'funds');
        let amountString = undefined;
        let costString = undefined;
        let marginMode = undefined;
        [marginMode, params] = this.handleMarginModeAndParams('createOrder', params);
        if (type === 'market') {
            if (quoteAmount !== undefined) {
                params = this.omit(params, ['cost', 'funds']);
                // kucoin uses base precision even for quote values
                costString = this.marketOrderAmountToPrecision(symbol, quoteAmount);
                request['funds'] = costString;
            }
            else {
                amountString = this.amountToPrecision(symbol, amount);
                request['size'] = this.amountToPrecision(symbol, amount);
            }
        }
        else {
            amountString = this.amountToPrecision(symbol, amount);
            request['size'] = amountString;
            request['price'] = this.priceToPrecision(symbol, price);
        }
        const tradeType = this.safeString(params, 'tradeType'); // keep it for backward compatibility
        const [triggerPrice, stopLossPrice, takeProfitPrice] = this.handleTriggerPrices(params);
        const isTriggerOrder = (triggerPrice || stopLossPrice || takeProfitPrice);
        const isMarginOrder = tradeType === 'MARGIN_TRADE' || marginMode !== undefined;
        params = this.omit(params, ['stopLossPrice', 'takeProfitPrice', 'triggerPrice', 'stopPrice']);
        if (isTriggerOrder) {
            if (triggerPrice) {
                request['stopPrice'] = this.priceToPrecision(symbol, triggerPrice);
            }
            else if (stopLossPrice || takeProfitPrice) {
                if (stopLossPrice) {
                    request['stop'] = (side === 'buy') ? 'entry' : 'loss';
                    request['stopPrice'] = this.priceToPrecision(symbol, stopLossPrice);
                }
                else {
                    request['stop'] = (side === 'buy') ? 'loss' : 'entry';
                    request['stopPrice'] = this.priceToPrecision(symbol, takeProfitPrice);
                }
            }
            if (marginMode === 'isolated') {
                throw new errors.BadRequest(this.id + ' createOrder does not support isolated margin for stop orders');
            }
            else if (marginMode === 'cross') {
                request['tradeType'] = this.options['marginModes'][marginMode];
            }
        }
        else if (isMarginOrder) {
            if (marginMode === 'isolated') {
                request['marginModel'] = 'isolated';
            }
        }
        let postOnly = undefined;
        [postOnly, params] = this.handlePostOnly(type === 'market', false, params);
        if (postOnly) {
            request['postOnly'] = true;
        }
        return this.extend(request, params);
    }
    /**
     * @method
     * @name kucoin#editOrder
     * @description edit an order, kucoin currently only supports the modification of HF orders
     * @see https://docs.kucoin.com/spot-hf/#modify-order
     * @param {string} id order id
     * @param {string} symbol unified symbol of the market to create an order in
     * @param {string} type not used
     * @param {string} side not used
     * @param {float} amount how much of the currency you want to trade in units of the base currency
     * @param {float} [price] the price at which the order is to be fulfilled, in units of the quote currency, ignored in market orders
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @param {string} [params.clientOrderId] client order id, defaults to id if not passed
     * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
     */
    async editOrder(id, symbol, type, side, amount = undefined, price = undefined, params = {}) {
        await this.loadMarkets();
        const market = this.market(symbol);
        const request = {
            'symbol': market['id'],
        };
        const clientOrderId = this.safeString2(params, 'clientOid', 'clientOrderId');
        if (clientOrderId !== undefined) {
            request['clientOid'] = clientOrderId;
        }
        else {
            request['orderId'] = id;
        }
        if (amount !== undefined) {
            request['newSize'] = this.amountToPrecision(symbol, amount);
        }
        if (price !== undefined) {
            request['newPrice'] = this.priceToPrecision(symbol, price);
        }
        const response = await this.privatePostHfOrdersAlter(this.extend(request, params));
        //
        // {
        //     "code":"200000",
        //     "data":{
        //        "newOrderId":"6478d7a6c883280001e92d8b"
        //     }
        // }
        //
        const data = this.safeDict(response, 'data', {});
        return this.parseOrder(data, market);
    }
    /**
     * @method
     * @name kucoin#cancelOrder
     * @description cancels an open order
     * @see https://docs.kucoin.com/spot#cancel-an-order
     * @see https://docs.kucoin.com/spot#cancel-an-order-2
     * @see https://docs.kucoin.com/spot#cancel-single-order-by-clientoid
     * @see https://docs.kucoin.com/spot#cancel-single-order-by-clientoid-2
     * @see https://docs.kucoin.com/spot-hf/#cancel-orders-by-orderid
     * @see https://docs.kucoin.com/spot-hf/#cancel-order-by-clientoid
     * @see https://www.kucoin.com/docs/rest/spot-trading/spot-hf-trade-pro-account/sync-cancel-hf-order-by-orderid
     * @see https://www.kucoin.com/docs/rest/spot-trading/spot-hf-trade-pro-account/sync-cancel-hf-order-by-clientoid
     * @param {string} id order id
     * @param {string} symbol unified symbol of the market the order was made in
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @param {bool} [params.trigger] True if cancelling a stop order
     * @param {bool} [params.hf] false, // true for hf order
     * @param {bool} [params.sync] false, // true to use the hf sync call
     * @returns Response from the exchange
     */
    async cancelOrder(id, symbol = undefined, params = {}) {
        await this.loadMarkets();
        const request = {};
        const clientOrderId = this.safeString2(params, 'clientOid', 'clientOrderId');
        const trigger = this.safeBool2(params, 'stop', 'trigger', false);
        let hf = undefined;
        [hf, params] = this.handleHfAndParams(params);
        let useSync = false;
        [useSync, params] = this.handleOptionAndParams(params, 'cancelOrder', 'sync', false);
        if (hf || useSync) {
            if (symbol === undefined) {
                throw new errors.ArgumentsRequired(this.id + ' cancelOrder() requires a symbol parameter for hf orders');
            }
            const market = this.market(symbol);
            request['symbol'] = market['id'];
        }
        let response = undefined;
        params = this.omit(params, ['clientOid', 'clientOrderId', 'stop', 'trigger']);
        if (clientOrderId !== undefined) {
            request['clientOid'] = clientOrderId;
            if (trigger) {
                response = await this.privateDeleteStopOrderCancelOrderByClientOid(this.extend(request, params));
                //
                //    {
                //        code: '200000',
                //        data: {
                //          cancelledOrderId: 'vs8lgpiuao41iaft003khbbk',
                //          clientOid: '123456'
                //        }
                //    }
                //
            }
            else if (useSync) {
                response = await this.privateDeleteHfOrdersSyncClientOrderClientOid(this.extend(request, params));
            }
            else if (hf) {
                response = await this.privateDeleteHfOrdersClientOrderClientOid(this.extend(request, params));
                //
                //    {
                //        "code": "200000",
                //        "data": {
                //          "clientOid": "6d539dc614db3"
                //        }
                //    }
                //
            }
            else {
                response = await this.privateDeleteOrderClientOrderClientOid(this.extend(request, params));
                //
                //    {
                //        code: '200000',
                //        data: {
                //          cancelledOrderId: '665e580f6660500007aba341',
                //          clientOid: '1234567',
                //          cancelledOcoOrderIds: null
                //        }
                //    }
                //
            }
            response = this.safeDict(response, 'data');
            return this.parseOrder(response);
        }
        else {
            request['orderId'] = id;
            if (trigger) {
                response = await this.privateDeleteStopOrderOrderId(this.extend(request, params));
                //
                //    {
                //        code: '200000',
                //        data: { cancelledOrderIds: [ 'vs8lgpiuaco91qk8003vebu9' ] }
                //    }
                //
            }
            else if (useSync) {
                response = await this.privateDeleteHfOrdersSyncOrderId(this.extend(request, params));
            }
            else if (hf) {
                response = await this.privateDeleteHfOrdersOrderId(this.extend(request, params));
                //
                //    {
                //        "code": "200000",
                //        "data": {
                //          "orderId": "630625dbd9180300014c8d52"
                //        }
                //    }
                //
                response = this.safeDict(response, 'data');
                return this.parseOrder(response);
            }
            else {
                response = await this.privateDeleteOrdersOrderId(this.extend(request, params));
                //
                //    {
                //        code: '200000',
                //        data: { cancelledOrderIds: [ '665e4fbe28051a0007245c41' ] }
                //    }
                //
            }
            const data = this.safeDict(response, 'data');
            const orderIds = this.safeList(data, 'cancelledOrderIds', []);
            const orderId = this.safeString(orderIds, 0);
            return this.safeOrder({
                'info': data,
                'id': orderId,
            });
        }
    }
    /**
     * @method
     * @name kucoin#cancelAllOrders
     * @description cancel all open orders
     * @see https://docs.kucoin.com/spot#cancel-all-orders
     * @see https://docs.kucoin.com/spot#cancel-orders
     * @see https://docs.kucoin.com/spot-hf/#cancel-all-hf-orders-by-symbol
     * @param {string} symbol unified market symbol, only orders in the market of this symbol are cancelled when symbol is not undefined
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @param {bool} [params.trigger] *invalid for isolated margin* true if cancelling all stop orders
     * @param {string} [params.marginMode] 'cross' or 'isolated'
     * @param {string} [params.orderIds] *stop orders only* Comma seperated order IDs
     * @param {bool} [params.hf] false, // true for hf order
     * @returns Response from the exchange
     */
    async cancelAllOrders(symbol = undefined, params = {}) {
        await this.loadMarkets();
        const request = {};
        const trigger = this.safeBool(params, 'stop', false);
        let hf = undefined;
        [hf, params] = this.handleHfAndParams(params);
        params = this.omit(params, 'stop');
        const [marginMode, query] = this.handleMarginModeAndParams('cancelAllOrders', params);
        if (symbol !== undefined) {
            request['symbol'] = this.marketId(symbol);
        }
        if (marginMode !== undefined) {
            request['tradeType'] = this.options['marginModes'][marginMode];
            if (marginMode === 'isolated' && trigger) {
                throw new errors.BadRequest(this.id + ' cancelAllOrders does not support isolated margin for stop orders');
            }
        }
        let response = undefined;
        if (trigger) {
            response = await this.privateDeleteStopOrderCancel(this.extend(request, query));
        }
        else if (hf) {
            if (symbol === undefined) {
                response = await this.privateDeleteHfOrdersCancelAll(this.extend(request, query));
            }
            else {
                response = await this.privateDeleteHfOrders(this.extend(request, query));
            }
        }
        else {
            response = await this.privateDeleteOrders(this.extend(request, query));
        }
        return response;
    }
    /**
     * @method
     * @name kucoin#fetchOrdersByStatus
     * @description fetch a list of orders
     * @see https://docs.kucoin.com/spot#list-orders
     * @see https://docs.kucoin.com/spot#list-stop-orders
     * @see https://docs.kucoin.com/spot-hf/#obtain-list-of-active-hf-orders
     * @see https://docs.kucoin.com/spot-hf/#obtain-list-of-filled-hf-orders
     * @param {string} status *not used for stop orders* 'open' or 'closed'
     * @param {string} symbol unified market symbol
     * @param {int} [since] timestamp in ms of the earliest order
     * @param {int} [limit] max number of orders to return
     * @param {object} [params] exchange specific params
     * @param {int} [params.until] end time in ms
     * @param {string} [params.side] buy or sell
     * @param {string} [params.type] limit, market, limit_stop or market_stop
     * @param {string} [params.tradeType] TRADE for spot trading, MARGIN_TRADE for Margin Trading
     * @param {int} [params.currentPage] *trigger orders only* current page
     * @param {string} [params.orderIds] *trigger orders only* comma seperated order ID list
     * @param {bool} [params.trigger] True if fetching a trigger order
     * @param {bool} [params.hf] false, // true for hf order
     * @returns An [array of order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
     */
    async fetchOrdersByStatus(status, symbol = undefined, since = undefined, limit = undefined, params = {}) {
        await this.loadMarkets();
        let lowercaseStatus = status.toLowerCase();
        const until = this.safeInteger(params, 'until');
        const trigger = this.safeBool2(params, 'stop', 'trigger', false);
        let hf = undefined;
        [hf, params] = this.handleHfAndParams(params);
        if (hf && (symbol === undefined)) {
            throw new errors.ArgumentsRequired(this.id + ' fetchOrdersByStatus() requires a symbol parameter for hf orders');
        }
        params = this.omit(params, ['stop', 'trigger', 'till', 'until']);
        const [marginMode, query] = this.handleMarginModeAndParams('fetchOrdersByStatus', params);
        if (lowercaseStatus === 'open') {
            lowercaseStatus = 'active';
        }
        else if (lowercaseStatus === 'closed') {
            lowercaseStatus = 'done';
        }
        const request = {
            'status': lowercaseStatus,
        };
        let market = undefined;
        if (symbol !== undefined) {
            market = this.market(symbol);
            request['symbol'] = market['id'];
        }
        if (since !== undefined) {
            request['startAt'] = since;
        }
        if (limit !== undefined) {
            request['pageSize'] = limit;
        }
        if (until) {
            request['endAt'] = until;
        }
        request['tradeType'] = this.safeString(this.options['marginModes'], marginMode, 'TRADE');
        let response = undefined;
        if (trigger) {
            response = await this.privateGetStopOrder(this.extend(request, query));
        }
        else if (hf) {
            if (lowercaseStatus === 'active') {
                response = await this.privateGetHfOrdersActive(this.extend(request, query));
            }
            else if (lowercaseStatus === 'done') {
                response = await this.privateGetHfOrdersDone(this.extend(request, query));
            }
        }
        else {
            response = await this.privateGetOrders(this.extend(request, query));
        }
        //
        //     {
        //         "code": "200000",
        //         "data": {
        //             "currentPage": 1,
        //             "pageSize": 1,
        //             "totalNum": 153408,
        //             "totalPage": 153408,
        //             "items": [
        //                 {
        //                     "id": "5c35c02703aa673ceec2a168",   //orderid
        //                     "symbol": "BTC-USDT",   //symbol
        //                     "opType": "DEAL",      // operation type,deal is pending order,cancel is cancel order
        //                     "type": "limit",       // order type,e.g. limit,markrt,stop_limit.
        //                     "side": "buy",         // transaction direction,include buy and sell
        //                     "price": "10",         // order price
        //                     "size": "2",           // order quantity
        //                     "funds": "0",          // order funds
        //                     "dealFunds": "0.166",  // deal funds
        //                     "dealSize": "2",       // deal quantity
        //                     "fee": "0",            // fee
        //                     "feeCurrency": "USDT", // charge fee currency
        //                     "stp": "",             // self trade prevention,include CN,CO,DC,CB
        //                     "stop": "",            // stop type
        //                     "stopTriggered": false,  // stop order is triggered
        //                     "stopPrice": "0",      // stop price
        //                     "timeInForce": "GTC",  // time InForce,include GTC,GTT,IOC,FOK
        //                     "postOnly": false,     // postOnly
        //                     "hidden": false,       // hidden order
        //                     "iceberg": false,      // iceberg order
        //                     "visibleSize": "0",    // display quantity for iceberg order
        //                     "cancelAfter": 0,      // cancel orders time,requires timeInForce to be GTT
        //                     "channel": "IOS",      // order source
        //                     "clientOid": "",       // user-entered order unique mark
        //                     "remark": "",          // remark
        //                     "tags": "",            // tag order source
        //                     "isActive": false,     // status before unfilled or uncancelled
        //                     "cancelExist": false,   // order cancellation transaction record
        //                     "createdAt": 1547026471000  // time
        //                 },
        //             ]
        //         }
        //    }
        const listData = this.safeList(response, 'data');
        if (listData !== undefined) {
            return this.parseOrders(listData, market, since, limit);
        }
        const responseData = this.safeDict(response, 'data', {});
        const orders = this.safeList(responseData, 'items', []);
        return this.parseOrders(orders, market, since, limit);
    }
    /**
     * @method
     * @name kucoin#fetchClosedOrders
     * @description fetches information on multiple closed orders made by the user
     * @see https://docs.kucoin.com/spot#list-orders
     * @see https://docs.kucoin.com/spot#list-stop-orders
     * @see https://docs.kucoin.com/spot-hf/#obtain-list-of-active-hf-orders
     * @see https://docs.kucoin.com/spot-hf/#obtain-list-of-filled-hf-orders
     * @param {string} symbol unified market symbol of the market orders were made in
     * @param {int} [since] the earliest time in ms to fetch orders for
     * @param {int} [limit] the maximum number of order structures to retrieve
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @param {int} [params.until] end time in ms
     * @param {string} [params.side] buy or sell
     * @param {string} [params.type] limit, market, limit_stop or market_stop
     * @param {string} [params.tradeType] TRADE for spot trading, MARGIN_TRADE for Margin Trading
     * @param {bool} [params.trigger] True if fetching a trigger order
     * @param {bool} [params.hf] false, // true for hf order
     * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
     * @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
     */
    async fetchClosedOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
        await this.loadMarkets();
        let paginate = false;
        [paginate, params] = this.handleOptionAndParams(params, 'fetchClosedOrders', 'paginate');
        if (paginate) {
            return await this.fetchPaginatedCallDynamic('fetchClosedOrders', symbol, since, limit, params);
        }
        return await this.fetchOrdersByStatus('done', symbol, since, limit, params);
    }
    /**
     * @method
     * @name kucoin#fetchOpenOrders
     * @description fetch all unfilled currently open orders
     * @see https://docs.kucoin.com/spot#list-orders
     * @see https://docs.kucoin.com/spot#list-stop-orders
     * @see https://docs.kucoin.com/spot-hf/#obtain-list-of-active-hf-orders
     * @see https://docs.kucoin.com/spot-hf/#obtain-list-of-filled-hf-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 orders structures to retrieve
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @param {int} [params.until] end time in ms
     * @param {bool} [params.trigger] true if fetching trigger orders
     * @param {string} [params.side] buy or sell
     * @param {string} [params.type] limit, market, limit_stop or market_stop
     * @param {string} [params.tradeType] TRADE for spot trading, MARGIN_TRADE for Margin Trading
     * @param {int} [params.currentPage] *trigger orders only* current page
     * @param {string} [params.orderIds] *trigger orders only* comma seperated order ID list
     * @param {bool} [params.hf] false, // true for hf order
     * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
     * @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
     */
    async fetchOpenOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
        await this.loadMarkets();
        let paginate = false;
        [paginate, params] = this.handleOptionAndParams(params, 'fetchOpenOrders', 'paginate');
        if (paginate) {
            return await this.fetchPaginatedCallDynamic('fetchOpenOrders', symbol, since, limit, params);
        }
        return await this.fetchOrdersByStatus('active', symbol, since, limit, params);
    }
    /**
     * @method
     * @name kucoin#fetchOrder
     * @description fetch an order
     * @see https://docs.kucoin.com/spot#get-an-order
     * @see https://docs.kucoin.com/spot#get-single-active-order-by-clientoid
     * @see https://docs.kucoin.com/spot#get-single-order-info
     * @see https://docs.kucoin.com/spot#get-single-order-by-clientoid
     * @see https://docs.kucoin.com/spot-hf/#details-of-a-single-hf-order
     * @see https://docs.kucoin.com/spot-hf/#obtain-details-of-a-single-hf-order-using-clientoid
     * @param {string} id Order id
     * @param {string} symbol not sent to exchange except for trigger orders with clientOid, but used internally by CCXT to filter
     * @param {object} [params] exchange specific parameters
     * @param {bool} [params.trigger] true if fetching a trigger order
     * @param {bool} [params.hf] false, // true for hf order
     * @param {bool} [params.clientOid] unique order id created by users to identify their orders
     * @returns An [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
     */
    async fetchOrder(id, symbol = undefined, params = {}) {
        await this.loadMarkets();
        const request = {};
        const clientOrderId = this.safeString2(params, 'clientOid', 'clientOrderId');
        const trigger = this.safeBool2(params, 'stop', 'trigger', false);
        let hf = undefined;
        [hf, params] = this.handleHfAndParams(params);
        let market = undefined;
        if (symbol !== undefined) {
            market = this.market(symbol);
        }
        if (hf) {
            if (symbol === undefined) {
                throw new errors.ArgumentsRequired(this.id + ' fetchOrder() requires a symbol parameter for hf orders');
            }
            request['symbol'] = market['id'];
        }
        params = this.omit(params, ['stop', 'clientOid', 'clientOrderId', 'trigger']);
        let response = undefined;
        if (clientOrderId !== undefined) {
            request['clientOid'] = clientOrderId;
            if (trigger) {
                if (symbol !== undefined) {
                    request['symbol'] = market['id'];
                }
                response = await this.privateGetStopOrderQueryOrderByClientOid(this.extend(request, params));
            }
            else if (hf) {
                response = await this.privateGetHfOrdersClientOrderClientOid(this.extend(request, params));
            }
            else {
                response = await this.privateGetOrderClientOrderClientOid(this.extend(request, params));
            }
        }
        else {
            // a special case for undefined ids
            // otherwise a wrong endpoint for all orders will be triggered
            // https://github.com/ccxt/ccxt/issues/7234
            if (id === undefined) {
                throw new errors.InvalidOrder(this.id + ' fetchOrder() requires an order id');
            }
            request['orderId'] = id;
            if (trigger) {
                response = await this.privateGetStopOrderOrderId(this.extend(request, params));
            }
            else if (hf) {
                response = await this.privateGetHfOrdersOrderId(this.extend(request, params));
            }
            else {
                response = await this.privateGetOrdersOrderId(this.extend(request, params));
            }
        }
        let responseData = this.safeDict(response, 'data', {});
        if (Array.isArray(responseData)) {
            responseData = this.safeValue(responseData, 0);
        }
        return this.parseOrder(responseData, market);
    }
    parseOrder(order, market = undefined) {
        //
        // createOrder
        //
        //    {
        //        "orderId": "63c97e47d686c5000159a656"
        //    }
        //
        // cancelOrder
        //
        //    {
        //        "cancelledOrderIds": [ "63c97e47d686c5000159a656" ]
        //    }
        //
        // fetchOpenOrders, fetchClosedOrders
        //
        //    {
        //        "id": "63c97ce8d686c500015793bb",
        //        "symbol": "USDC-USDT",
        //        "opType": "DEAL",
        //        "type": "limit",
        //        "side": "sell",
        //        "price": "1.05",
        //        "size": "1",
        //        "funds": "0",
        //        "dealFunds": "0",
        //        "dealSize": "0",
        //        "fee": "0",
        //        "feeCurrency": "USDT",
        //        "stp": "",
        //        "stop": "",
        //        "stopTriggered": false,
        //        "stopPrice": "0",
        //        "timeInForce": "GTC",
        //        "postOnly": false,
        //        "hidden": false,
        //        "iceberg": false,
        //        "visibleSize": "0",
        //        "cancelAfter": 0,
        //        "channel": "API",
        //        "clientOid": "d602d73f-5424-4751-bef0-8debce8f0a82",
        //        "remark": null,
        //        "tags": "partner:ccxt",
        //        "isActive": true,
        //        "cancelExist": false,
        //        "createdAt": 1674149096927,
        //        "tradeType": "TRADE"
        //    }
        //
        // stop orders (fetchOpenOrders, fetchClosedOrders)
        //
        //    {
        //        "id": "vs9f6ou9e864rgq8000t4qnm",
        //        "symbol": "USDC-USDT",
        //        "userId": "613a896885d8660006151f01",
        //        "status": "NEW",
        //        "type": "market",
        //        "side": "sell",
        //        "price": null,
        //        "size": "1.00000000000000000000",
        //        "funds": null,
        //        "stp": null,
        //        "timeInForce": "GTC",
        //        "cancelAfter": -1,
        //        "postOnly": false,
        //        "hidden": false,
        //        "iceberg": false,
        //        "visibleSize": null,
        //        "channel": "API",
        //        "clientOid": "5d3fd727-6456-438d-9550-40d9d85eee0b",
        //        "remark": null,
        //        "tags": "partner:ccxt",
        //        "relatedNo": null,
        //        "orderTime": 1674146316994000028,
        //        "domainId": "kucoin",
        //        "tradeSource": "USER",
        //        "tradeType": "MARGIN_TRADE",
        //        "feeCurrency": "USDT",
        //        "takerFeeRate": "0.00100000000000000000",
        //        "makerFeeRate": "0.00100000000000000000",
        //        "createdAt": 1674146316994,
        //        "stop": "loss",
        //        "stopTriggerTime": null,
        //        "stopPrice": "0.97000000000000000000"
        //    }
        // hf order
        //    {
        //        "id":"6478cf1439bdfc0001528a1d",
        //        "symbol":"LTC-USDT",
        //        "opType":"DEAL",
        //        "type":"limit",
        //        "side":"buy",
        //        "price":"50",
        //        "size":"0.1",
        //        "funds":"5",
        //        "dealSize":"0",
        //        "dealFunds":"0",
        //        "fee":"0",
        //        "feeCurrency":"USDT",
        //        "stp":null,
        //        "timeInForce":"GTC",
        //        "postOnly":false,
        //        "hidden":false,
        //        "iceberg":false,
        //        "visibleSize":"0",
        //        "cancelAfter":0,
        //        "channel":"API",
        //        "clientOid":"d4d2016b-8e3a-445c-aa5d-dc6df5d1678d",
        //        "remark":null,
        //        "tags":"partner:ccxt",
        //        "cancelExist":false,
        //        "createdAt":1685638932074,
        //        "lastUpdatedAt":1685639013735,
        //        "tradeType":"TRADE",
        //        "inOrderBook":true,
        //        "cancelledSize":"0",
        //        "cancelledFunds":"0",
        //        "remainSize":"0.1",
        //        "remainFunds":"5",
        //        "active":true
        //    }
        //
        const marketId = this.safeString(order, 'symbol');
        const timestamp = this.safeInteger(order, 'createdAt');
        const feeCurrencyId = this.safeString(order, 'feeCurrency');
        const cancelExist = this.safeBool(order, 'cancelExist', false);
        const responseStop = this.safeString(order, 'stop');
        const trigger = responseStop !== undefined;
        const stopTriggered = this.safeBool(order, 'stopTriggered', false);
        const isActive = this.safeBool2(order, 'isActive', 'active');
        const responseStatus = this.safeString(order, 'status');
        let status = undefined;
        if (isActive !== undefined) {
            if (isActive === true) {
                status = 'open';
            }
            else {
                status = 'closed';
            }
        }
        if (trigger) {
            if (responseStatus === 'NEW') {
                status = 'open';
            }
            else if (!isActive && !stopTriggered) {
                status = 'cancelled';
            }
        }
        if (cancelExist) {
            status = 'canceled';
        }
        if (responseStatus === 'fail') {
            status = 'rejected';
        }
        return this.safeOrder({
            'info': order,
            'id': this.safeStringN(order, ['id', 'orderId', 'newOrderId', 'cancelledOrderId']),
            'clientOrderId': this.safeString(order, 'clientOid'),
            'symbol': this.safeSymbol(marketId, market, '-'),
            'type': this.safeString(order, 'type'),
            'timeInForce': this.safeString(order, 'timeInForce'),
            'postOnly': this.safeBool(order, 'postOnly'),
            'side': this.safeString(order, 'side'),
            'amount': this.safeString(order, 'size'),
            'price': this.safeString(order, 'price'),
            'triggerPrice': this.safeNumber(order, 'stopPrice'),
            'cost': this.safeString(order, 'dealFunds'),
            'filled': this.safeString(order, 'dealSize'),
            'remaining': undefined,
            'timestamp': timestamp,
            'datetime': this.iso8601(timestamp),
            'fee': {
                'currency': this.safeCurrencyCode(feeCurrencyId),
                'cost': this.safeNumber(order, 'fee'),
            },
            'status': status,
            'lastTradeTimestamp': undefined,
            'average': this.safeString(order, 'avgDealPrice'),
            'trades': undefined,
        }, market);
    }
    /**
     * @method
     * @name kucoin#fetchOrderTrades
     * @description fetch all the trades made from a single order
     * @see https://docs.kucoin.com/#list-fills
     * @see https://docs.kucoin.com/spot-hf/#transaction-details
     * @param {string} id order id
     * @param {string} symbol unified market symbol
     * @param {int} [since] the earliest time in ms to fetch trades for
     * @param {int} [limit] the maximum number of trades to retrieve
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=trade-structure}
     */
    async fetchOrderTrades(id, symbol = undefined, since = undefined, limit = undefined, params = {}) {
        const request = {
            'orderId': id,
        };
        return await this.fetchMyTrades(symbol, since, limit, this.extend(request, params));
    }
    /**
     * @method
     * @name kucoin#fetchMyTrades
     * @see https://docs.kucoin.com/#list-fills
     * @see https://docs.kucoin.com/spot-hf/#transaction-details
     * @description 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 {object} [params] extra parameters specific to the exchange API endpoint
     * @param {int} [params.until] the latest time in ms to fetch entries for
     * @param {bool} [params.hf] false, // true for hf order
     * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
     * @returns {Trade[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=trade-structure}
     */
    async fetchMyTrades(symbol = undefined, since = undefined, limit = undefined, params = {}) {
        await this.loadMarkets();
        let paginate = false;
        [paginate, params] = this.handleOptionAndParams(params, 'fetchMyTrades', 'paginate');
        if (paginate) {
            return await this.fetchPaginatedCallDynamic('fetchMyTrades', symbol, since, limit, params);
        }
        let request = {};
        let hf = undefined;
        [hf, params] = this.handleHfAndParams(params);
        if (hf && symbol === undefined) {
            throw new errors.ArgumentsRequired(this.id + ' fetchMyTrades() requires a symbol parameter for hf orders');
        }
        let market = undefined;
        if (symbol !== undefined) {
            market = this.market(symbol);
            request['symbol'] = market['id'];
        }
        const method = this.options['fetchMyTradesMethod'];
        let parseResponseData = false;
        let response = undefined;
        [request, params] = this.handleUntilOption('endAt', request, params);
        if (hf) {
            // does not return trades earlier than 2019-02-18T00:00:00Z
            if (limit !== undefined) {
                request['limit'] = limit;
            }
            if (since !== undefined) {
                // only returns trades up to one week after the since param
                request['startAt'] = since;
            }
            response = await this.privateGetHfFills(this.extend(request, params));
        }
        else if (method === 'private_get_fills') {
            // does not return trades earlier than 2019-02-18T00:00:00Z
            if (since !== undefined) {
                // only returns trades up to one week after the since param
                request['startAt'] = since;
            }
            response = await this.privateGetFills(this.extend(request, params));
        }
        else if (method === 'private_get_limit_fills') {
            // does not return trades earlier than 2019-02-18T00:00:00Z
            // takes no params
            // only returns first 1000 trades (not only "in the last 24 hours" as stated in the docs)
            parseResponseData = true;
            response = await this.privateGetLimitFills(this.extend(request, params));
        }
        else {
            throw new errors.ExchangeError(this.id + ' fetchMyTradesMethod() invalid method');
        }
        //
        //     {
        //         "currentPage": 1,
        //         "pageSize": 50,
        //         "totalNum": 1,
        //         "totalPage": 1,
        //         "items": [
        //             {
        //                 "symbol":"BTC-USDT",       // symbol
        //                 "tradeId":"5c35c02709e4f67d5266954e",        // trade id
        //                 "orderId":"5c35c02703aa673ceec2a168",        // order id
        //                 "counterOrderId":"5c1ab46003aa676e487fa8e3", // counter order id
        //                 "side":"buy",              // transaction direction,include buy and sell
        //                 "liquidity":"taker",       // include taker and maker
        //                 "forceTaker":true,         // forced to become taker
        //                 "price":"0.083",           // order price
        //                 "size":"0.8424304",        // order quantity
        //                 "funds":"0.0699217232",    // order funds
        //                 "fee":"0",                 // fee
        //                 "feeRate":"0",             // fee rate
        //                 "feeCurrency":"USDT",      // charge fee currency
        //                 "stop":"",                 // stop type
        //                 "type":"limit",            // order type, e.g. limit, market, stop_limit.
        //                 "createdAt":1547026472000  // time
        //             },
        //             //------------------------------------------------------
        //             // v1 (historical) trade response structure
        //             {
        //                 "symbol": "SNOV-ETH",
        //                 "dealPrice": "0.0000246",
        //                 "dealValue": "0.018942",
        //                 "amount": "770",
        //                 "fee": "0.00001137",
        //                 "side": "sell",
        //                 "createdAt": 1540080199
        //                 "id":"5c4d389e4c8c60413f78e2e5",
        //             }
        //         ]
        //     }
        //
        const data = this.safeDict(response, 'data', {});
        let trades = undefined;
        if (parseResponseData) {
            trades = data;
        }
        else {
            trades = this.safeList(data, 'items', []);
        }
        return this.parseTrades(trades, market, since, limit);
    }
    /**
     * @method
     * @name kucoin#fetchTrades
     * @description get the list of most recent trades for a particular symbol
     * @see https://www.kucoin.com/docs/rest/spot-trading/market-data/get-trade-histories
     * @param {string} symbol unified symbol of the market to fetch trades for
     * @param {int} [since] timestamp in ms of the earliest trade to fetch
     * @param {int} [limit] the maximum amount of trades to fetch
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {Trade[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=public-trades}
     */
    async fetchTrades(symbol, since = undefined, limit = undefined, params = {}) {
        await this.loadMarkets();
        const market = this.market(symbol);
        const request = {
            'symbol': market['id'],
        };
        // pagination is not supported on the exchange side anymore
        // if (since !== undefined) {
        //     request['startAt'] = Math.floor (since / 1000);
        // }
        // if (limit !== undefined) {
        //     request['pageSize'] = limit;
        // }
        const response = await this.publicGetMarketHistories(this.extend(request, params));
        //
        //     {
        //         "code": "200000",
        //         "data": [
        //             {
        //                 "sequence": "1548764654235",
        //                 "side": "sell",
        //                 "size":"0.6841354",
        //                 "price":"0.03202",
        //                 "time":1548848575203567174
        //             }
        //         ]
        //     }
        //
        const trades = this.safeList(response, 'data', []);
        return this.parseTrades(trades, market, since, limit);
    }
    parseTrade(trade, market = undefined) {
        //
        // fetchTrades (public)
        //
        //     {
        //         "sequence": "1548764654235",
        //         "side": "sell",
        //         "size":"0.6841354",
        //         "price":"0.03202",
        //         "time":1548848575203567174
        //     }
        //
        //     {
        //         "sequence": "1568787654360",
        //         "symbol": "BTC-USDT",
        //         "side": "buy",
        //         "size": "0.00536577",
        //         "price": "9345",
        //         "takerOrderId": "5e356c4a9f1a790008f8d921",
        //         "time": "1580559434436443257",
        //         "type": "match",
        //         "makerOrderId": "5e356bffedf0010008fa5d7f",
        //         "tradeId": "5e356c4aeefabd62c62a1ece"
        //     }
        //
        // fetchMyTrades (private) v2
        //
        //     {
        //         "symbol":"BTC-USDT",
        //         "tradeId":"5c35c02709e4f67d5266954e",
        //         "orderId":"5c35c02703aa673ceec2a168",
        //         "counterOrderId":"5c1ab46003aa676e487fa8e3",
        //         "side":"buy",
        //         "liquidity":"taker",
        //         "forceTaker":true,
        //         "price":"0.083",
        //         "size":"0.8424304",
        //         "funds":"0.0699217232",
        //         "fee":"0",
        //         "feeRate":"0",
        //         "feeCurrency":"USDT",
        //         "stop":"",
        //         "type":"limit",
        //         "createdAt":1547026472000
        //     }
        //
        // fetchMyTrades v2 alternative format since 2019-05-21 https://github.com/ccxt/ccxt/pull/5162
        //
        //     {
        //         "symbol": "OPEN-BTC",
        //         "forceTaker":  false,
        //         "orderId": "5ce36420054b4663b1fff2c9",
        //         "fee": "0",
        //         "feeCurrency": "",
        //         "type": "",
        //         "feeRate": "0",
        //         "createdAt": 1558417615000,
        //         "size": "12.8206",
        //         "stop": "",
        //         "price": "0",
        //         "funds": "0",
        //         "tradeId": "5ce390cf6e0db23b861c6e80"
        //     }
        //
        // fetchMyTrades (private) v1 (historical)
        //
        //     {
        //         "symbol": "SNOV-ETH",
        //         "dealPrice": "0.0000246",
        //         "dealValue": "0.018942",
        //         "amount": "770",
        //         "fee": "0.00001137",
        //         "side": "sell",
        //         "createdAt": 1540080199
        //         "id":"5c4d389e4c8c60413f78e2e5",
        //     }
        //
        const marketId = this.safeString(trade, 'symbol');
        market = this.safeMarket(marketId, market, '-');
        const id = this.safeString2(trade, 'tradeId', 'id');
        const orderId = this.safeString(trade, 'orderId');
        const takerOrMaker = this.safeString(trade, 'liquidity');
        let timestamp = this.safeInteger(trade, 'time');
        if (timestamp !== undefined) {
            timestamp = this.parseToInt(timestamp / 1000000);
        }
        else {
            timestamp = this.safeInteger(trade, 'createdAt');
            // if it's a historical v1 trade, the exchange returns timestamp in seconds
            if (('dealValue' in trade) && (timestamp !== undefined)) {
                timestamp = timestamp * 1000;
            }
        }
        const priceString = this.safeString2(trade, 'price', 'dealPrice');
        const amountString = this.safeString2(trade, 'size', 'amount');
        const side = this.safeString(trade, 'side');
        let fee = undefined;
        const feeCostString = this.safeString(trade, 'fee');
        if (feeCostString !== undefined) {
            const feeCurrencyId = this.safeString(trade, 'feeCurrency');
            let feeCurrency = this.safeCurrencyCode(feeCurrencyId);
            if (feeCurrency === undefined) {
                feeCurrency = (side === 'sell') ? market['quote'] : market['base'];
            }
            fee = {
                'cost': feeCostString,
                'currency': feeCurrency,
                'rate': this.safeString(trade, 'feeRate'),
            };
        }
        let type = this.safeString(trade, 'type');
        if (type === 'match') {
            type = undefined;
        }
        const costString = this.safeString2(trade, 'funds', 'dealValue');
        return this.safeTrade({
            'info': trade,
            'id': id,
            'order': orderId,
            'timestamp': timestamp,
            'datetime': this.iso8601(timestamp),
            'symbol': market['symbol'],
            'type': type,
            'takerOrMaker': takerOrMaker,
            'side': side,
            'price': priceString,
            'amount': amountString,
            'cost': costString,
            'fee': fee,
        }, market);
    }
    /**
     * @method
     * @name kucoin#fetchTradingFee
     * @description fetch the trading fees for a market
     * @see https://www.kucoin.com/docs/rest/funding/trade-fee/trading-pair-actual-fee-spot-margin-trade_hf
     * @param {string} symbol unified market symbol
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {object} a [fee structure]{@link https://docs.ccxt.com/#/?id=fee-structure}
     */
    async fetchTradingFee(symbol, params = {}) {
        await this.loadMarkets();
        const market = this.market(symbol);
        const request = {
            'symbols': market['id'],
        };
        const response = await this.privateGetTradeFees(this.extend(request, params));
        //
        //     {
        //         "code": "200000",
        //         "data": [
        //           {
        //             "symbol": "BTC-USDT",
        //             "takerFeeRate": "0.001",
        //             "makerFeeRate": "0.001"
        //           }
        //         ]
        //     }
        //
        const data = this.safeList(response, 'data', []);
        const first = this.safeDict(data, 0);
        const marketId = this.safeString(first, 'symbol');
        return {
            'info': response,
            'symbol': this.safeSymbol(marketId, market),
            'maker': this.safeNumber(first, 'makerFeeRate'),
            'taker': this.safeNumber(first, 'takerFeeRate'),
            'percentage': true,
            'tierBased': true,
        };
    }
    /**
     * @method
     * @name kucoin#withdraw
     * @description make a withdrawal
     * @see https://www.kucoin.com/docs/rest/funding/withdrawals/apply-withdraw-v3-
     * @param {string} code unified currency code
     * @param {float} amount the amount to withdraw
     * @param {string} address the address to withdraw to
     * @param {string} tag
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {object} a [transaction structure]{@link https://docs.ccxt.com/#/?id=transaction-structure}
     */
    async withdraw(code, amount, address, tag = undefined, params = {}) {
        [tag, params] = this.handleWithdrawTagAndParams(tag, params);
        await this.loadMarkets();
        this.checkAddress(address);
        const currency = this.currency(code);
        const request = {
            'currency': currency['id'],
            'toAddress': address,
            'withdrawType': 'ADDRESS',
            // 'memo': tag,
            // 'isInner': false, // internal transfer or external withdrawal
            // 'remark': 'optional',
            // 'chain': 'OMNI', // 'ERC20', 'TRC20', default is ERC20, This only apply for multi-chain currency, and there is no need for single chain currency.
        };
        if (tag !== undefined) {
            request['memo'] = tag;
        }
        let networkCode = undefined;
        [networkCode, params] = this.handleNetworkCodeAndParams(params);
        if (networkCode !== undefined) {
            request['chain'] = this.networkCodeToId(networkCode).toLowerCase();
        }
        request['amount'] = parseFloat(this.currencyToPrecision(code, amount, networkCode));
        let includeFee = undefined;
        [includeFee, params] = this.handleOptionAndParams(params, 'withdraw', 'includeFee', false);
        if (includeFee) {
            request['feeDeductType'] = 'INTERNAL';
        }
        const response = await this.privatePostWithdrawals(this.extend(request, params));
        //
        // the id is inside "data"
        //
        //     {
        //         "code":  200000,
        //         "data": {
        //             "withdrawalId":  "5bffb63303aa675e8bbe18f9"
        //         }
        //     }
        //
        const data = this.safeDict(response, 'data', {});
        return this.parseTransaction(data, currency);
    }
    parseTransactionStatus(status) {
        const statuses = {
            'SUCCESS': 'ok',
            'PROCESSING': 'pending',
            'WALLET_PROCESSING': 'pending',
            'FAILURE': 'failed',
        };
        return this.safeString(statuses, status, status);
    }
    parseTransaction(transaction, currency = undefined) {
        //
        // fetchDeposits
        //
        //     {
        //         "address": "0x5f047b29041bcfdbf0e4478cdfa753a336ba6989",
        //         "memo": "5c247c8a03aa677cea2a251d",
        //         "amount": 1,
        //         "fee": 0.0001,
        //         "currency": "KCS",
        //         "chain": "",
        //         "isInner": false,
        //         "walletTxId": "5bbb57386d99522d9f954c5a@test004",
        //         "status": "SUCCESS",
        //         "createdAt": 1544178843000,
        //         "updatedAt": 1544178891000
        //         "remark":"foobar"
        //     }
        //
        // fetchWithdrawals
        //
        //     {
        //         "id": "5c2dc64e03aa675aa263f1ac",
        //         "address": "0x5bedb060b8eb8d823e2414d82acce78d38be7fe9",
        //         "memo": "",
        //         "currency": "ETH",
        //         "chain": "",
        //         "amount": 1.0000000,
        //         "fee": 0.0100000,
        //         "walletTxId": "3e2414d82acce78d38be7fe9",
        //         "isInner": false,
        //         "status": "FAILURE",
        //         "createdAt": 1546503758000,
        //         "updatedAt": 1546504603000
        //         "remark":"foobar"
        //     }
        //
        // withdraw
        //
        //     {
        //         "withdrawalId":  "5bffb63303aa675e8bbe18f9"
        //     }
        //
        const currencyId = this.safeString(transaction, 'currency');
        const code = this.safeCurrencyCode(currencyId, currency);
        let address = this.safeString(transaction, 'address');
        const amount = this.safeString(transaction, 'amount');
        let txid = this.safeString(transaction, 'walletTxId');
        if (txid !== undefined) {
            const txidParts = txid.split('@');
            const numTxidParts = txidParts.length;
            if (numTxidParts > 1) {
                if (address === undefined) {
                    if (txidParts[1].length > 1) {
                        address = txidParts[1];
                    }
                }
            }
            txid = txidParts[0];
        }
        let type = (txid === undefined) ? 'withdrawal' : 'deposit';
        const rawStatus = this.safeString(transaction, 'status');
        let fee = undefined;
        const feeCost = this.safeString(transaction, 'fee');
        if (feeCost !== undefined) {
            let rate = undefined;
            if (amount !== undefined) {
                rate = Precise["default"].stringDiv(feeCost, amount);
            }
            fee = {
                'cost': this.parseNumber(feeCost),
                'rate': this.parseNumber(rate),
                'currency': code,
            };
        }
        let timestamp = this.safeInteger2(transaction, 'createdAt', 'createAt');
        let updated = this.safeInteger(transaction, 'updatedAt');
        const isV1 = !('createdAt' in transaction);
        // if it's a v1 structure
        if (isV1) {
            type = ('address' in transaction) ? 'withdrawal' : 'deposit';
            if (timestamp !== undefined) {
                timestamp = timestamp * 1000;
            }
            if (updated !== undefined) {
                updated = updated * 1000;
            }
        }
        const internal = this.safeBool(transaction, 'isInner');
        const tag = this.safeString(transaction, 'memo');
        return {
            'info': transaction,
            'id': this.safeString2(transaction, 'id', 'withdrawalId'),
            'timestamp': timestamp,
            'datetime': this.iso8601(timestamp),
            'network': this.networkIdToCode(this.safeString(transaction, 'chain')),
            'address': address,
            'addressTo': address,
            'addressFrom': undefined,
            'tag': tag,
            'tagTo': tag,
            'tagFrom': undefined,
            'currency': code,
            'amount': this.parseNumber(amount),
            'txid': txid,
            'type': type,
            'status': this.parseTransactionStatus(rawStatus),
            'comment': this.safeString(transaction, 'remark'),
            'internal': internal,
            'fee': fee,
            'updated': updated,
        };
    }
    /**
     * @method
     * @name kucoin#fetchDeposits
     * @description fetch all deposits made to an account
     * @see https://www.kucoin.com/docs/rest/funding/deposit/get-deposit-list
     * @see https://www.kucoin.com/docs/rest/funding/deposit/get-v1-historical-deposits-list
     * @param {string} code unified currency code
     * @param {int} [since] the earliest time in ms to fetch deposits for
     * @param {int} [limit] the maximum number of deposits structures to retrieve
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @param {int} [params.until] the latest time in ms to fetch entries for
     * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
     * @returns {object[]} a list of [transaction structures]{@link https://docs.ccxt.com/#/?id=transaction-structure}
     */
    async fetchDeposits(code = undefined, since = undefined, limit = undefined, params = {}) {
        await this.loadMarkets();
        let paginate = false;
        [paginate, params] = this.handleOptionAndParams(params, 'fetchDeposits', 'paginate');
        if (paginate) {
            return await this.fetchPaginatedCallDynamic('fetchDeposits', code, since, limit, params);
        }
        let request = {};
        let currency = undefined;
        if (code !== undefined) {
            currency = this.currency(code);
            request['currency'] = currency['id'];
        }
        if (limit !== undefined) {
            request['pageSize'] = limit;
        }
        [request, params] = this.handleUntilOption('endAt', request, params);
        let response = undefined;
        if (since !== undefined && since < 1550448000000) {
            // if since is earlier than 2019-02-18T00:00:00Z
            request['startAt'] = this.parseToInt(since / 1000);
            response = await this.privateGetHistDeposits(this.extend(request, params));
        }
        else {
            if (since !== undefined) {
                request['startAt'] = since;
            }
            response = await this.privateGetDeposits(this.extend(request, params));
        }
        //
        //     {
        //         "code": "200000",
        //         "data": {
        //             "currentPage": 1,
        //             "pageSize": 5,
        //             "totalNum": 2,
        //             "totalPage": 1,
        //             "items": [
        //                 //--------------------------------------------------
        //                 // version 2 deposit response structure
        //                 {
        //                     "address": "0x5f047b29041bcfdbf0e4478cdfa753a336ba6989",
        //                     "memo": "5c247c8a03aa677cea2a251d",
        //                     "amount": 1,
        //                     "fee": 0.0001,
        //                     "currency": "KCS",
        //                     "isInner": false,
        //                     "walletTxId": "5bbb57386d99522d9f954c5a@test004",
        //                     "status": "SUCCESS",
        //                     "createdAt": 1544178843000,
        //                     "updatedAt": 1544178891000
        //                     "remark":"foobar"
        //                 },
        //                 //--------------------------------------------------
        //                 // version 1 (historical) deposit response structure
        //                 {
        //                     "currency": "BTC",
        //                     "createAt": 1528536998,
        //                     "amount": "0.03266638",
        //                     "walletTxId": "55c643bc2c68d6f17266383ac1be9e454038864b929ae7cee0bc408cc5c869e8@12ffGWmMMD1zA1WbFm7Ho3JZ1w6NYXjpFk@234",
        //                     "isInner": false,
        //                     "status": "SUCCESS",
        //                 }
        //             ]
        //         }
        //     }
        //
        const data = this.safeDict(response, 'data', {});
        const items = this.safeList(data, 'items', []);
        return this.parseTransactions(items, currency, since, limit, { 'type': 'deposit' });
    }
    /**
     * @method
     * @name kucoin#fetchWithdrawals
     * @description fetch all withdrawals made from an account
     * @see https://www.kucoin.com/docs/rest/funding/withdrawals/get-withdrawals-list
     * @see https://www.kucoin.com/docs/rest/funding/withdrawals/get-v1-historical-withdrawals-list
     * @param {string} code unified currency code
     * @param {int} [since] the earliest time in ms to fetch withdrawals for
     * @param {int} [limit] the maximum number of withdrawals structures to retrieve
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @param {int} [params.until] the latest time in ms to fetch entries for
     * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
     * @returns {object[]} a list of [transaction structures]{@link https://docs.ccxt.com/#/?id=transaction-structure}
     */
    async fetchWithdrawals(code = undefined, since = undefined, limit = undefined, params = {}) {
        await this.loadMarkets();
        let paginate = false;
        [paginate, params] = this.handleOptionAndParams(params, 'fetchWithdrawals', 'paginate');
        if (paginate) {
            return await this.fetchPaginatedCallDynamic('fetchWithdrawals', code, since, limit, params);
        }
        let request = {};
        let currency = undefined;
        if (code !== undefined) {
            currency = this.currency(code);
            request['currency'] = currency['id'];
        }
        if (limit !== undefined) {
            request['pageSize'] = limit;
        }
        [request, params] = this.handleUntilOption('endAt', request, params);
        let response = undefined;
        if (since !== undefined && since < 1550448000000) {
            // if since is earlier than 2019-02-18T00:00:00Z
            request['startAt'] = this.parseToInt(since / 1000);
            response = await this.privateGetHistWithdrawals(this.extend(request, params));
        }
        else {
            if (since !== undefined) {
                request['startAt'] = since;
            }
            response = await this.privateGetWithdrawals(this.extend(request, params));
        }
        //
        //     {
        //         "code": "200000",
        //         "data": {
        //             "currentPage": 1,
        //             "pageSize": 5,
        //             "totalNum": 2,
        //             "totalPage": 1,
        //             "items": [
        //                 //--------------------------------------------------
        //                 // version 2 withdrawal response structure
        //                 {
        //                     "id": "5c2dc64e03aa675aa263f1ac",
        //                     "address": "0x5bedb060b8eb8d823e2414d82acce78d38be7fe9",
        //                     "memo": "",
        //                     "currency": "ETH",
        //                     "amount": 1.0000000,
        //                     "fee": 0.0100000,
        //                     "walletTxId": "3e2414d82acce78d38be7fe9",
        //                     "isInner": false,
        //                     "status": "FAILURE",
        //                     "createdAt": 1546503758000,
        //                     "updatedAt": 1546504603000
        //                 },
        //                 //--------------------------------------------------
        //                 // version 1 (historical) withdrawal response structure
        //                 {
        //                     "currency": "BTC",
        //                     "createAt": 1526723468,
        //                     "amount": "0.534",
        //                     "address": "33xW37ZSW4tQvg443Pc7NLCAs167Yc2XUV",
        //                     "walletTxId": "aeacea864c020acf58e51606169240e96774838dcd4f7ce48acf38e3651323f4",
        //                     "isInner": false,
        //                     "status": "SUCCESS"
        //                 }
        //             ]
        //         }
        //     }
        //
        const data = this.safeDict(response, 'data', {});
        const items = this.safeList(data, 'items', []);
        return this.parseTransactions(items, currency, since, limit, { 'type': 'withdrawal' });
    }
    parseBalanceHelper(entry) {
        const account = this.account();
        account['used'] = this.safeString2(entry, 'holdBalance', 'hold');
        account['free'] = this.safeString2(entry, 'availableBalance', 'available');
        account['total'] = this.safeString2(entry, 'totalBalance', 'total');
        const debt = this.safeString(entry, 'liability');
        const interest = this.safeString(entry, 'interest');
        account['debt'] = Precise["default"].stringAdd(debt, interest);
        return account;
    }
    /**
     * @method
     * @name kucoin#fetchBalance
     * @description query for balance and get the amount of funds available for trading or funds locked in orders
     * @see https://www.kucoin.com/docs/rest/account/basic-info/get-account-list-spot-margin-trade_hf
     * @see https://www.kucoin.com/docs/rest/funding/funding-overview/get-account-detail-margin
     * @see https://www.kucoin.com/docs/rest/funding/funding-overview/get-account-detail-isolated-margin
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @param {object} [params.marginMode] 'cross' or 'isolated', margin type for fetching margin balance
     * @param {object} [params.type] extra parameters specific to the exchange API endpoint
     * @param {object} [params.hf] *default if false* if true, the result includes the balance of the high frequency account
     * @returns {object} a [balance structure]{@link https://docs.ccxt.com/#/?id=balance-structure}
     */
    async fetchBalance(params = {}) {
        await this.loadMarkets();
        const code = this.safeString(params, 'code');
        let currency = undefined;
        if (code !== undefined) {
            currency = this.currency(code);
        }
        const defaultType = this.safeString2(this.options, 'fetchBalance', 'defaultType', 'spot');
        const requestedType = this.safeString(params, 'type', defaultType);
        const accountsByType = this.safeDict(this.options, 'accountsByType');
        let type = this.safeString(accountsByType, requestedType, requestedType);
        params = this.omit(params, 'type');
        let hf = undefined;
        [hf, params] = this.handleHfAndParams(params);
        if (hf && (type !== 'main')) {
            type = 'trade_hf';
        }
        const [marginMode, query] = this.handleMarginModeAndParams('fetchBalance', params);
        let response = undefined;
        const request = {};
        const isolated = (marginMode === 'isolated') || (type === 'isolated');
        const cross = (marginMode === 'cross') || (type === 'margin');
        if (isolated) {
            if (currency !== undefined) {
                request['balanceCurrency'] = currency['id'];
            }
            response = await this.privateGetIsolatedAccounts(this.extend(request, query));
        }
        else if (cross) {
            response = await this.privateGetMarginAccount(this.extend(request, query));
        }
        else {
            if (currency !== undefined) {
                request['currency'] = currency['id'];
            }
            request['type'] = type;
            response = await this.privateGetAccounts(this.extend(request, query));
        }
        //
        // Spot
        //
        //    {
        //        "code": "200000",
        //        "data": [
        //            {
        //                "balance": "0.00009788",
        //                "available": "0.00009788",
        //                "holds": "0",
        //                "currency": "BTC",
        //                "id": "5c6a4fd399a1d81c4f9cc4d0",
        //                "type": "trade",
        //            },
        //        ]
        //    }
        //
        // Cross
        //
        //     {
        //         "code": "200000",
        //         "data": {
        //             "debtRatio": "0",
        //             "accounts": [
        //                 {
        //                     "currency": "USDT",
        //                     "totalBalance": "5",
        //                     "availableBalance": "5",
        //                     "holdBalance": "0",
        //                     "liability": "0",
        //                     "maxBorrowSize": "20"
        //                 },
        //             ]
        //         }
        //     }
        //
        // Isolated
        //
        //    {
        //        "code": "200000",
        //        "data": {
        //            "totalAssetOfQuoteCurrency": "0",
        //            "totalLiabilityOfQuoteCurrency": "0",
        //            "timestamp": 1712085661155,
        //            "assets": [
        //                {
        //                    "symbol": "MANA-USDT",
        //                    "status": "EFFECTIVE",
        //                    "debtRatio": "0",
        //                    "baseAsset": {
        //                        "currency": "MANA",
        //                        "borrowEnabled": true,
        //                        "transferInEnabled": true,
        //                        "total": "0",
        //                        "hold": "0",
        //                        "available": "0",
        //                        "liability": "0",
        //                        "interest": "0",
        //                        "maxBorrowSize": "0"
        //                    },
        //                    "quoteAsset": {
        //                        "currency": "USDT",
        //                        "borrowEnabled": true,
        //                        "transferInEnabled": true,
        //                        "total": "0",
        //                        "hold": "0",
        //                        "available": "0",
        //                        "liability": "0",
        //                        "interest": "0",
        //                        "maxBorrowSize": "0"
        //                    }
        //                },
        //                ...
        //            ]
        //        }
        //    }
        //
        let data = undefined;
        const result = {
            'info': response,
            'timestamp': undefined,
            'datetime': undefined,
        };
        if (isolated) {
            data = this.safeDict(response, 'data', {});
            const assets = this.safeValue(data, 'assets', data);
            for (let i = 0; i < assets.length; i++) {
                const entry = assets[i];
                const marketId = this.safeString(entry, 'symbol');
                const symbol = this.safeSymbol(marketId, undefined, '_');
                const base = this.safeDict(entry, 'baseAsset', {});
                const quote = this.safeDict(entry, 'quoteAsset', {});
                const baseCode = this.safeCurrencyCode(this.safeString(base, 'currency'));
                const quoteCode = this.safeCurrencyCode(this.safeString(quote, 'currency'));
                const subResult = {};
                subResult[baseCode] = this.parseBalanceHelper(base);
                subResult[quoteCode] = this.parseBalanceHelper(quote);
                result[symbol] = this.safeBalance(subResult);
            }
        }
        else if (cross) {
            data = this.safeDict(response, 'data', {});
            const accounts = this.safeList(data, 'accounts', []);
            for (let i = 0; i < accounts.length; i++) {
                const balance = accounts[i];
                const currencyId = this.safeString(balance, 'currency');
                const codeInner = this.safeCurrencyCode(currencyId);
                result[codeInner] = this.parseBalanceHelper(balance);
            }
        }
        else {
            data = this.safeList(response, 'data', []);
            for (let i = 0; i < data.length; i++) {
                const balance = data[i];
                const balanceType = this.safeString(balance, 'type');
                if (balanceType === type) {
                    const currencyId = this.safeString(balance, 'currency');
                    const codeInner2 = this.safeCurrencyCode(currencyId);
                    const account = this.account();
                    account['total'] = this.safeString(balance, 'balance');
                    account['free'] = this.safeString(balance, 'available');
                    account['used'] = this.safeString(balance, 'holds');
                    result[codeInner2] = account;
                }
            }
        }
        let returnType = result;
        if (!isolated) {
            returnType = this.safeBalance(result);
        }
        return returnType;
    }
    /**
     * @method
     * @name kucoin#transfer
     * @description transfer currency internally between wallets on the same account
     * @see https://www.kucoin.com/docs/rest/funding/transfer/inner-transfer
     * @see https://docs.kucoin.com/futures/#transfer-funds-to-kucoin-main-account-2
     * @see https://docs.kucoin.com/spot-hf/#internal-funds-transfers-in-high-frequency-trading-accounts
     * @param {string} code unified currency code
     * @param {float} amount amount to transfer
     * @param {string} fromAccount account to transfer from
     * @param {string} toAccount account to transfer to
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {object} a [transfer structure]{@link https://docs.ccxt.com/#/?id=transfer-structure}
     */
    async transfer(code, amount, fromAccount, toAccount, params = {}) {
        await this.loadMarkets();
        const currency = this.currency(code);
        const requestedAmount = this.currencyToPrecision(code, amount);
        let fromId = this.convertTypeToAccount(fromAccount);
        let toId = this.convertTypeToAccount(toAccount);
        const fromIsolated = this.inArray(fromId, this.ids);
        const toIsolated = this.inArray(toId, this.ids);
        if (fromId === 'contract') {
            if (toId !== 'main') {
                throw new errors.ExchangeError(this.id + ' transfer() only supports transferring from futures account to main account');
            }
            const request = {
                'currency': currency['id'],
                'amount': requestedAmount,
            };
            if (!('bizNo' in params)) {
                // it doesn't like more than 24 characters
                request['bizNo'] = this.uuid22();
            }
            const response = await this.futuresPrivatePostTransferOut(this.extend(request, params));
            //
            //     {
            //         "code": "200000",
            //         "data": {
            //             "applyId": "605a87217dff1500063d485d",
            //             "bizNo": "bcd6e5e1291f4905af84dc",
            //             "payAccountType": "CONTRACT",
            //             "payTag": "DEFAULT",
            //             "remark": '',
            //             "recAccountType": "MAIN",
            //             "recTag": "DEFAULT",
            //             "recRemark": '',
            //             "recSystem": "KUCOIN",
            //             "status": "PROCESSING",
            //             "currency": "XBT",
            //             "amount": "0.00001",
            //             "fee": "0",
            //             "sn": "573688685663948",
            //             "reason": '',
            //             "createdAt": 1616545569000,
            //             "updatedAt": 1616545569000
            //         }
            //     }
            //
            const data = this.safeDict(response, 'data');
            return this.parseTransfer(data, currency);
        }
        else {
            const request = {
                'currency': currency['id'],
                'amount': requestedAmount,
            };
            if (fromIsolated || toIsolated) {
                if (this.inArray(fromId, this.ids)) {
                    request['fromTag'] = fromId;
                    fromId = 'isolated';
                }
                if (this.inArray(toId, this.ids)) {
                    request['toTag'] = toId;
                    toId = 'isolated';
                }
            }
            request['from'] = fromId;
            request['to'] = toId;
            if (!('clientOid' in params)) {
                request['clientOid'] = this.uuid();
            }
            const response = await this.privatePostAccountsInnerTransfer(this.extend(request, params));
            //
            //     {
            //         "code": "200000",
            //         "data": {
            //              "orderId": "605a6211e657f00006ad0ad6"
            //         }
            //     }
            //
            const data = this.safeDict(response, 'data');
            return this.parseTransfer(data, currency);
        }
    }
    parseTransfer(transfer, currency = undefined) {
        //
        // transfer (spot)
        //
        //    {
        //        "orderId": "605a6211e657f00006ad0ad6"
        //    }
        //
        //    {
        //        "code": "200000",
        //        "msg": "Failed to transfer out. The amount exceeds the upper limit"
        //    }
        //
        // transfer (futures)
        //
        //     {
        //         "applyId": "605a87217dff1500063d485d",
        //         "bizNo": "bcd6e5e1291f4905af84dc",
        //         "payAccountType": "CONTRACT",
        //         "payTag": "DEFAULT",
        //         "remark": '',
        //         "recAccountType": "MAIN",
        //         "recTag": "DEFAULT",
        //         "recRemark": '',
        //         "recSystem": "KUCOIN",
        //         "status": "PROCESSING",
        //         "currency": "XBT",
        //         "amount": "0.00001",
        //         "fee": "0",
        //         "sn": "573688685663948",
        //         "reason": '',
        //         "createdAt": 1616545569000,
        //         "updatedAt": 1616545569000
        //     }
        //
        const timestamp = this.safeInteger(transfer, 'createdAt');
        const currencyId = this.safeString(transfer, 'currency');
        const rawStatus = this.safeString(transfer, 'status');
        const accountFromRaw = this.safeStringLower(transfer, 'payAccountType');
        const accountToRaw = this.safeStringLower(transfer, 'recAccountType');
        const accountsByType = this.safeDict(this.options, 'accountsByType');
        const accountFrom = this.safeString(accountsByType, accountFromRaw, accountFromRaw);
        const accountTo = this.safeString(accountsByType, accountToRaw, accountToRaw);
        return {
            'id': this.safeString2(transfer, 'applyId', 'orderId'),
            'currency': this.safeCurrencyCode(currencyId, currency),
            'timestamp': timestamp,
            'datetime': this.iso8601(timestamp),
            'amount': this.safeNumber(transfer, 'amount'),
            'fromAccount': accountFrom,
            'toAccount': accountTo,
            'status': this.parseTransferStatus(rawStatus),
            'info': transfer,
        };
    }
    parseTransferStatus(status) {
        const statuses = {
            'PROCESSING': 'pending',
        };
        return this.safeString(statuses, status, status);
    }
    parseLedgerEntryType(type) {
        const types = {
            'Assets Transferred in After Upgrading': 'transfer',
            'Deposit': 'transaction',
            'Withdrawal': 'transaction',
            'Transfer': 'transfer',
            'Trade_Exchange': 'trade',
            // 'Vote for Coin': 'Vote for Coin', // Vote for Coin
            'KuCoin Bonus': 'bonus',
            'Referral Bonus': 'referral',
            'Rewards': 'bonus',
            // 'Distribution': 'Distribution', // Distribution, such as get GAS by holding NEO
            'Airdrop/Fork': 'airdrop',
            'Other rewards': 'bonus',
            'Fee Rebate': 'rebate',
            'Buy Crypto': 'trade',
            'Sell Crypto': 'sell',
            'Public Offering Purchase': 'trade',
            // 'Send red envelope': 'Send red envelope', // Send red envelope
            // 'Open red envelope': 'Open red envelope', // Open red envelope
            // 'Staking': 'Staking', // Staking
            // 'LockDrop Vesting': 'LockDrop Vesting', // LockDrop Vesting
            // 'Staking Profits': 'Staking Profits', // Staking Profits
            // 'Redemption': 'Redemption', // Redemption
            'Refunded Fees': 'fee',
            'KCS Pay Fees': 'fee',
            'Margin Trade': 'trade',
            'Loans': 'Loans',
            // 'Borrowings': 'Borrowings', // Borrowings
            // 'Debt Repayment': 'Debt Repayment', // Debt Repayment
            // 'Loans Repaid': 'Loans Repaid', // Loans Repaid
            // 'Lendings': 'Lendings', // Lendings
            // 'Pool transactions': 'Pool transactions', // Pool-X transactions
            'Instant Exchange': 'trade',
            'Sub-account transfer': 'transfer',
            'Liquidation Fees': 'fee', // Liquidation Fees
            // 'Soft Staking Profits': 'Soft Staking Profits', // Soft Staking Profits
            // 'Voting Earnings': 'Voting Earnings', // Voting Earnings on Pool-X
            // 'Redemption of Voting': 'Redemption of Voting', // Redemption of Voting on Pool-X
            // 'Voting': 'Voting', // Voting on Pool-X
            // 'Convert to KCS': 'Convert to KCS', // Convert to KCS
        };
        return this.safeString(types, type, type);
    }
    parseLedgerEntry(item, currency = undefined) {
        //
        //     {
        //         "id": "611a1e7c6a053300067a88d9", //unique key for each ledger entry
        //         "currency": "USDT", //Currency
        //         "amount": "10.00059547", //The total amount of assets (fees included) involved in assets changes such as transaction, withdrawal and bonus distribution.
        //         "fee": "0", //Deposit or withdrawal fee
        //         "balance": "0", //Total assets of a currency remaining funds after transaction
        //         "accountType": "MAIN", //Account Type
        //         "bizType": "Loans Repaid", //business type
        //         "direction": "in", //side, in or out
        //         "createdAt": 1629101692950, //Creation time
        //         "context": "{\"borrowerUserId\":\"601ad03e50dc810006d242ea\",\"loanRepayDetailNo\":\"611a1e7cc913d000066cf7ec\"}" //Business core parameters
        //     }
        //
        const id = this.safeString(item, 'id');
        const currencyId = this.safeString(item, 'currency');
        const code = this.safeCurrencyCode(currencyId, currency);
        currency = this.safeCurrency(currencyId, currency);
        const amount = this.safeNumber(item, 'amount');
        const balanceAfter = undefined;
        // const balanceAfter = this.safeNumber (item, 'balance'); only returns zero string
        const bizType = this.safeString(item, 'bizType');
        const type = this.parseLedgerEntryType(bizType);
        const direction = this.safeString(item, 'direction');
        const timestamp = this.safeInteger(item, 'createdAt');
        const datetime = this.iso8601(timestamp);
        const account = this.safeString(item, 'accountType'); // MAIN, TRADE, MARGIN, or CONTRACT
        const context = this.safeString(item, 'context'); // contains other information about the ledger entry
        //
        // withdrawal transaction
        //
        //     "{\"orderId\":\"617bb2d09e7b3b000196dac8\",\"txId\":\"0x79bb9855f86b351a45cab4dc69d78ca09586a94c45dde49475722b98f401b054\"}"
        //
        // deposit to MAIN, trade via MAIN
        //
        //     "{\"orderId\":\"617ab9949e7b3b0001948081\",\"txId\":\"0x7a06b16bbd6b03dbc3d96df5683b15229fc35e7184fd7179a5f3a310bd67d1fa@default@0\"}"
        //
        // sell trade
        //
        //     "{\"symbol\":\"ETH-USDT\",\"orderId\":\"617adcd1eb3fa20001dd29a1\",\"tradeId\":\"617adcd12e113d2b91222ff9\"}"
        //
        let referenceId = undefined;
        if (context !== undefined && context !== '') {
            try {
                const parsed = JSON.parse(context);
                const orderId = this.safeString(parsed, 'orderId');
                const tradeId = this.safeString(parsed, 'tradeId');
                // transactions only have an orderId but for trades we wish to use tradeId
                if (tradeId !== undefined) {
                    referenceId = tradeId;
                }
                else {
                    referenceId = orderId;
                }
            }
            catch (exc) {
                referenceId = context;
            }
        }
        let fee = undefined;
        const feeCost = this.safeString(item, 'fee');
        let feeCurrency = undefined;
        if (feeCost !== '0') {
            feeCurrency = code;
            fee = { 'cost': this.parseNumber(feeCost), 'currency': feeCurrency };
        }
        return this.safeLedgerEntry({
            'info': item,
            'id': id,
            'direction': direction,
            'account': account,
            'referenceId': referenceId,
            'referenceAccount': account,
            'type': type,
            'currency': code,
            'amount': amount,
            'timestamp': timestamp,
            'datetime': datetime,
            'before': undefined,
            'after': balanceAfter,
            'status': undefined,
            'fee': fee,
        }, currency);
    }
    /**
     * @method
     * @name kucoin#fetchLedger
     * @description fetch the history of changes, actions done by the user or operations that altered the balance of the user
     * @see https://www.kucoin.com/docs/rest/account/basic-info/get-account-ledgers-spot-margin
     * @see https://www.kucoin.com/docs/rest/account/basic-info/get-account-ledgers-trade_hf
     * @see https://www.kucoin.com/docs/rest/account/basic-info/get-account-ledgers-margin_hf
     * @param {string} [code] unified currency code, default is undefined
     * @param {int} [since] timestamp in ms of the earliest ledger entry, default is undefined
     * @param {int} [limit] max number of ledger entries to return, default is undefined
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @param {boolean} [params.hf] default false, when true will fetch ledger entries for the high frequency trading account
     * @param {int} [params.until] the latest time in ms to fetch entries for
     * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [available parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
     * @returns {object} a [ledger structure]{@link https://docs.ccxt.com/#/?id=ledger}
     */
    async fetchLedger(code = undefined, since = undefined, limit = undefined, params = {}) {
        await this.loadMarkets();
        await this.loadAccounts();
        let paginate = false;
        [paginate, params] = this.handleOptionAndParams(params, 'fetchLedger', 'paginate');
        let hf = undefined;
        [hf, params] = this.handleHfAndParams(params);
        if (paginate) {
            return await this.fetchPaginatedCallDynamic('fetchLedger', code, since, limit, params);
        }
        let request = {
        // 'currency': currency['id'], // can choose up to 10, if not provided returns for all currencies by default
        // 'direction': 'in', // 'out'
        // 'bizType': 'DEPOSIT', // DEPOSIT, WITHDRAW, TRANSFER, SUB_TRANSFER,TRADE_EXCHANGE, MARGIN_EXCHANGE, KUCOIN_BONUS (optional)
        // 'startAt': since,
        // 'endAt': exchange.milliseconds (),
        };
        if (since !== undefined) {
            request['startAt'] = since;
        }
        // atm only single currency retrieval is supported
        let currency = undefined;
        if (code !== undefined) {
            currency = this.currency(code);
            request['currency'] = currency['id'];
        }
        [request, params] = this.handleUntilOption('endAt', request, params);
        let marginMode = undefined;
        [marginMode, params] = this.handleMarginModeAndParams('fetchLedger', params);
        let response = undefined;
        if (hf) {
            if (marginMode !== undefined) {
                response = await this.privateGetHfMarginAccountLedgers(this.extend(request, params));
            }
            else {
                response = await this.privateGetHfAccountsLedgers(this.extend(request, params));
            }
        }
        else {
            response = await this.privateGetAccountsLedgers(this.extend(request, params));
        }
        //
        //     {
        //         "code":"200000",
        //         "data":{
        //             "currentPage":1,
        //             "pageSize":50,
        //             "totalNum":1,
        //             "totalPage":1,
        //             "items":[
        //                 {
        //                     "id":"617cc528729f5f0001c03ceb",
        //                     "currency":"GAS",
        //                     "amount":"0.00000339",
        //                     "fee":"0",
        //                     "balance":"0",
        //                     "accountType":"MAIN",
        //                     "bizType":"Distribution",
        //                     "direction":"in",
        //                     "createdAt":1635566888183,
        //                     "context":"{\"orderId\":\"617cc47a1c47ed0001ce3606\",\"description\":\"Holding NEO,distribute GAS(2021/10/30)\"}"
        //                 }
        //                 {
        //                     "id": "611a1e7c6a053300067a88d9",//unique key
        //                     "currency": "USDT", //Currency
        //                     "amount": "10.00059547", //Change amount of the funds
        //                     "fee": "0", //Deposit or withdrawal fee
        //                     "balance": "0", //Total assets of a currency
        //                     "accountType": "MAIN", //Account Type
        //                     "bizType": "Loans Repaid", //business type
        //                     "direction": "in", //side, in or out
        //                     "createdAt": 1629101692950, //Creation time
        //                     "context": "{\"borrowerUserId\":\"601ad03e50dc810006d242ea\",\"loanRepayDetailNo\":\"611a1e7cc913d000066cf7ec\"}"
        //                 },
        //             ]
        //         }
        //     }
        //
        const dataList = this.safeList(response, 'data');
        if (dataList !== undefined) {
            return this.parseLedger(dataList, currency, since, limit);
        }
        const data = this.safeDict(response, 'data');
        const items = this.safeList(data, 'items', []);
        return this.parseLedger(items, currency, since, limit);
    }
    calculateRateLimiterCost(api, method, path, params, config = {}) {
        const versions = this.safeDict(this.options, 'versions', {});
        const apiVersions = this.safeDict(versions, api, {});
        const methodVersions = this.safeDict(apiVersions, method, {});
        const defaultVersion = this.safeString(methodVersions, path, this.options['version']);
        const version = this.safeString(params, 'version', defaultVersion);
        if (version === 'v3' && ('v3' in config)) {
            return config['v3'];
        }
        else if (version === 'v2' && ('v2' in config)) {
            return config['v2'];
        }
        else if (version === 'v1' && ('v1' in config)) {
            return config['v1'];
        }
        return this.safeValue(config, 'cost', 1);
    }
    parseBorrowRate(info, currency = undefined) {
        //
        //     {
        //         "tradeId": "62db2dcaff219600012b56cd",
        //         "currency": "USDT",
        //         "size": "10",
        //         "dailyIntRate": "0.00003",
        //         "term": 7,
        //         "timestamp": 1658531274508488480
        //     },
        //
        //     {
        //         "createdAt": 1697783812257,
        //         "currency": "XMR",
        //         "interestAmount": "0.1",
        //         "dayRatio": "0.001"
        //     }
        //
        const timestampId = this.safeString2(info, 'createdAt', 'timestamp');
        const timestamp = this.parseToInt(timestampId.slice(0, 13));
        const currencyId = this.safeString(info, 'currency');
        return {
            'currency': this.safeCurrencyCode(currencyId, currency),
            'rate': this.safeNumber2(info, 'dailyIntRate', 'dayRatio'),
            'period': 86400000,
            'timestamp': timestamp,
            'datetime': this.iso8601(timestamp),
            'info': info,
        };
    }
    /**
     * @method
     * @name kucoin#fetchBorrowInterest
     * @description fetch the interest owed by the user for borrowing currency for margin trading
     * @see https://docs.kucoin.com/#get-repay-record
     * @see https://docs.kucoin.com/#query-isolated-margin-account-info
     * @param {string} [code] unified currency code
     * @param {string} [symbol] unified market symbol, required for isolated margin
     * @param {int} [since] the earliest time in ms to fetch borrrow interest for
     * @param {int} [limit] the maximum number of structures to retrieve
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @param {string} [params.marginMode] 'cross' or 'isolated' default is 'cross'
     * @returns {object[]} a list of [borrow interest structures]{@link https://docs.ccxt.com/#/?id=borrow-interest-structure}
     */
    async fetchBorrowInterest(code = undefined, symbol = undefined, since = undefined, limit = undefined, params = {}) {
        await this.loadMarkets();
        let marginMode = undefined;
        [marginMode, params] = this.handleMarginModeAndParams('fetchBorrowInterest', params, 'cross');
        const request = {};
        let currency = undefined;
        if (code !== undefined) {
            currency = this.currency(code);
            if (marginMode === 'isolated') {
                request['balanceCurrency'] = currency['id'];
            }
            else {
                request['quoteCurrency'] = currency['id'];
            }
        }
        let market = undefined;
        if (symbol !== undefined) {
            market = this.market(symbol);
        }
        let response = undefined;
        if (marginMode === 'isolated') {
            response = await this.privateGetIsolatedAccounts(this.extend(request, params));
        }
        else {
            response = await this.privateGetMarginAccounts(this.extend(request, params));
        }
        //
        // Cross
        //
        //     {
        //         "code": "200000",
        //         "data": {
        //             "totalAssetOfQuoteCurrency": "0",
        //             "totalLiabilityOfQuoteCurrency": "0",
        //             "debtRatio": "0",
        //             "status": "EFFECTIVE",
        //             "accounts": [
        //                 {
        //                     "currency": "1INCH",
        //                     "total": "0",
        //                     "available": "0",
        //                     "hold": "0",
        //                     "liability": "0",
        //                     "maxBorrowSize": "0",
        //                     "borrowEnabled": true,
        //                     "transferInEnabled": true
        //                 }
        //             ]
        //         }
        //     }
        //
        // Isolated
        //
        //     {
        //         "code": "200000",
        //         "data": {
        //             "totalConversionBalance": "0.02138647",
        //             "liabilityConversionBalance": "0.01480001",
        //             "assets": [
        //                 {
        //                     "symbol": "MANA-USDT",
        //                     "debtRatio": "0",
        //                     "status": "BORROW",
        //                     "baseAsset": {
        //                         "currency": "MANA",
        //                         "borrowEnabled": true,
        //                         "repayEnabled": true,
        //                         "transferEnabled": true,
        //                         "borrowed": "0",
        //                         "totalAsset": "0",
        //                         "available": "0",
        //                         "hold": "0",
        //                         "maxBorrowSize": "1000"
        //                     },
        //                     "quoteAsset": {
        //                         "currency": "USDT",
        //                         "borrowEnabled": true,
        //                         "repayEnabled": true,
        //                         "transferEnabled": true,
        //                         "borrowed": "0",
        //                         "totalAsset": "0",
        //                         "available": "0",
        //                         "hold": "0",
        //                         "maxBorrowSize": "50000"
        //                     }
        //                 }
        //             ]
        //         }
        //     }
        //
        const data = this.safeDict(response, 'data', {});
        const assets = (marginMode === 'isolated') ? this.safeList(data, 'assets', []) : this.safeList(data, 'accounts', []);
        const interest = this.parseBorrowInterests(assets, market);
        const filteredByCurrency = this.filterByCurrencySinceLimit(interest, code, since, limit);
        return this.filterBySymbolSinceLimit(filteredByCurrency, symbol, since, limit);
    }
    parseBorrowInterest(info, market = undefined) {
        //
        // Cross
        //
        //     {
        //         "currency": "1INCH",
        //         "total": "0",
        //         "available": "0",
        //         "hold": "0",
        //         "liability": "0",
        //         "maxBorrowSize": "0",
        //         "borrowEnabled": true,
        //         "transferInEnabled": true
        //     }
        //
        // Isolated
        //
        //     {
        //         "symbol": "MANA-USDT",
        //         "debtRatio": "0",
        //         "status": "BORROW",
        //         "baseAsset": {
        //             "currency": "MANA",
        //             "borrowEnabled": true,
        //             "repayEnabled": true,
        //             "transferEnabled": true,
        //             "borrowed": "0",
        //             "totalAsset": "0",
        //             "available": "0",
        //             "hold": "0",
        //             "maxBorrowSize": "1000"
        //         },
        //         "quoteAsset": {
        //             "currency": "USDT",
        //             "borrowEnabled": true,
        //             "repayEnabled": true,
        //             "transferEnabled": true,
        //             "borrowed": "0",
        //             "totalAsset": "0",
        //             "available": "0",
        //             "hold": "0",
        //             "maxBorrowSize": "50000"
        //         }
        //     }
        //
        const marketId = this.safeString(info, 'symbol');
        const marginMode = (marketId === undefined) ? 'cross' : 'isolated';
        market = this.safeMarket(marketId, market);
        const symbol = this.safeString(market, 'symbol');
        const timestamp = this.safeInteger(info, 'createdAt');
        const isolatedBase = this.safeDict(info, 'baseAsset', {});
        let amountBorrowed = undefined;
        let interest = undefined;
        let currencyId = undefined;
        if (marginMode === 'isolated') {
            amountBorrowed = this.safeNumber(isolatedBase, 'liability');
            interest = this.safeNumber(isolatedBase, 'interest');
            currencyId = this.safeString(isolatedBase, 'currency');
        }
        else {
            amountBorrowed = this.safeNumber(info, 'liability');
            interest = this.safeNumber(info, 'accruedInterest');
            currencyId = this.safeString(info, 'currency');
        }
        return {
            'info': info,
            'symbol': symbol,
            'currency': this.safeCurrencyCode(currencyId),
            'interest': interest,
            'interestRate': this.safeNumber(info, 'dailyIntRate'),
            'amountBorrowed': amountBorrowed,
            'marginMode': marginMode,
            'timestamp': timestamp,
            'datetime': this.iso8601(timestamp),
        };
    }
    /**
     * @method
     * @name kucoin#fetchBorrowRateHistories
     * @description retrieves a history of a multiple currencies borrow interest rate at specific time slots, returns all currencies if no symbols passed, default is undefined
     * @see https://www.kucoin.com/docs/rest/margin-trading/margin-trading-v3-/get-cross-isolated-margin-interest-records
     * @param {string[]|undefined} codes list of unified currency codes, default is undefined
     * @param {int} [since] timestamp in ms of the earliest borrowRate, default is undefined
     * @param {int} [limit] max number of borrow rate prices to return, default is undefined
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @param {string} [params.marginMode] 'cross' or 'isolated' default is 'cross'
     * @param {int} [params.until] the latest time in ms to fetch entries for
     * @returns {object} a dictionary of [borrow rate structures]{@link https://docs.ccxt.com/#/?id=borrow-rate-structure} indexed by the market symbol
     */
    async fetchBorrowRateHistories(codes = undefined, since = undefined, limit = undefined, params = {}) {
        await this.loadMarkets();
        const marginResult = this.handleMarginModeAndParams('fetchBorrowRateHistories', params);
        const marginMode = this.safeString(marginResult, 0, 'cross');
        const isIsolated = (marginMode === 'isolated'); // true-isolated, false-cross
        let request = {
            'isIsolated': isIsolated,
        };
        if (since !== undefined) {
            request['startTime'] = since;
        }
        [request, params] = this.handleUntilOption('endTime', request, params);
        if (limit !== undefined) {
            request['pageSize'] = limit; // default:50, min:10, max:500
        }
        const response = await this.privateGetMarginInterest(this.extend(request, params));
        //
        //     {
        //         "code": "200000",
        //         "data": {
        //             "timestamp": 1710829939673,
        //             "currentPage": 1,
        //             "pageSize": 50,
        //             "totalNum": 0,
        //             "totalPage": 0,
        //             "items": [
        //                 {
        //                     "createdAt": 1697783812257,
        //                     "currency": "XMR",
        //                     "interestAmount": "0.1",
        //                     "dayRatio": "0.001"
        //                 }
        //             ]
        //         }
        //     }
        //
        const data = this.safeDict(response, 'data');
        const rows = this.safeList(data, 'items', []);
        return this.parseBorrowRateHistories(rows, codes, since, limit);
    }
    /**
     * @method
     * @name kucoin#fetchBorrowRateHistory
     * @description retrieves a history of a currencies borrow interest rate at specific time slots
     * @see https://www.kucoin.com/docs/rest/margin-trading/margin-trading-v3-/get-cross-isolated-margin-interest-records
     * @param {string} code unified currency code
     * @param {int} [since] timestamp for the earliest borrow rate
     * @param {int} [limit] the maximum number of [borrow rate structures]{@link https://docs.ccxt.com/#/?id=borrow-rate-structure} to retrieve
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @param {string} [params.marginMode] 'cross' or 'isolated' default is 'cross'
     * @param {int} [params.until] the latest time in ms to fetch entries for
     * @returns {object[]} an array of [borrow rate structures]{@link https://docs.ccxt.com/#/?id=borrow-rate-structure}
     */
    async fetchBorrowRateHistory(code, since = undefined, limit = undefined, params = {}) {
        await this.loadMarkets();
        const marginResult = this.handleMarginModeAndParams('fetchBorrowRateHistories', params);
        const marginMode = this.safeString(marginResult, 0, 'cross');
        const isIsolated = (marginMode === 'isolated'); // true-isolated, false-cross
        const currency = this.currency(code);
        let request = {
            'isIsolated': isIsolated,
            'currency': currency['id'],
        };
        if (since !== undefined) {
            request['startTime'] = since;
        }
        [request, params] = this.handleUntilOption('endTime', request, params);
        if (limit !== undefined) {
            request['pageSize'] = limit; // default:50, min:10, max:500
        }
        const response = await this.privateGetMarginInterest(this.extend(request, params));
        //
        //     {
        //         "code": "200000",
        //         "data": {
        //             "timestamp": 1710829939673,
        //             "currentPage": 1,
        //             "pageSize": 50,
        //             "totalNum": 0,
        //             "totalPage": 0,
        //             "items": [
        //                 {
        //                     "createdAt": 1697783812257,
        //                     "currency": "XMR",
        //                     "interestAmount": "0.1",
        //                     "dayRatio": "0.001"
        //                 }
        //             ]
        //         }
        //     }
        //
        const data = this.safeDict(response, 'data');
        const rows = this.safeList(data, 'items', []);
        return this.parseBorrowRateHistory(rows, code, since, limit);
    }
    parseBorrowRateHistories(response, codes, since, limit) {
        //
        //     [
        //         {
        //             "createdAt": 1697783812257,
        //             "currency": "XMR",
        //             "interestAmount": "0.1",
        //             "dayRatio": "0.001"
        //         }
        //     ]
        //
        const borrowRateHistories = {};
        for (let i = 0; i < response.length; i++) {
            const item = response[i];
            const code = this.safeCurrencyCode(this.safeString(item, 'currency'));
            if (codes === undefined || this.inArray(code, codes)) {
                if (!(code in borrowRateHistories)) {
                    borrowRateHistories[code] = [];
                }
                const borrowRateStructure = this.parseBorrowRate(item);
                const borrowRateHistoriesCode = borrowRateHistories[code];
                borrowRateHistoriesCode.push(borrowRateStructure);
            }
        }
        const keys = Object.keys(borrowRateHistories);
        for (let i = 0; i < keys.length; i++) {
            const code = keys[i];
            borrowRateHistories[code] = this.filterByCurrencySinceLimit(borrowRateHistories[code], code, since, limit);
        }
        return borrowRateHistories;
    }
    /**
     * @method
     * @name kucoin#borrowCrossMargin
     * @description create a loan to borrow margin
     * @see https://docs.kucoin.com/#1-margin-borrowing
     * @param {string} code unified currency code of the currency to borrow
     * @param {float} amount the amount to borrow
     * @param {object} [params] extra parameters specific to the exchange API endpoints
     * @param {string} [params.timeInForce] either IOC or FOK
     * @returns {object} a [margin loan structure]{@link https://docs.ccxt.com/#/?id=margin-loan-structure}
     */
    async borrowCrossMargin(code, amount, params = {}) {
        await this.loadMarkets();
        const currency = this.currency(code);
        const request = {
            'currency': currency['id'],
            'size': this.currencyToPrecision(code, amount),
            'timeInForce': 'FOK',
        };
        const response = await this.privatePostMarginBorrow(this.extend(request, params));
        //
        //     {
        //         "success": true,
        //         "code": "200",
        //         "msg": "success",
        //         "retry": false,
        //         "data": {
        //             "orderNo": "5da6dba0f943c0c81f5d5db5",
        //             "actualSize": 10
        //         }
        //     }
        //
        const data = this.safeDict(response, 'data', {});
        return this.parseMarginLoan(data, currency);
    }
    /**
     * @method
     * @name kucoin#borrowIsolatedMargin
     * @description create a loan to borrow margin
     * @see https://docs.kucoin.com/#1-margin-borrowing
     * @param {string} symbol unified market symbol, required for isolated margin
     * @param {string} code unified currency code of the currency to borrow
     * @param {float} amount the amount to borrow
     * @param {object} [params] extra parameters specific to the exchange API endpoints
     * @param {string} [params.timeInForce] either IOC or FOK
     * @returns {object} a [margin loan structure]{@link https://docs.ccxt.com/#/?id=margin-loan-structure}
     */
    async borrowIsolatedMargin(symbol, code, amount, params = {}) {
        await this.loadMarkets();
        const market = this.market(symbol);
        const currency = this.currency(code);
        const request = {
            'currency': currency['id'],
            'size': this.currencyToPrecision(code, amount),
            'symbol': market['id'],
            'timeInForce': 'FOK',
            'isIsolated': true,
        };
        const response = await this.privatePostMarginBorrow(this.extend(request, params));
        //
        //     {
        //         "success": true,
        //         "code": "200",
        //         "msg": "success",
        //         "retry": false,
        //         "data": {
        //             "orderNo": "5da6dba0f943c0c81f5d5db5",
        //             "actualSize": 10
        //         }
        //     }
        //
        const data = this.safeDict(response, 'data', {});
        return this.parseMarginLoan(data, currency);
    }
    /**
     * @method
     * @name kucoin#repayCrossMargin
     * @description repay borrowed margin and interest
     * @see https://docs.kucoin.com/#2-repayment
     * @param {string} code unified currency code of the currency to repay
     * @param {float} amount the amount to repay
     * @param {object} [params] extra parameters specific to the exchange API endpoints
     * @returns {object} a [margin loan structure]{@link https://docs.ccxt.com/#/?id=margin-loan-structure}
     */
    async repayCrossMargin(code, amount, params = {}) {
        await this.loadMarkets();
        const currency = this.currency(code);
        const request = {
            'currency': currency['id'],
            'size': this.currencyToPrecision(code, amount),
        };
        const response = await this.privatePostMarginRepay(this.extend(request, params));
        //
        //     {
        //         "success": true,
        //         "code": "200",
        //         "msg": "success",
        //         "retry": false,
        //         "data": {
        //             "orderNo": "5da6dba0f943c0c81f5d5db5",
        //             "actualSize": 10
        //         }
        //     }
        //
        const data = this.safeDict(response, 'data', {});
        return this.parseMarginLoan(data, currency);
    }
    /**
     * @method
     * @name kucoin#repayIsolatedMargin
     * @description repay borrowed margin and interest
     * @see https://docs.kucoin.com/#2-repayment
     * @param {string} symbol unified market symbol
     * @param {string} code unified currency code of the currency to repay
     * @param {float} amount the amount to repay
     * @param {object} [params] extra parameters specific to the exchange API endpoints
     * @returns {object} a [margin loan structure]{@link https://docs.ccxt.com/#/?id=margin-loan-structure}
     */
    async repayIsolatedMargin(symbol, code, amount, params = {}) {
        await this.loadMarkets();
        const market = this.market(symbol);
        const currency = this.currency(code);
        const request = {
            'currency': currency['id'],
            'size': this.currencyToPrecision(code, amount),
            'symbol': market['id'],
            'isIsolated': true,
        };
        const response = await this.privatePostMarginRepay(this.extend(request, params));
        //
        //     {
        //         "success": true,
        //         "code": "200",
        //         "msg": "success",
        //         "retry": false,
        //         "data": {
        //             "orderNo": "5da6dba0f943c0c81f5d5db5",
        //             "actualSize": 10
        //         }
        //     }
        //
        const data = this.safeDict(response, 'data', {});
        return this.parseMarginLoan(data, currency);
    }
    parseMarginLoan(info, currency = undefined) {
        //
        //     {
        //         "orderNo": "5da6dba0f943c0c81f5d5db5",
        //         "actualSize": 10
        //     }
        //
        const timestamp = this.milliseconds();
        const currencyId = this.safeString(info, 'currency');
        return {
            'id': this.safeString(info, 'orderNo'),
            'currency': this.safeCurrencyCode(currencyId, currency),
            'amount': this.safeNumber(info, 'actualSize'),
            'symbol': undefined,
            'timestamp': timestamp,
            'datetime': this.iso8601(timestamp),
            'info': info,
        };
    }
    /**
     * @method
     * @name kucoin#fetchDepositWithdrawFees
     * @description fetch deposit and withdraw fees - *IMPORTANT* use fetchDepositWithdrawFee to get more in-depth info
     * @see https://docs.kucoin.com/#get-currencies
     * @param {string[]|undefined} codes list of unified currency codes
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {object} a list of [fee structures]{@link https://docs.ccxt.com/#/?id=fee-structure}
     */
    async fetchDepositWithdrawFees(codes = undefined, params = {}) {
        await this.loadMarkets();
        const response = await this.publicGetCurrencies(params);
        //
        //  [
        //      {
        //        "currency": "CSP",
        //        "name": "CSP",
        //        "fullName": "Caspian",
        //        "precision": 8,
        //        "confirms": 12,
        //        "contractAddress": "0xa6446d655a0c34bc4f05042ee88170d056cbaf45",
        //        "withdrawalMinSize": "2000",
        //        "withdrawalMinFee": "1000",
        //        "isWithdrawEnabled": true,
        //        "isDepositEnabled": true,
        //        "isMarginEnabled": false,
        //        "isDebitEnabled": false
        //      },
        //  ]
        //
        const data = this.safeList(response, 'data', []);
        return this.parseDepositWithdrawFees(data, codes, 'currency');
    }
    /**
     * @method
     * @name kucoin#setLeverage
     * @description set the level of leverage for a market
     * @see https://www.kucoin.com/docs/rest/margin-trading/margin-trading-v3-/modify-leverage-multiplier
     * @param {int } [leverage] New leverage multiplier. Must be greater than 1 and up to two decimal places, and cannot be less than the user's current debt leverage or greater than the system's maximum leverage
     * @param {string} [symbol] unified market symbol
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {object} response from the exchange
     */
    async setLeverage(leverage, symbol = undefined, params = {}) {
        await this.loadMarkets();
        let market = undefined;
        let marketType = undefined;
        [marketType, params] = this.handleMarketTypeAndParams('setLeverage', undefined, params);
        if ((symbol !== undefined) || marketType !== 'spot') {
            market = this.market(symbol);
            if (market['contract']) {
                throw new errors.NotSupported(this.id + ' setLeverage currently supports only spot margin');
            }
        }
        let marginMode = undefined;
        [marginMode, params] = this.handleMarginModeAndParams('setLeverage', params);
        if (marginMode === undefined) {
            throw new errors.ArgumentsRequired(this.id + ' setLeverage requires a marginMode parameter');
        }
        const request = {};
        if (marginMode === 'isolated' && symbol === undefined) {
            throw new errors.ArgumentsRequired(this.id + ' setLeverage requires a symbol parameter for isolated margin');
        }
        if (symbol !== undefined) {
            request['symbol'] = market['id'];
        }
        request['leverage'] = leverage.toString();
        request['isIsolated'] = (marginMode === 'isolated');
        return await this.privatePostPositionUpdateUserLeverage(this.extend(request, params));
    }
    sign(path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
        //
        // the v2 URL is https://openapi-v2.kucoin.com/api/v1/endpoint
        //                                ↑                 ↑
        //                                ↑                 ↑
        //
        const versions = this.safeDict(this.options, 'versions', {});
        const apiVersions = this.safeDict(versions, api, {});
        const methodVersions = this.safeDict(apiVersions, method, {});
        const defaultVersion = this.safeString(methodVersions, path, this.options['version']);
        const version = this.safeString(params, 'version', defaultVersion);
        params = this.omit(params, 'version');
        let endpoint = '/api/' + version + '/' + this.implodeParams(path, params);
        if (api === 'webExchange') {
            endpoint = '/' + this.implodeParams(path, params);
        }
        if (api === 'earn') {
            endpoint = '/api/v1/' + this.implodeParams(path, params);
        }
        const query = this.omit(params, this.extractParams(path));
        let endpart = '';
        headers = (headers !== undefined) ? headers : {};
        let url = this.urls['api'][api];
        if (!this.isEmpty(query)) {
            if (((method === 'GET') || (method === 'DELETE')) && (path !== 'orders/multi-cancel')) {
                endpoint += '?' + this.rawencode(query);
            }
            else {
                body = this.json(query);
                endpart = body;
                headers['Content-Type'] = 'application/json';
            }
        }
        url = url + endpoint;
        const isFuturePrivate = (api === 'futuresPrivate');
        const isPrivate = (api === 'private');
        const isBroker = (api === 'broker');
        const isEarn = (api === 'earn');
        if (isPrivate || isFuturePrivate || isBroker || isEarn) {
            this.checkRequiredCredentials();
            const timestamp = this.nonce().toString();
            headers = this.extend({
                'KC-API-KEY-VERSION': '2',
                'KC-API-KEY': this.apiKey,
                'KC-API-TIMESTAMP': timestamp,
            }, headers);
            const apiKeyVersion = this.safeString(headers, 'KC-API-KEY-VERSION');
            if (apiKeyVersion === '2') {
                const passphrase = this.hmac(this.encode(this.password), this.encode(this.secret), sha256.sha256, 'base64');
                headers['KC-API-PASSPHRASE'] = passphrase;
            }
            else {
                headers['KC-API-PASSPHRASE'] = this.password;
            }
            const payload = timestamp + method + endpoint + endpart;
            const signature = this.hmac(this.encode(payload), this.encode(this.secret), sha256.sha256, 'base64');
            headers['KC-API-SIGN'] = signature;
            let partner = this.safeDict(this.options, 'partner', {});
            partner = isFuturePrivate ? this.safeValue(partner, 'future', partner) : this.safeValue(partner, 'spot', partner);
            const partnerId = this.safeString(partner, 'id');
            const partnerSecret = this.safeString2(partner, 'secret', 'key');
            if ((partnerId !== undefined) && (partnerSecret !== undefined)) {
                const partnerPayload = timestamp + partnerId + this.apiKey;
                const partnerSignature = this.hmac(this.encode(partnerPayload), this.encode(partnerSecret), sha256.sha256, 'base64');
                headers['KC-API-PARTNER-SIGN'] = partnerSignature;
                headers['KC-API-PARTNER'] = partnerId;
                headers['KC-API-PARTNER-VERIFY'] = 'true';
            }
            if (isBroker) {
                const brokerName = this.safeString(partner, 'name');
                if (brokerName !== undefined) {
                    headers['KC-BROKER-NAME'] = brokerName;
                }
            }
        }
        return { 'url': url, 'method': method, 'body': body, 'headers': headers };
    }
    handleErrors(code, reason, url, method, headers, body, response, requestHeaders, requestBody) {
        if (!response) {
            this.throwBroadlyMatchedException(this.exceptions['broad'], body, body);
            return undefined;
        }
        //
        // bad
        //     { "code": "400100", "msg": "validation.createOrder.clientOidIsRequired" }
        // good
        //     { code: '200000', data: { ... }}
        //
        const errorCode = this.safeString(response, 'code');
        const message = this.safeString2(response, 'msg', 'data', '');
        const feedback = this.id + ' ' + body;
        this.throwExactlyMatchedException(this.exceptions['exact'], message, feedback);
        this.throwExactlyMatchedException(this.exceptions['exact'], errorCode, feedback);
        this.throwBroadlyMatchedException(this.exceptions['broad'], body, feedback);
        if (errorCode !== '200000' && errorCode !== '200') {
            throw new errors.ExchangeError(feedback);
        }
        return undefined;
    }
}

module.exports = kucoin;