UNPKG

astro-perp-ccxt-dev

Version:

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

2,641 lines 121 kB
'use strict';

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

// ----------------------------------------------------------------------------
//  ---------------------------------------------------------------------------
/**
 * @class tokocrypto
 * @augments Exchange
 */
class tokocrypto extends tokocrypto$1 {
    describe() {
        return this.deepExtend(super.describe(), {
            'id': 'tokocrypto',
            'name': 'Tokocrypto',
            'countries': ['ID'],
            'certified': false,
            'pro': false,
            'version': 'v1',
            // new metainfo interface
            'has': {
                'CORS': undefined,
                'spot': true,
                'margin': true,
                'swap': false,
                'future': false,
                'option': false,
                'addMargin': undefined,
                'borrowMargin': undefined,
                'cancelAllOrders': false,
                'cancelOrder': true,
                'cancelOrders': undefined,
                'createDepositAddress': false,
                'createMarketBuyOrderWithCost': true,
                'createMarketOrderWithCost': false,
                'createMarketSellOrderWithCost': false,
                'createOrder': true,
                'createReduceOnlyOrder': undefined,
                'createStopLimitOrder': true,
                'createStopMarketOrder': true,
                'createStopOrder': true,
                'fetchAccounts': false,
                'fetchBalance': true,
                'fetchBidsAsks': true,
                'fetchBorrowInterest': undefined,
                'fetchBorrowRateHistories': undefined,
                'fetchBorrowRateHistory': undefined,
                'fetchCanceledOrders': false,
                'fetchClosedOrder': false,
                'fetchClosedOrders': 'emulated',
                'fetchCrossBorrowRate': false,
                'fetchCrossBorrowRates': false,
                'fetchCurrencies': false,
                'fetchDeposit': false,
                'fetchDepositAddress': true,
                'fetchDepositAddresses': false,
                'fetchDepositAddressesByNetwork': false,
                'fetchDeposits': true,
                'fetchDepositsWithdrawals': false,
                'fetchFundingHistory': false,
                'fetchFundingRate': false,
                'fetchFundingRateHistory': false,
                'fetchFundingRates': false,
                'fetchIndexOHLCV': false,
                'fetchIsolatedBorrowRate': false,
                'fetchIsolatedBorrowRates': false,
                'fetchL3OrderBook': false,
                'fetchLedger': undefined,
                'fetchLeverage': false,
                'fetchLeverageTiers': false,
                'fetchMarketLeverageTiers': 'emulated',
                'fetchMarkets': true,
                'fetchMarkOHLCV': false,
                'fetchMyTrades': true,
                'fetchOHLCV': true,
                'fetchOpenInterestHistory': false,
                'fetchOpenOrder': false,
                'fetchOpenOrders': true,
                'fetchOrder': true,
                'fetchOrderBook': true,
                'fetchOrderBooks': false,
                'fetchOrders': true,
                'fetchOrderTrades': false,
                'fetchPosition': false,
                'fetchPositions': false,
                'fetchPositionsRisk': false,
                'fetchPremiumIndexOHLCV': false,
                'fetchStatus': false,
                'fetchTicker': false,
                'fetchTickers': false,
                'fetchTime': true,
                'fetchTrades': true,
                'fetchTradingFee': false,
                'fetchTradingFees': false,
                'fetchTradingLimits': false,
                'fetchTransactionFee': false,
                'fetchTransactionFees': false,
                'fetchTransactions': false,
                'fetchTransfers': false,
                'fetchWithdrawal': false,
                'fetchWithdrawals': true,
                'fetchWithdrawalWhitelist': false,
                'reduceMargin': false,
                'repayCrossMargin': false,
                'repayIsolatedMargin': false,
                'setLeverage': false,
                'setMargin': false,
                'setMarginMode': false,
                'setPositionMode': false,
                'signIn': false,
                'transfer': false,
                'withdraw': true,
            },
            'timeframes': {
                '1m': '1m',
                '3m': '3m',
                '5m': '5m',
                '15m': '15m',
                '30m': '30m',
                '1h': '1h',
                '2h': '2h',
                '4h': '4h',
                '6h': '6h',
                '8h': '8h',
                '12h': '12h',
                '1d': '1d',
                '3d': '3d',
                '1w': '1w',
                '1M': '1M',
            },
            'urls': {
                'logo': 'https://user-images.githubusercontent.com/1294454/183870484-d3398d0c-f6a1-4cce-91b8-d58792308716.jpg',
                'api': {
                    'rest': {
                        'public': 'https://www.tokocrypto.com',
                        'binance': 'https://api.binance.com/api/v3',
                        'private': 'https://www.tokocrypto.com',
                    },
                },
                'www': 'https://tokocrypto.com',
                // 'referral': 'https://www.binance.us/?ref=35005074',
                'doc': 'https://www.tokocrypto.com/apidocs/',
                'fees': 'https://www.tokocrypto.com/fees/newschedule',
            },
            'api': {
                'binance': {
                    'get': {
                        'ping': 1,
                        'time': 1,
                        'depth': { 'cost': 1, 'byLimit': [[100, 1], [500, 5], [1000, 10], [5000, 50]] },
                        'trades': 1,
                        'aggTrades': 1,
                        'historicalTrades': 5,
                        'klines': 1,
                        'ticker/24hr': { 'cost': 1, 'noSymbol': 40 },
                        'ticker/price': { 'cost': 1, 'noSymbol': 2 },
                        'ticker/bookTicker': { 'cost': 1, 'noSymbol': 2 },
                        'exchangeInfo': 10,
                    },
                    'put': {
                        'userDataStream': 1,
                    },
                    'post': {
                        'userDataStream': 1,
                    },
                    'delete': {
                        'userDataStream': 1,
                    },
                },
                'public': {
                    'get': {
                        'open/v1/common/time': 1,
                        'open/v1/common/symbols': 1,
                        // all the actual symbols are type 1
                        'open/v1/market/depth': 1,
                        'open/v1/market/trades': 1,
                        'open/v1/market/agg-trades': 1,
                        'open/v1/market/klines': 1, // when symbol type is not 1
                    },
                },
                'private': {
                    'get': {
                        'open/v1/orders/detail': 1,
                        'open/v1/orders': 1,
                        'open/v1/account/spot': 1,
                        'open/v1/account/spot/asset': 1,
                        'open/v1/orders/trades': 1,
                        'open/v1/withdraws': 1,
                        'open/v1/deposits': 1,
                        'open/v1/deposits/address': 1,
                    },
                    'post': {
                        'open/v1/orders': 1,
                        'open/v1/orders/cancel': 1,
                        'open/v1/orders/oco': 1,
                        'open/v1/withdraws': 1,
                        'open/v1/user-data-stream': 1,
                    },
                },
            },
            'fees': {
                'trading': {
                    'tierBased': true,
                    'percentage': true,
                    'taker': this.parseNumber('0.0075'),
                    'maker': this.parseNumber('0.0075'), // 0.1% trading fee, zero fees for all trading pairs before November 1
                },
            },
            'precisionMode': number.TICK_SIZE,
            'options': {
                // 'fetchTradesMethod': 'binanceGetTrades', // binanceGetTrades, binanceGetAggTrades
                'createMarketBuyOrderRequiresPrice': true,
                'defaultTimeInForce': 'GTC',
                // 'defaultType': 'spot', // 'spot', 'future', 'margin', 'delivery'
                'hasAlreadyAuthenticatedSuccessfully': false,
                'warnOnFetchOpenOrdersWithoutSymbol': true,
                // 'fetchPositions': 'positionRisk', // or 'account'
                'recvWindow': 5 * 1000,
                'timeDifference': 0,
                'adjustForTimeDifference': false,
                'newOrderRespType': {
                    'market': 'FULL',
                    'limit': 'FULL', // we change it from 'ACK' by default to 'FULL' (returns immediately if limit is not hit)
                },
                'quoteOrderQty': false,
                'networks': {
                    'ERC20': 'ETH',
                    'TRC20': 'TRX',
                    'BEP2': 'BNB',
                    'BEP20': 'BSC',
                    'OMNI': 'OMNI',
                    'EOS': 'EOS',
                    'SPL': 'SOL',
                },
                'reverseNetworks': {
                    'tronscan.org': 'TRC20',
                    'etherscan.io': 'ERC20',
                    'bscscan.com': 'BSC',
                    'explorer.binance.org': 'BEP2',
                    'bithomp.com': 'XRP',
                    'bloks.io': 'EOS',
                    'stellar.expert': 'XLM',
                    'blockchair.com/bitcoin': 'BTC',
                    'blockchair.com/bitcoin-cash': 'BCH',
                    'blockchair.com/ecash': 'XEC',
                    'explorer.litecoin.net': 'LTC',
                    'explorer.avax.network': 'AVAX',
                    'solscan.io': 'SOL',
                    'polkadot.subscan.io': 'DOT',
                    'dashboard.internetcomputer.org': 'ICP',
                    'explorer.chiliz.com': 'CHZ',
                    'cardanoscan.io': 'ADA',
                    'mainnet.theoan.com': 'AION',
                    'algoexplorer.io': 'ALGO',
                    'explorer.ambrosus.com': 'AMB',
                    'viewblock.io/zilliqa': 'ZIL',
                    'viewblock.io/arweave': 'AR',
                    'explorer.ark.io': 'ARK',
                    'atomscan.com': 'ATOM',
                    'www.mintscan.io': 'CTK',
                    'explorer.bitcoindiamond.org': 'BCD',
                    'btgexplorer.com': 'BTG',
                    'bts.ai': 'BTS',
                    'explorer.celo.org': 'CELO',
                    'explorer.nervos.org': 'CKB',
                    'cerebro.cortexlabs.ai': 'CTXC',
                    'chainz.cryptoid.info': 'VIA',
                    'explorer.dcrdata.org': 'DCR',
                    'digiexplorer.info': 'DGB',
                    'dock.subscan.io': 'DOCK',
                    'dogechain.info': 'DOGE',
                    'explorer.elrond.com': 'EGLD',
                    'blockscout.com': 'ETC',
                    'explore-fetchhub.fetch.ai': 'FET',
                    'filfox.info': 'FIL',
                    'fio.bloks.io': 'FIO',
                    'explorer.firo.org': 'FIRO',
                    'neoscan.io': 'NEO',
                    'ftmscan.com': 'FTM',
                    'explorer.gochain.io': 'GO',
                    'block.gxb.io': 'GXS',
                    'hash-hash.info': 'HBAR',
                    'www.hiveblockexplorer.com': 'HIVE',
                    'explorer.helium.com': 'HNT',
                    'tracker.icon.foundation': 'ICX',
                    'www.iostabc.com': 'IOST',
                    'explorer.iota.org': 'IOTA',
                    'iotexscan.io': 'IOTX',
                    'irishub.iobscan.io': 'IRIS',
                    'kava.mintscan.io': 'KAVA',
                    'scope.klaytn.com': 'KLAY',
                    'kmdexplorer.io': 'KMD',
                    'kusama.subscan.io': 'KSM',
                    'explorer.lto.network': 'LTO',
                    'polygonscan.com': 'POLYGON',
                    'explorer.ont.io': 'ONT',
                    'minaexplorer.com': 'MINA',
                    'nanolooker.com': 'NANO',
                    'explorer.nebulas.io': 'NAS',
                    'explorer.nbs.plus': 'NBS',
                    'explorer.nebl.io': 'NEBL',
                    'nulscan.io': 'NULS',
                    'nxscan.com': 'NXS',
                    'explorer.harmony.one': 'ONE',
                    'explorer.poa.network': 'POA',
                    'qtum.info': 'QTUM',
                    'explorer.rsk.co': 'RSK',
                    'www.oasisscan.com': 'ROSE',
                    'ravencoin.network': 'RVN',
                    'sc.tokenview.com': 'SC',
                    'secretnodes.com': 'SCRT',
                    'explorer.skycoin.com': 'SKY',
                    'steemscan.com': 'STEEM',
                    'explorer.stacks.co': 'STX',
                    'www.thetascan.io': 'THETA',
                    'scan.tomochain.com': 'TOMO',
                    'explore.vechain.org': 'VET',
                    'explorer.vite.net': 'VITE',
                    'www.wanscan.org': 'WAN',
                    'wavesexplorer.com': 'WAVES',
                    'wax.eosx.io': 'WAXP',
                    'waltonchain.pro': 'WTC',
                    'chain.nem.ninja': 'XEM',
                    'verge-blockchain.info': 'XVG',
                    'explorer.yoyow.org': 'YOYOW',
                    'explorer.zcha.in': 'ZEC',
                    'explorer.zensystem.io': 'ZEN',
                },
                'impliedNetworks': {
                    'ETH': { 'ERC20': 'ETH' },
                    'TRX': { 'TRC20': 'TRX' },
                },
                'legalMoney': {
                    'MXN': true,
                    'UGX': true,
                    'SEK': true,
                    'CHF': true,
                    'VND': true,
                    'AED': true,
                    'DKK': true,
                    'KZT': true,
                    'HUF': true,
                    'PEN': true,
                    'PHP': true,
                    'USD': true,
                    'TRY': true,
                    'EUR': true,
                    'NGN': true,
                    'PLN': true,
                    'BRL': true,
                    'ZAR': true,
                    'KES': true,
                    'ARS': true,
                    'RUB': true,
                    'AUD': true,
                    'NOK': true,
                    'CZK': true,
                    'GBP': true,
                    'UAH': true,
                    'GHS': true,
                    'HKD': true,
                    'CAD': true,
                    'INR': true,
                    'JPY': true,
                    'NZD': true,
                },
            },
            // https://binance-docs.github.io/apidocs/spot/en/#error-codes-2
            'exceptions': {
                'exact': {
                    'System is under maintenance.': errors.OnMaintenance,
                    'System abnormality': errors.ExchangeError,
                    'You are not authorized to execute this request.': errors.PermissionDenied,
                    'API key does not exist': errors.AuthenticationError,
                    'Order would trigger immediately.': errors.OrderImmediatelyFillable,
                    'Stop price would trigger immediately.': errors.OrderImmediatelyFillable,
                    'Order would immediately match and take.': errors.OrderImmediatelyFillable,
                    'Account has insufficient balance for requested action.': errors.InsufficientFunds,
                    'Rest API trading is not enabled.': errors.ExchangeNotAvailable,
                    "You don't have permission.": errors.PermissionDenied,
                    'Market is closed.': errors.ExchangeNotAvailable,
                    'Too many requests. Please try again later.': errors.DDoSProtection,
                    'This action disabled is on this account.': errors.AccountSuspended,
                    '-1000': errors.ExchangeNotAvailable,
                    '-1001': errors.ExchangeNotAvailable,
                    '-1002': errors.AuthenticationError,
                    '-1003': errors.RateLimitExceeded,
                    '-1004': errors.DDoSProtection,
                    '-1005': errors.PermissionDenied,
                    '-1006': errors.BadResponse,
                    '-1007': errors.RequestTimeout,
                    '-1010': errors.BadResponse,
                    '-1011': errors.PermissionDenied,
                    '-1013': errors.InvalidOrder,
                    '-1014': errors.InvalidOrder,
                    '-1015': errors.RateLimitExceeded,
                    '-1016': errors.ExchangeNotAvailable,
                    '-1020': errors.BadRequest,
                    '-1021': errors.InvalidNonce,
                    '-1022': errors.AuthenticationError,
                    '-1023': errors.BadRequest,
                    '-1099': errors.AuthenticationError,
                    '-1100': errors.BadRequest,
                    '-1101': errors.BadRequest,
                    '-1102': errors.BadRequest,
                    '-1103': errors.BadRequest,
                    '-1104': errors.BadRequest,
                    '-1105': errors.BadRequest,
                    '-1106': errors.BadRequest,
                    '-1108': errors.BadRequest,
                    '-1109': errors.AuthenticationError,
                    '-1110': errors.BadRequest,
                    '-1111': errors.BadRequest,
                    '-1112': errors.InvalidOrder,
                    '-1113': errors.BadRequest,
                    '-1114': errors.BadRequest,
                    '-1115': errors.BadRequest,
                    '-1116': errors.BadRequest,
                    '-1117': errors.BadRequest,
                    '-1118': errors.BadRequest,
                    '-1119': errors.BadRequest,
                    '-1120': errors.BadRequest,
                    '-1121': errors.BadSymbol,
                    '-1125': errors.AuthenticationError,
                    '-1127': errors.BadRequest,
                    '-1128': errors.BadRequest,
                    '-1130': errors.BadRequest,
                    '-1131': errors.BadRequest,
                    '-1136': errors.BadRequest,
                    '-2008': errors.AuthenticationError,
                    '-2010': errors.ExchangeError,
                    '-2011': errors.OrderNotFound,
                    '-2013': errors.OrderNotFound,
                    '-2014': errors.AuthenticationError,
                    '-2015': errors.AuthenticationError,
                    '-2016': errors.BadRequest,
                    '-2018': errors.InsufficientFunds,
                    '-2019': errors.InsufficientFunds,
                    '-2020': errors.OrderNotFillable,
                    '-2021': errors.OrderImmediatelyFillable,
                    '-2022': errors.InvalidOrder,
                    '-2023': errors.InsufficientFunds,
                    '-2024': errors.InsufficientFunds,
                    '-2025': errors.InvalidOrder,
                    '-2026': errors.InvalidOrder,
                    '-2027': errors.InvalidOrder,
                    '-2028': errors.InsufficientFunds,
                    '-3000': errors.ExchangeError,
                    '-3001': errors.AuthenticationError,
                    '-3002': errors.BadSymbol,
                    '-3003': errors.BadRequest,
                    '-3004': errors.ExchangeError,
                    '-3005': errors.InsufficientFunds,
                    '-3006': errors.InsufficientFunds,
                    '-3007': errors.ExchangeError,
                    '-3008': errors.InsufficientFunds,
                    '-3009': errors.BadRequest,
                    '-3010': errors.ExchangeError,
                    '-3011': errors.BadRequest,
                    '-3012': errors.ExchangeError,
                    '-3013': errors.BadRequest,
                    '-3014': errors.AccountSuspended,
                    '-3015': errors.ExchangeError,
                    '-3016': errors.BadRequest,
                    '-3017': errors.ExchangeError,
                    '-3018': errors.AccountSuspended,
                    '-3019': errors.AccountSuspended,
                    '-3020': errors.InsufficientFunds,
                    '-3021': errors.BadRequest,
                    '-3022': errors.AccountSuspended,
                    '-3023': errors.BadRequest,
                    '-3024': errors.ExchangeError,
                    '-3025': errors.BadRequest,
                    '-3026': errors.BadRequest,
                    '-3027': errors.BadSymbol,
                    '-3028': errors.BadSymbol,
                    '-3029': errors.ExchangeError,
                    '-3036': errors.AccountSuspended,
                    '-3037': errors.ExchangeError,
                    '-3038': errors.BadRequest,
                    '-3041': errors.InsufficientFunds,
                    '-3042': errors.BadRequest,
                    '-3043': errors.BadRequest,
                    '-3044': errors.DDoSProtection,
                    '-3045': errors.ExchangeError,
                    '-3999': errors.ExchangeError,
                    '-4001': errors.BadRequest,
                    '-4002': errors.BadRequest,
                    '-4003': errors.BadRequest,
                    '-4004': errors.AuthenticationError,
                    '-4005': errors.RateLimitExceeded,
                    '-4006': errors.BadRequest,
                    '-4007': errors.BadRequest,
                    '-4008': errors.BadRequest,
                    '-4010': errors.BadRequest,
                    '-4011': errors.BadRequest,
                    '-4012': errors.BadRequest,
                    '-4013': errors.AuthenticationError,
                    '-4014': errors.PermissionDenied,
                    '-4015': errors.ExchangeError,
                    '-4016': errors.PermissionDenied,
                    '-4017': errors.PermissionDenied,
                    '-4018': errors.BadSymbol,
                    '-4019': errors.BadSymbol,
                    '-4021': errors.BadRequest,
                    '-4022': errors.BadRequest,
                    '-4023': errors.ExchangeError,
                    '-4024': errors.InsufficientFunds,
                    '-4025': errors.InsufficientFunds,
                    '-4026': errors.InsufficientFunds,
                    '-4027': errors.ExchangeError,
                    '-4028': errors.BadRequest,
                    '-4029': errors.BadRequest,
                    '-4030': errors.ExchangeError,
                    '-4031': errors.ExchangeError,
                    '-4032': errors.ExchangeError,
                    '-4033': errors.BadRequest,
                    '-4034': errors.ExchangeError,
                    '-4035': errors.PermissionDenied,
                    '-4036': errors.BadRequest,
                    '-4037': errors.ExchangeError,
                    '-4038': errors.ExchangeError,
                    '-4039': errors.BadRequest,
                    '-4040': errors.BadRequest,
                    '-4041': errors.ExchangeError,
                    '-4042': errors.ExchangeError,
                    '-4043': errors.BadRequest,
                    '-4044': errors.BadRequest,
                    '-4045': errors.ExchangeError,
                    '-4046': errors.AuthenticationError,
                    '-4047': errors.BadRequest,
                    '-5001': errors.BadRequest,
                    '-5002': errors.InsufficientFunds,
                    '-5003': errors.InsufficientFunds,
                    '-5004': errors.BadRequest,
                    '-5005': errors.InsufficientFunds,
                    '-5006': errors.BadRequest,
                    '-5007': errors.BadRequest,
                    '-5008': errors.InsufficientFunds,
                    '-5009': errors.BadRequest,
                    '-5010': errors.ExchangeError,
                    '-5011': errors.BadRequest,
                    '-5012': errors.ExchangeError,
                    '-5013': errors.InsufficientFunds,
                    '-5021': errors.BadRequest,
                    '-6001': errors.BadRequest,
                    '-6003': errors.BadRequest,
                    '-6004': errors.ExchangeError,
                    '-6005': errors.InvalidOrder,
                    '-6006': errors.BadRequest,
                    '-6007': errors.BadRequest,
                    '-6008': errors.BadRequest,
                    '-6009': errors.RateLimitExceeded,
                    '-6011': errors.BadRequest,
                    '-6012': errors.InsufficientFunds,
                    '-6013': errors.ExchangeError,
                    '-6014': errors.BadRequest,
                    '-6015': errors.BadRequest,
                    '-6016': errors.BadRequest,
                    '-6017': errors.BadRequest,
                    '-6018': errors.BadRequest,
                    '-6019': errors.AuthenticationError,
                    '-6020': errors.BadRequest,
                    '-7001': errors.BadRequest,
                    '-7002': errors.BadRequest,
                    '-9000': errors.InsufficientFunds,
                    '-10017': errors.BadRequest,
                    '-11008': errors.InsufficientFunds,
                    '-12014': errors.RateLimitExceeded,
                    '-13000': errors.BadRequest,
                    '-13001': errors.BadRequest,
                    '-13002': errors.BadRequest,
                    '-13003': errors.BadRequest,
                    '-13004': errors.BadRequest,
                    '-13005': errors.BadRequest,
                    '-13006': errors.InvalidOrder,
                    '-13007': errors.AuthenticationError,
                    '-21001': errors.BadRequest,
                    '-21002': errors.BadRequest,
                    '-21003': errors.BadRequest,
                    '100001003': errors.BadRequest,
                    '2202': errors.InsufficientFunds,
                    '3210': errors.InvalidOrder,
                    '3203': errors.InvalidOrder,
                    '3211': errors.InvalidOrder,
                    '3207': errors.InvalidOrder,
                    '3218': errors.OrderNotFound, // {"code":3218,"msg":"Order does not exist","timestamp":1662739749275}
                },
                'broad': {
                    'has no operation privilege': errors.PermissionDenied,
                    'MAX_POSITION': errors.InvalidOrder, // {"code":-2010,"msg":"Filter failure: MAX_POSITION"}
                },
            },
            'features': {
                'spot': {
                    'sandbox': false,
                    'createOrder': {
                        'marginMode': false,
                        'triggerPrice': true,
                        'triggerDirection': false,
                        'triggerPriceType': undefined,
                        'stopLossPrice': false,
                        'takeProfitPrice': false,
                        'attachedStopLossTakeProfit': undefined,
                        'timeInForce': {
                            'IOC': true,
                            'FOK': true,
                            'PO': true,
                            'GTD': false,
                        },
                        'hedged': false,
                        'trailing': false,
                        'leverage': false,
                        'marketBuyByCost': true,
                        'marketBuyRequiresPrice': true,
                        'selfTradePrevention': true,
                        'iceberg': true, // todo
                    },
                    'createOrders': undefined,
                    'fetchMyTrades': {
                        'marginMode': false,
                        'limit': 1000,
                        'daysBack': 100000,
                        'untilDays': 100000,
                        'symbolRequired': true,
                    },
                    'fetchOrder': {
                        'marginMode': false,
                        'trigger': false,
                        'trailing': false,
                        'symbolRequired': false,
                    },
                    'fetchOpenOrders': {
                        'marginMode': false,
                        'limit': 1000,
                        'trigger': false,
                        'trailing': false,
                        'symbolRequired': true,
                    },
                    'fetchOrders': {
                        'marginMode': false,
                        'limit': 1000,
                        'daysBack': 100000,
                        'untilDays': 100000,
                        'trigger': false,
                        'trailing': false,
                        'symbolRequired': true,
                    },
                    'fetchClosedOrders': {
                        'marginMode': false,
                        'limit': 1000,
                        'daysBack': 100000,
                        'daysBackCanceled': 1,
                        'untilDays': 100000,
                        'trigger': false,
                        'trailing': false,
                        'symbolRequired': true,
                    },
                    'fetchOHLCV': {
                        'limit': 1000,
                    },
                },
                'swap': {
                    'linear': undefined,
                    'inverse': undefined,
                },
                'future': {
                    'linear': undefined,
                    'inverse': undefined,
                },
            },
        });
    }
    nonce() {
        return this.milliseconds() - this.options['timeDifference'];
    }
    /**
     * @method
     * @name tokocrypto#fetchTime
     * @see https://www.tokocrypto.com/apidocs/#check-server-time
     * @description fetches the current integer timestamp in milliseconds from the exchange server
     * @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.publicGetOpenV1CommonTime(params);
        //
        // {
        //     "code": 0,
        //     "msg": "Success",
        //     "data": null,
        //     "timestamp": 1737378074159
        // }
        //
        return this.safeInteger(response, 'timestamp');
    }
    /**
     * @method
     * @name tokocrypto#fetchMarkets
     * @see https://www.tokocrypto.com/apidocs/#get-all-supported-trading-symbol
     * @description retrieves data on all markets for tokocrypto
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {object[]} an array of objects representing market data
     */
    async fetchMarkets(params = {}) {
        const response = await this.publicGetOpenV1CommonSymbols(params);
        //
        //     {
        //         "code":0,
        //         "msg":"Success",
        //         "data":{
        //             "list":[
        //                 {
        //                     "type":1,
        //                     "symbol":"1INCH_BTC",
        //                     "baseAsset":"1INCH",
        //                     "basePrecision":8,
        //                     "quoteAsset":"BTC",
        //                     "quotePrecision":8,
        //                     "filters":[
        //                         {"filterType":"PRICE_FILTER","minPrice":"0.00000001","maxPrice":"1000.00000000","tickSize":"0.00000001","applyToMarket":false},
        //                         {"filterType":"PERCENT_PRICE","multiplierUp":5,"multiplierDown":0.2,"avgPriceMins":"5","applyToMarket":false},
        //                         {"filterType":"LOT_SIZE","minQty":"0.10000000","maxQty":"90000000.00000000","stepSize":"0.10000000","applyToMarket":false},
        //                         {"filterType":"MIN_NOTIONAL","avgPriceMins":"5","minNotional":"0.00010000","applyToMarket":true},
        //                         {"filterType":"ICEBERG_PARTS","applyToMarket":false,"limit":"10"},
        //                         {"filterType":"MARKET_LOT_SIZE","minQty":"0.00000000","maxQty":"79460.14117231","stepSize":"0.00000000","applyToMarket":false},
        //                         {"filterType":"TRAILING_DELTA","applyToMarket":false},
        //                         {"filterType":"MAX_NUM_ORDERS","applyToMarket":false},
        //                         {"filterType":"MAX_NUM_ALGO_ORDERS","applyToMarket":false,"maxNumAlgoOrders":"5"}
        //                     ],
        //                     "orderTypes":["LIMIT","LIMIT_MAKER","MARKET","STOP_LOSS_LIMIT","TAKE_PROFIT_LIMIT"],
        //                     "icebergEnable":1,
        //                     "ocoEnable":1,
        //                     "spotTradingEnable":1,
        //                     "marginTradingEnable":1,
        //                     "permissions":["SPOT","MARGIN"]
        //                 },
        //             ]
        //         },
        //         "timestamp":1659492212507
        //     }
        //
        if (this.options['adjustForTimeDifference']) {
            await this.loadTimeDifference();
        }
        const data = this.safeValue(response, 'data', {});
        const list = this.safeValue(data, 'list', []);
        const result = [];
        for (let i = 0; i < list.length; i++) {
            const market = list[i];
            const baseId = this.safeString(market, 'baseAsset');
            const quoteId = this.safeString(market, 'quoteAsset');
            const id = this.safeString(market, 'symbol');
            const lowercaseId = this.safeStringLower(market, 'symbol');
            const settleId = this.safeString(market, 'marginAsset');
            const base = this.safeCurrencyCode(baseId);
            const quote = this.safeCurrencyCode(quoteId);
            const settle = this.safeCurrencyCode(settleId);
            const symbol = base + '/' + quote;
            const filters = this.safeValue(market, 'filters', []);
            const filtersByType = this.indexBy(filters, 'filterType');
            const status = this.safeString(market, 'spotTradingEnable');
            let active = (status === '1');
            const permissions = this.safeValue(market, 'permissions', []);
            for (let j = 0; j < permissions.length; j++) {
                if (permissions[j] === 'TRD_GRP_003') {
                    active = false;
                    break;
                }
            }
            const isMarginTradingAllowed = this.safeBool(market, 'isMarginTradingAllowed', false);
            const entry = {
                'id': id,
                'lowercaseId': lowercaseId,
                'symbol': symbol,
                'base': base,
                'quote': quote,
                'settle': settle,
                'baseId': baseId,
                'quoteId': quoteId,
                'settleId': settleId,
                'type': 'spot',
                'spot': true,
                'margin': isMarginTradingAllowed,
                'swap': false,
                'future': false,
                'delivery': false,
                'option': false,
                'active': active,
                'contract': false,
                'linear': undefined,
                'inverse': undefined,
                'contractSize': undefined,
                'expiry': undefined,
                'expiryDatetime': undefined,
                'strike': undefined,
                'optionType': undefined,
                'precision': {
                    'amount': this.parseNumber(this.parsePrecision(this.safeString(market, 'quantityPrecision'))),
                    'price': this.parseNumber(this.parsePrecision(this.safeString(market, 'pricePrecision'))),
                    'base': this.parseNumber(this.parsePrecision(this.safeString(market, 'baseAssetPrecision'))),
                    'quote': this.parseNumber(this.parsePrecision(this.safeString(market, 'quotePrecision'))),
                },
                'limits': {
                    'leverage': {
                        'min': undefined,
                        'max': undefined,
                    },
                    'amount': {
                        'min': undefined,
                        'max': undefined,
                    },
                    'price': {
                        'min': undefined,
                        'max': undefined,
                    },
                    'cost': {
                        'min': undefined,
                        'max': undefined,
                    },
                },
                'created': undefined,
                'info': market,
            };
            if ('PRICE_FILTER' in filtersByType) {
                const filter = this.safeValue(filtersByType, 'PRICE_FILTER', {});
                entry['precision']['price'] = this.safeNumber(filter, 'tickSize');
                // PRICE_FILTER reports zero values for maxPrice
                // since they updated filter types in November 2018
                // https://github.com/ccxt/ccxt/issues/4286
                // therefore limits['price']['max'] doesn't have any meaningful value except undefined
                entry['limits']['price'] = {
                    'min': this.safeNumber(filter, 'minPrice'),
                    'max': this.safeNumber(filter, 'maxPrice'),
                };
                entry['precision']['price'] = filter['tickSize'];
            }
            if ('LOT_SIZE' in filtersByType) {
                const filter = this.safeValue(filtersByType, 'LOT_SIZE', {});
                entry['precision']['amount'] = this.safeNumber(filter, 'stepSize');
                entry['limits']['amount'] = {
                    'min': this.safeNumber(filter, 'minQty'),
                    'max': this.safeNumber(filter, 'maxQty'),
                };
            }
            if ('MARKET_LOT_SIZE' in filtersByType) {
                const filter = this.safeValue(filtersByType, 'MARKET_LOT_SIZE', {});
                entry['limits']['market'] = {
                    'min': this.safeNumber(filter, 'minQty'),
                    'max': this.safeNumber(filter, 'maxQty'),
                };
            }
            if ('MIN_NOTIONAL' in filtersByType) {
                const filter = this.safeValue(filtersByType, 'MIN_NOTIONAL', {});
                entry['limits']['cost']['min'] = this.safeNumber2(filter, 'minNotional', 'notional');
            }
            result.push(entry);
        }
        return result;
    }
    /**
     * @method
     * @name tokocrypto#fetchOrderBook
     * @see https://www.tokocrypto.com/apidocs/#order-book
     * @description fetches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
     * @param {string} symbol unified symbol of the market to fetch the order book for
     * @param {int} [limit] the maximum amount of order book entries to return
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols
     */
    async fetchOrderBook(symbol, limit = undefined, params = {}) {
        await this.loadMarkets();
        const market = this.market(symbol);
        const request = {};
        if (limit !== undefined) {
            request['limit'] = limit; // default 100, max 5000, see https://github.com/binance/binance-spot-api-docs/blob/master/rest-api.md#order-book
        }
        let response = undefined;
        if (market['quote'] === 'USDT') {
            request['symbol'] = market['baseId'] + market['quoteId'];
            response = await this.binanceGetDepth(this.extend(request, params));
        }
        else {
            request['symbol'] = market['id'];
            response = await this.publicGetOpenV1MarketDepth(this.extend(request, params));
        }
        //
        // future
        //
        //     {
        //         "lastUpdateId":333598053905,
        //         "E":1618631511986,
        //         "T":1618631511964,
        //         "bids":[
        //             ["2493.56","20.189"],
        //             ["2493.54","1.000"],
        //             ["2493.51","0.005"]
        //         ],
        //         "asks":[
        //             ["2493.57","0.877"],
        //             ["2493.62","0.063"],
        //             ["2493.71","12.054"],
        //         ]
        //     }
        // type not 1
        //     {
        //         "code":0,
        //         "msg":"Success",
        //         "data":{
        //            "lastUpdateId":3204783,
        //            "bids":[],
        //            "asks": []
        //         },
        //         "timestamp":1692262634599
        //     }
        const data = this.safeValue(response, 'data', response);
        const timestamp = this.safeInteger2(response, 'T', 'timestamp');
        const orderbook = this.parseOrderBook(data, symbol, timestamp);
        orderbook['nonce'] = this.safeInteger(data, 'lastUpdateId');
        return orderbook;
    }
    parseTrade(trade, market = undefined) {
        //
        // aggregate trades
        // https://github.com/binance-exchange/binance-official-api-docs/blob/master/rest-api.md#compressedaggregate-trades-list
        //
        //     {
        //         "a": 26129,         // Aggregate tradeId
        //         "p": "0.01633102",  // Price
        //         "q": "4.70443515",  // Quantity
        //         "f": 27781,         // First tradeId
        //         "l": 27781,         // Last tradeId
        //         "T": 1498793709153, // Timestamp
        //         "m": true,          // Was the buyer the maker?
        //         "M": true           // Was the trade the best price match?
        //     }
        //
        // recent public trades and old public trades
        // https://github.com/binance-exchange/binance-official-api-docs/blob/master/rest-api.md#recent-trades-list
        // https://github.com/binance-exchange/binance-official-api-docs/blob/master/rest-api.md#old-trade-lookup-market_data
        //
        //     {
        //         "id": 28457,
        //         "price": "4.00000100",
        //         "qty": "12.00000000",
        //         "time": 1499865549590,
        //         "isBuyerMaker": true,
        //         "isBestMatch": true
        //     }
        //
        // private trades
        // https://github.com/binance-exchange/binance-official-api-docs/blob/master/rest-api.md#account-trade-list-user_data
        //
        //     {
        //         "symbol": "BNBBTC",
        //         "id": 28457,
        //         "orderId": 100234,
        //         "price": "4.00000100",
        //         "qty": "12.00000000",
        //         "commission": "10.10000000",
        //         "commissionAsset": "BNB",
        //         "time": 1499865549590,
        //         "isBuyer": true,
        //         "isMaker": false,
        //         "isBestMatch": true
        //     }
        //
        // futures trades
        // https://binance-docs.github.io/apidocs/futures/en/#account-trade-list-user_data
        //
        //     {
        //       "accountId": 20,
        //       "buyer": False,
        //       "commission": "-0.07819010",
        //       "commissionAsset": "USDT",
        //       "counterPartyId": 653,
        //       "id": 698759,
        //       "maker": False,
        //       "orderId": 25851813,
        //       "price": "7819.01",
        //       "qty": "0.002",
        //       "quoteQty": "0.01563",
        //       "realizedPnl": "-0.91539999",
        //       "side": "SELL",
        //       "symbol": "BTCUSDT",
        //       "time": 1569514978020
        //     }
        //     {
        //       "symbol": "BTCUSDT",
        //       "id": 477128891,
        //       "orderId": 13809777875,
        //       "side": "SELL",
        //       "price": "38479.55",
        //       "qty": "0.001",
        //       "realizedPnl": "-0.00009534",
        //       "marginAsset": "USDT",
        //       "quoteQty": "38.47955",
        //       "commission": "-0.00076959",
        //       "commissionAsset": "USDT",
        //       "time": 1612733566708,
        //       "positionSide": "BOTH",
        //       "maker": true,
        //       "buyer": false
        //     }
        //
        // { respType: FULL }
        //
        //     {
        //       "price": "4000.00000000",
        //       "qty": "1.00000000",
        //       "commission": "4.00000000",
        //       "commissionAsset": "USDT",
        //       "tradeId": "1234",
        //     }
        //
        const timestamp = this.safeInteger2(trade, 'T', 'time');
        const price = this.safeString2(trade, 'p', 'price');
        const amount = this.safeString2(trade, 'q', 'qty');
        const cost = this.safeString2(trade, 'quoteQty', 'baseQty'); // inverse futures
        const marketId = this.safeString(trade, 'symbol');
        const symbol = this.safeSymbol(marketId, market);
        let id = this.safeString2(trade, 't', 'a');
        id = this.safeString2(trade, 'id', 'tradeId', id);
        let side = undefined;
        const orderId = this.safeString(trade, 'orderId');
        const buyerMaker = this.safeValue2(trade, 'm', 'isBuyerMaker');
        let takerOrMaker = undefined;
        if (buyerMaker !== undefined) {
            side = buyerMaker ? 'sell' : 'buy'; // this is reversed intentionally
            takerOrMaker = 'taker';
        }
        else if ('side' in trade) {
            side = this.safeStringLower(trade, 'side');
        }
        else {
            if ('isBuyer' in trade) {
                side = trade['isBuyer'] ? 'buy' : 'sell'; // this is a true side
            }
        }
        let fee = undefined;
        if ('commission' in trade) {
            fee = {
                'cost': this.safeString(trade, 'commission'),
                'currency': this.safeCurrencyCode(this.safeString(trade, 'commissionAsset')),
            };
        }
        if ('isMaker' in trade) {
            takerOrMaker = trade['isMaker'] ? 'maker' : 'taker';
        }
        if ('maker' in trade) {
            takerOrMaker = trade['maker'] ? 'maker' : 'taker';
        }
        return this.safeTrade({
            'info': trade,
            'timestamp': timestamp,
            'datetime': this.iso8601(timestamp),
            'symbol': symbol,
            'id': id,
            'order': orderId,
            'type': undefined,
            'side': side,
            'takerOrMaker': takerOrMaker,
            'price': price,
            'amount': amount,
            'cost': cost,
            'fee': fee,
        }, market);
    }
    /**
     * @method
     * @name tokocrypto#fetchTrades
     * @see https://www.tokocrypto.com/apidocs/#recent-trades-list
     * @see https://www.tokocrypto.com/apidocs/#compressedaggregate-trades-list
     * @description get the list of most recent trades for a particular symbol
     * @param {string} symbol unified symbol of the market to fetch trades for
     * @param {int} [since] timestamp in ms of the earliest trade to fetch
     * @param {int} [limit] the maximum amount of trades to fetch
     * @param {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': this.getMarketIdByType(market),
            // 'fromId': 123,    // ID to get aggregate trades from INCLUSIVE.
            // 'startTime': 456, // Timestamp in ms to get aggregate trades from INCLUSIVE.
            // 'endTime': 789,   // Timestamp in ms to get aggregate trades until INCLUSIVE.
            // 'limit': 500,     // default = 500, maximum = 1000
        };
        if (market['quote'] !== 'USDT') {
            if (limit !== undefined) {
                request['limit'] = limit;
            }
            const responseInner = this.publicGetOpenV1MarketTrades(this.extend(request, params));
            //
            //    {
            //       "code": 0,
            //       "msg": "success",
            //       "data": {
            //           "list": [
            //                {
            //                    "id": 28457,
            //                    "price": "4.00000100",
            //                    "qty": "12.00000000",
            //                    "time": 1499865549590,
            //                    "isBuyerMaker": true,
            //                    "isBestMatch": true
            //                }
            //            ]
            //        },
            //        "timestamp": 1571921637091
            //    }
            //
            const data = this.safeDict(responseInner, 'data', {});
            const list = this.safeList(data, 'list', []);
            return this.parseTrades(list, market, since, limit);
        }
        if (limit !== undefined) {
            request['limit'] = limit; // default = 500, maximum = 1000
        }
        const defaultMethod = 'binanceGetTrades';
        const method = this.safeString(this.options, 'fetchTradesMethod', defaultMethod);
        let response = undefined;
        if ((method === 'binanceGetAggTrades') && (since !== undefined)) {
            request['startTime'] = since;
            // https://github.com/ccxt/ccxt/issues/6400
            // https://github.com/binance-exchange/binance-official-api-docs/blob/master/rest-api.md#compressedaggregate-trades-list
            request['endTime'] = this.sum(since, 3600000);
            response = await this.binanceGetAggTrades(this.extend(request, params));
        }
        else {
            response = await this.binanceGetTrades(this.extend(request, params));
        }
        //
        // Caveats:
        // - default limit (500) applies only if no other parameters set, trades up
        //   to the maximum limit may be returned to satisfy other parameters
        // - if both limit and time window is set and time window contains more
        //   trades than the limit then the last trades from the window are returned
        // - 'tradeId' accepted and returned by this method is "aggregate" trade id
        //   which is different from actual trade id
        // - setting both fromId and time window results in error
        //
        // aggregate trades
        //
        //     [
        //         {
        //             "a": 26129,         // Aggregate tradeId
        //             "p": "0.01633102",  // Price
        //             "q": "4.70443515",  // Quantity
        //             "f": 27781,         // First tradeId
        //             "l": 27781,         // Last tradeId
        //             "T": 1498793709153, // Timestamp
        //             "m": true,          // Was the buyer the maker?
        //             "M": true           // Was the trade the best price match?
        //         }
        //     ]
        //
        // recent public trades and historical public trades
        //
        //     [
        //         {
        //             "id": 28457,
        //             "price": "4.00000100",
        //             "qty": "12.00000000",
        //             "time": 1499865549590,
        //             "isBuyerMaker": true,
        //             "isBestMatch": true
        //         }
        //     ]
        //
        return this.parseTrades(response, market, since, limit);
    }
    parseTicker(ticker, market = undefined) {
        //
        //     {
        //         "symbol": "ETHBTC",
        //         "priceChange": "0.00068700",
        //         "priceChangePercent": "2.075",
        //         "weightedAvgPrice": "0.03342681",
        //         "prevClosePrice": "0.03310300",
        //         "lastPrice": "0.03378900",
        //         "lastQty": "0.07700000",
        //         "bidPrice": "0.03378900",
        //         "bidQty": "7.16800000",
        //         "askPrice": "0.03379000",
        //         "askQty": "24.00000000",
        //         "openPrice": "0.03310200",
        //         "highPrice": "0.03388900",
        //         "lowPrice": "0.03306900",
        //         "volume": "205478.41000000",
        //         "quoteVolume": "6868.48826294",
        //         "openTime": 1601469986932,
        //         "closeTime": 1601556386932,
        //         "firstId": 196098772,
        //         "lastId": 196186315,
        //         "count": 87544
        //     }
        //
        // coinm
        //     {
        //         "baseVolume": "214549.95171161",
        //         "closeTime": "1621965286847",
        //         "count": "1283779",
        //         "firstId": "152560106",
        //         "highPrice": "39938.3",
        //         "lastId": "153843955",
        //         "lastPrice": "37993.4",
        //         "lastQty": "1",
        //         "lowPrice": "36457.2",
        //         "openPrice": "37783.4",
        //         "openTime": "1621878840000",
        //         "pair": "BTCUSD",
        //         "priceChange": "210.0",
        //         "priceChangePercent": "0.556",
        //         "symbol": "BTCUSD_PERP",
        //         "volume": "81990451",
        //         "weightedAvgPrice": "38215.08713747"
        //     }
        //
        const timestamp = this.safeInteger(ticker, 'closeTime');
        const marketId = this.safeString(ticker, 'symbol');
        const symbol = this.safeSymbol(marketId, market);
        const last = this.safeString(ticker, 'lastPrice');
        const isCoinm = ('baseVolume' in ticker);
        let baseVolume = undefined;
        let quoteVolume = undefined;
        if (isCoinm) {
            baseVolume = this.safeString(ticker, 'baseVolume');
            quoteVolume = this.safeString(ticker, 'volume');
        }
        else {
            baseVolume = this.safeString(ticker, 'volume');
            quoteVolume = this.safeString(ticker, 'quoteVolume');
        }
        return this.safeTicker({
            'symbol': symbol,
            'timestamp': timestamp,
            'datetime': this.iso8601(timestamp),
            'high': this.safeString(ticker, 'highPrice'),
            'low': this.safeString(ticker, 'lowPrice'),
            'bid': this.safeString(ticker, 'bidPrice'),
            'bidVolume': this.safeString(ticker, 'bidQty'),
            'ask': this.safeString(ticker, 'askPrice'),
            'askVolume': this.safeString(ticker, 'askQty'),
            'vwap': this.safeString(ticker, 'weightedAvgPrice'),
            'open': this.safeString(ticker, 'openPrice'),
            'close': last,
            'last': last,
            'previousClose': this.safeString(ticker, 'prevClosePrice'),
            'change': this.safeString(ticker, 'priceChange'),
            'percentage': this.safeString(ticker, 'priceChangePercent'),
            'average': undefined,
            'baseVolume': baseVolume,
            'quoteVolume': quoteVolume,
            'info': ticker,
        }, market);
    }
    /**
     * @method
     * @name tokocrypto#fetchTickers
     * @see https://binance-docs.github.io/apidocs/spot/en/#24hr-ticker-price-change-statistics
     * @description fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market
     * @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();
        const response = await this.binanceGetTicker24hr(params);
        return this.parseTickers(response, symbols);
    }
    getMarketIdByType(market) {
        if (market['quote'] === 'USDT') {
            return market['baseId'] + market['quoteId'];
        }
        return market['id'];
    }
    /**
     * @method
     * @name tokocrypto#fetchTicker
     * @see https://binance-docs.github.io/apidocs/spot/en/#24hr-ticker-price-change-statistics
     * @description fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
     * @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['baseId'] + market['quoteId'],
        };
        const response = await this.binanceGetTicker24hr(this.extend(request, params));
        if (Array.isArray(response)) {
            const firstTicker = this.safeDict(response, 0, {});
            return this.parseTicker(firstTicker, market);
        }
        return this.parseTicker(response, market);
    }
    /**
     * @method
     * @name tokocrypto#fetchBidsAsks
     * @see https://binance-docs.github.io/apidocs/spot/en/#symbol-order-book-ticker
     * @description fetches the bid and ask price and volume for multiple markets
     * @param {string[]|undefined} symbols unified symbols of the markets to fetch the bids and asks for, all markets 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 fetchBidsAsks(symbols = undefined, params = {}) {
        await this.loadMarkets();
        const response = await this.binanceGetTickerBookTicker(params);
        return this.parseTickers(response, symbols);
    }
    parseOHLCV(ohlcv, market = undefined) {
        // when api method = publicGetKlines || fapiPublicGetKlines || dapiPublicGetKlines
        //     [
        //         1591478520000, // open time
        //         "0.02501300",  // open
        //         "0.02501800",  // high
        //         "0.02500000",  // low
        //         "0.02500000",  // close
        //         "22.19000000", // volume
        //         1591478579999, // close time
        //         "0.55490906",  // quote asset volume
        //         40,            // number of trades
        //         "10.92900000", // taker buy base asset volume
        //         "0.27336462",  // taker buy quote asset volume
        //         "0"            // ignore
        //     ]
        //
        //  when api method = fapiPublicGetMarkPriceKlines || fapiPublicGetIndexPriceKlines
        //     [
        //         [
        //         1591256460000,          // Open time
        //         "9653.29201333",        // Open
        //         "9654.56401333",        // High
        //         "9653.07367333",        // Low
        //         "9653.07367333",        // Close (or latest price)
        //         "0",                    // Ignore
        //         1591256519999,          // Close time
        //         "0",                    // Ignore
        //         60,                     // Number of bisic data
        //         "0",                    // Ignore
        //         "0",                    // Ignore
        //         "0"                     // Ignore
        //         ]
        //     ]
        //
        return [
            this.safeInteger(ohlcv, 0),
            this.safeNumber(ohlcv, 1),
            this.safeNumber(ohlcv, 2),
            this.safeNumber(ohlcv, 3),
            this.safeNumber(ohlcv, 4),
            this.safeNumber(ohlcv, 5),
        ];
    }
    /**
     * @method
     * @name tokocrypto#fetchOHLCV
     * @see https://binance-docs.github.io/apidocs/spot/en/#kline-candlestick-data
     * @description fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
     * @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 {string} [params.price] "mark" or "index" for mark price and index price candles
     * @param {int} [params.until] timestamp in ms of the latest candle to fetch
     * @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();
        const market = this.market(symbol);
        // binance docs say that the default limit 500, max 1500 for futures, max 1000 for spot markets
        // the reality is that the time range wider than 500 candles won't work right
        const defaultLimit = 500;
        const maxLimit = 1500;
        const price = this.safeString(params, 'price');
        const until = this.safeInteger(params, 'until');
        params = this.omit(params, ['price', 'until']);
        limit = (limit === undefined) ? defaultLimit : Math.min(limit, maxLimit);
        const request = {
            'interval': this.safeString(this.timeframes, timeframe, timeframe),
            'limit': limit,
        };
        if (price === 'index') {
            request['pair'] = market['id']; // Index price takes this argument instead of symbol
        }
        else {
            request['symbol'] = this.getMarketIdByType(market);
        }
        // const duration = this.parseTimeframe (timeframe);
        if (since !== undefined) {
            request['startTime'] = since;
        }
        if (until !== undefined) {
            request['endTime'] = until;
        }
        let response = undefined;
        if (market['quote'] === 'USDT') {
            response = await this.binanceGetKlines(this.extend(request, params));
        }
        else {
            response = await this.publicGetOpenV1MarketKlines(this.extend(request, params));
        }
        //
        //     [
        //         [1591478520000,"0.02501300","0.02501800","0.02500000","0.02500000","22.19000000",1591478579999,"0.55490906",40,"10.92900000","0.27336462","0"],
        //         [1591478580000,"0.02499600","0.02500900","0.02499400","0.02500300","21.34700000",1591478639999,"0.53370468",24,"7.53800000","0.18850725","0"],
        //         [1591478640000,"0.02500800","0.02501100","0.02500300","0.02500800","154.14200000",1591478699999,"3.85405839",97,"5.32300000","0.13312641","0"],
        //     ]
        //
        const data = this.safeList(response, 'data', response);
        return this.parseOHLCVs(data, market, timeframe, since, limit);
    }
    /**
     * @method
     * @name tokocrypto#fetchBalance
     * @see https://www.tokocrypto.com/apidocs/#account-information-signed
     * @description query for balance and get the amount of funds available for trading or funds locked in orders
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @param {string} [params.type] 'future', 'delivery', 'savings', 'funding', or 'spot'
     * @param {string} [params.marginMode] 'cross' or 'isolated', for margin trading, uses this.options.defaultMarginMode if not passed, defaults to undefined/None/null
     * @param {string[]|undefined} [params.symbols] unified market symbols, only used in isolated margin mode
     * @returns {object} a [balance structure]{@link https://docs.ccxt.com/#/?id=balance-structure}
     */
    async fetchBalance(params = {}) {
        await this.loadMarkets();
        const defaultType = this.safeString2(this.options, 'fetchBalance', 'defaultType', 'spot');
        const type = this.safeString(params, 'type', defaultType);
        const defaultMarginMode = this.safeString2(this.options, 'marginMode', 'defaultMarginMode');
        const marginMode = this.safeStringLower(params, 'marginMode', defaultMarginMode);
        const request = {};
        const response = await this.privateGetOpenV1AccountSpot(this.extend(request, params));
        //
        // spot
        //
        //     {
        //         "code":0,
        //         "msg":"Success",
        //         "data":{
        //             "makerCommission":"0.00100000",
        //             "takerCommission":"0.00100000",
        //             "buyerCommission":"0.00000000",
        //             "sellerCommission":"0.00000000",
        //             "canTrade":1,
        //             "canWithdraw":1,
        //             "canDeposit":1,
        //             "status":1,
        //             "accountAssets":[
        //                 {"asset":"1INCH","free":"0","locked":"0"},
        //                 {"asset":"AAVE","free":"0","locked":"0"},
        //                 {"asset":"ACA","free":"0","locked":"0"}
        //             ],
        //         },
        //         "timestamp":1659666786943
        //     }
        //
        return this.parseBalanceCustom(response, type, marginMode);
    }
    parseBalanceCustom(response, type = undefined, marginMode = undefined) {
        const timestamp = this.safeInteger(response, 'updateTime');
        const result = {
            'info': response,
            'timestamp': timestamp,
            'datetime': this.iso8601(timestamp),
        };
        const data = this.safeValue(response, 'data', {});
        const balances = this.safeValue(data, 'accountAssets', []);
        for (let i = 0; i < balances.length; i++) {
            const balance = balances[i];
            const currencyId = this.safeString(balance, 'asset');
            const code = this.safeCurrencyCode(currencyId);
            const account = this.account();
            account['free'] = this.safeString(balance, 'free');
            account['used'] = this.safeString(balance, 'locked');
            result[code] = account;
        }
        return this.safeBalance(result);
    }
    parseOrderStatus(status) {
        const statuses = {
            '-2': 'open',
            '0': 'open',
            '1': 'open',
            '2': 'closed',
            '3': 'canceled',
            '4': 'canceling',
            '5': 'rejected',
            '6': 'expired',
            'NEW': 'open',
            'PARTIALLY_FILLED': 'open',
            'FILLED': 'closed',
            'CANCELED': 'canceled',
            'PENDING_CANCEL': 'canceling',
            'REJECTED': 'rejected',
            'EXPIRED': 'expired',
        };
        return this.safeString(statuses, status, status);
    }
    parseOrder(order, market = undefined) {
        //
        // spot
        //
        //     {
        //         "symbol": "LTCBTC",
        //         "orderId": 1,
        //         "clientOrderId": "myOrder1",
        //         "price": "0.1",
        //         "origQty": "1.0",
        //         "executedQty": "0.0",
        //         "cummulativeQuoteQty": "0.0",
        //         "status": "NEW",
        //         "timeInForce": "GTC",
        //         "type": "LIMIT",
        //         "side": "BUY",
        //         "stopPrice": "0.0",
        //         "icebergQty": "0.0",
        //         "time": 1499827319559,
        //         "updateTime": 1499827319559,
        //         "isWorking": true
        //     }
        // createOrder
        //     {
        //         "orderId": "145265071",
        //         "bOrderListId": "0",
        //         "clientId": "49c09c3c2cd54419a59c05441f517b3c",
        //         "bOrderId": "35247529",
        //         "symbol": "USDT_BIDR",
        //         "symbolType": "1",
        //         "side": "0",
        //         "type": "1",
        //         "price": "11915",
        //         "origQty": "2",
        //         "origQuoteQty": "23830.00",
        //         "executedQty": "0.00000000",
        //         "executedPrice": "0",
        //         "executedQuoteQty": "0.00",
        //         "timeInForce": "1",
        //         "stopPrice": "0",
        //         "icebergQty": "0",
        //         "status": "0",
        //         "createTime": "1662711074372"
        //     }
        //
        // createOrder with { "newOrderRespType": "FULL" }
        //
        //     {
        //       "symbol": "BTCUSDT",
        //       "orderId": 5403233939,
        //       "orderListId": -1,
        //       "clientOrderId": "x-R4BD3S825e669e75b6c14f69a2c43e",
        //       "transactTime": 1617151923742,
        //       "price": "0.00000000",
        //       "origQty": "0.00050000",
        //       "executedQty": "0.00050000",
        //       "cummulativeQuoteQty": "29.47081500",
        //       "status": "FILLED",
        //       "timeInForce": "GTC",
        //       "type": "MARKET",
        //       "side": "BUY",
        //       "fills": [
        //         {
        //           "price": "58941.63000000",
        //           "qty": "0.00050000",
        //           "commission": "0.00007050",
        //           "commissionAsset": "BNB",
        //           "tradeId": 737466631
        //         }
        //       ]
        //     }
        //
        // delivery
        //
        //     {
        //       "orderId": "18742727411",
        //       "symbol": "ETHUSD_PERP",
        //       "pair": "ETHUSD",
        //       "status": "FILLED",
        //       "clientOrderId": "x-xcKtGhcu3e2d1503fdd543b3b02419",
        //       "price": "0",
        //       "avgPrice": "4522.14",
        //       "origQty": "1",
        //       "executedQty": "1",
        //       "cumBase": "0.00221134",
        //       "timeInForce": "GTC",
        //       "type": "MARKET",
        //       "reduceOnly": false,
        //       "closePosition": false,
        //       "side": "SELL",
        //       "positionSide": "BOTH",
        //       "stopPrice": "0",
        //       "workingType": "CONTRACT_PRICE",
        //       "priceProtect": false,
        //       "origType": "MARKET",
        //       "time": "1636061952660",
        //       "updateTime": "1636061952660"
        //     }
        //
        const status = this.parseOrderStatus(this.safeString(order, 'status'));
        const marketId = this.safeString(order, 'symbol');
        const symbol = this.safeSymbol(marketId, market);
        const filled = this.safeString(order, 'executedQty', '0');
        const timestamp = this.safeInteger(order, 'createTime');
        const average = this.safeString(order, 'avgPrice');
        const price = this.safeString2(order, 'price', 'executedPrice');
        const amount = this.safeString(order, 'origQty');
        // - Spot/Margin market: cummulativeQuoteQty
        //   Note this is not the actual cost, since Binance futures uses leverage to calculate margins.
        const cost = this.safeStringN(order, ['cummulativeQuoteQty', 'cumQuote', 'executedQuoteQty', 'cumBase']);
        const id = this.safeString(order, 'orderId');
        const type = this.parseOrderType(this.safeStringLower(order, 'type'));
        let side = this.safeStringLower(order, 'side');
        if (side === '0') {
            side = 'buy';
        }
        else if (side === '1') {
            side = 'sell';
        }
        const fills = this.safeValue(order, 'fills', []);
        const clientOrderId = this.safeString2(order, 'clientOrderId', 'clientId');
        let timeInForce = this.safeString(order, 'timeInForce');
        if (timeInForce === 'GTX') {
            // GTX means "Good Till Crossing" and is an equivalent way of saying Post Only
            timeInForce = 'PO';
        }
        const postOnly = (type === 'limit_maker') || (timeInForce === 'PO');
        return this.safeOrder({
            'info': order,
            'id': id,
            'clientOrderId': clientOrderId,
            'timestamp': timestamp,
            'datetime': this.iso8601(timestamp),
            'lastTradeTimestamp': undefined,
            'symbol': symbol,
            'type': type,
            'timeInForce': timeInForce,
            'postOnly': postOnly,
            'reduceOnly': this.safeValue(order, 'reduceOnly'),
            'side': side,
            'price': price,
            'triggerPrice': this.parseNumber(this.omitZero(this.safeString(order, 'stopPrice'))),
            'amount': amount,
            'cost': cost,
            'average': average,
            'filled': filled,
            'remaining': undefined,
            'status': status,
            'fee': undefined,
            'trades': fills,
        }, market);
    }
    parseOrderType(status) {
        const statuses = {
            '2': 'market',
            '1': 'limit',
            '4': 'limit',
            '7': 'limit',
        };
        return this.safeString(statuses, status, status);
    }
    /**
     * @method
     * @name tokocrypto#createOrder
     * @description create a trade order
     * @see https://www.tokocrypto.com/apidocs/#new-order--signed
     * @param {string} symbol unified symbol of the market to create an order in
     * @param {string} type 'market' or 'limit'
     * @param {string} side 'buy' or 'sell'
     * @param {float} amount how much of currency you want to trade in units of 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 {float} [params.triggerPrice] the price at which a trigger order would be triggered
     * @param {float} [params.cost] for spot market buy orders, the quote quantity that can be used as an alternative for the amount
     * @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 clientOrderId = this.safeString2(params, 'clientOrderId', 'clientId');
        const postOnly = this.safeBool(params, 'postOnly', false);
        // only supported for spot/margin api
        if (postOnly) {
            type = 'LIMIT_MAKER';
        }
        params = this.omit(params, ['clientId', 'clientOrderId']);
        const initialUppercaseType = type.toUpperCase();
        let uppercaseType = initialUppercaseType;
        const triggerPrice = this.safeValue2(params, 'triggerPrice', 'stopPrice');
        if (triggerPrice !== undefined) {
            params = this.omit(params, ['triggerPrice', 'stopPrice']);
            if (uppercaseType === 'MARKET') {
                uppercaseType = 'STOP_LOSS';
            }
            else if (uppercaseType === 'LIMIT') {
                uppercaseType = 'STOP_LOSS_LIMIT';
            }
        }
        const validOrderTypes = this.safeValue(market['info'], 'orderTypes');
        if (!this.inArray(uppercaseType, validOrderTypes)) {
            if (initialUppercaseType !== uppercaseType) {
                throw new errors.InvalidOrder(this.id + ' triggerPrice parameter is not allowed for ' + symbol + ' ' + type + ' orders');
            }
            else {
                throw new errors.InvalidOrder(this.id + ' ' + type + ' is not a valid order type for the ' + symbol + ' market');
            }
        }
        const reverseOrderTypeMapping = {
            'LIMIT': 1,
            'MARKET': 2,
            'STOP_LOSS': 3,
            'STOP_LOSS_LIMIT': 4,
            'TAKE_PROFIT': 5,
            'TAKE_PROFIT_LIMIT': 6,
            'LIMIT_MAKER': 7,
        };
        const request = {
            'symbol': market['baseId'] + '_' + market['quoteId'],
            'type': this.safeString(reverseOrderTypeMapping, uppercaseType),
        };
        if (side === 'buy') {
            request['side'] = 0;
        }
        else if (side === 'sell') {
            request['side'] = 1;
        }
        if (clientOrderId === undefined) {
            const broker = this.safeValue(this.options, 'broker');
            if (broker !== undefined) {
                const brokerId = this.safeString(broker, 'marketType');
                if (brokerId !== undefined) {
                    request['clientId'] = brokerId + this.uuid22();
                }
            }
        }
        else {
            request['clientId'] = clientOrderId;
        }
        // additional required fields depending on the order type
        let priceIsRequired = false;
        let triggerPriceIsRequired = false;
        let quantityIsRequired = false;
        //
        // spot/margin
        //
        //     LIMIT                timeInForce, quantity, price
        //     MARKET               quantity or quoteOrderQty
        //     STOP_LOSS            quantity, stopPrice
        //     STOP_LOSS_LIMIT      timeInForce, quantity, price, stopPrice
        //     TAKE_PROFIT          quantity, stopPrice
        //     TAKE_PROFIT_LIMIT    timeInForce, quantity, price, stopPrice
        //     LIMIT_MAKER          quantity, price
        //
        if (uppercaseType === 'MARKET') {
            if (side === 'buy') {
                const precision = market['precision']['price'];
                let quoteAmount = undefined;
                let createMarketBuyOrderRequiresPrice = true;
                [createMarketBuyOrderRequiresPrice, params] = this.handleOptionAndParams(params, 'createOrder', 'createMarketBuyOrderRequiresPrice', true);
                const cost = this.safeNumber2(params, 'cost', 'quoteOrderQty');
                params = this.omit(params, ['cost', 'quoteOrderQty']);
                if (cost !== undefined) {
                    quoteAmount = cost;
                }
                else if (createMarketBuyOrderRequiresPrice) {
                    if (price === undefined) {
                        throw new errors.InvalidOrder(this.id + ' createOrder() requires the price argument for market buy orders to calculate the total cost to spend (amount * price), alternatively set the createMarketBuyOrderRequiresPrice option or param to false and pass the cost to spend (quote quantity) in the amount argument');
                    }
                    else {
                        const amountString = this.numberToString(amount);
                        const priceString = this.numberToString(price);
                        quoteAmount = Precise["default"].stringMul(amountString, priceString);
                    }
                }
                else {
                    quoteAmount = amount;
                }
                request['quoteOrderQty'] = this.decimalToPrecision(quoteAmount, number.TRUNCATE, precision, this.precisionMode);
            }
            else {
                quantityIsRequired = true;
            }
        }
        else if (uppercaseType === 'LIMIT') {
            priceIsRequired = true;
            quantityIsRequired = true;
        }
        else if ((uppercaseType === 'STOP_LOSS') || (uppercaseType === 'TAKE_PROFIT')) {
            triggerPriceIsRequired = true;
            quantityIsRequired = true;
            if (market['linear'] || market['inverse']) {
                priceIsRequired = true;
            }
        }
        else if ((uppercaseType === 'STOP_LOSS_LIMIT') || (uppercaseType === 'TAKE_PROFIT_LIMIT')) {
            quantityIsRequired = true;
            triggerPriceIsRequired = true;
            priceIsRequired = true;
        }
        else if (uppercaseType === 'LIMIT_MAKER') {
            priceIsRequired = true;
            quantityIsRequired = true;
        }
        if (quantityIsRequired) {
            request['quantity'] = this.amountToPrecision(symbol, amount);
        }
        if (priceIsRequired) {
            if (price === undefined) {
                throw new errors.InvalidOrder(this.id + ' createOrder() requires a price argument for a ' + type + ' order');
            }
            request['price'] = this.priceToPrecision(symbol, price);
        }
        if (triggerPriceIsRequired) {
            if (triggerPrice === undefined) {
                throw new errors.InvalidOrder(this.id + ' createOrder() requires a triggerPrice extra param for a ' + type + ' order');
            }
            else {
                request['stopPrice'] = this.priceToPrecision(symbol, triggerPrice);
            }
        }
        const response = await this.privatePostOpenV1Orders(this.extend(request, params));
        //
        //     {
        //         "code": 0,
        //         "msg": "Success",
        //         "data": {
        //             "orderId": 145264846,
        //             "bOrderListId": 0,
        //             "clientId": "4ee2ab5e55e74b358eaf98079c670d17",
        //             "bOrderId": 35247499,
        //             "symbol": "USDT_BIDR",
        //             "symbolType": 1,
        //             "side": 0,
        //             "type": 1,
        //             "price": "11915",
        //             "origQty": "2",
        //             "origQuoteQty": "23830.00",
        //             "executedQty": "0.00000000",
        //             "executedPrice": "0",
        //             "executedQuoteQty": "0.00",
        //             "timeInForce": 1,
        //             "stopPrice": 0,
        //             "icebergQty": "0",
        //             "status": 0,
        //             "createTime": 1662710994848
        //         },
        //         "timestamp": 1662710994975
        //     }
        //
        const rawOrder = this.safeDict(response, 'data', {});
        return this.parseOrder(rawOrder, market);
    }
    /**
     * @method
     * @name tokocrypto#fetchOrder
     * @see https://www.tokocrypto.com/apidocs/#query-order-signed
     * @description fetches information on an order made by the user
     * @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
     * @returns {object} An [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
     */
    async fetchOrder(id, symbol = undefined, params = {}) {
        const request = {
            'orderId': id,
        };
        const response = await this.privateGetOpenV1Orders(this.extend(request, params));
        //
        //     {
        //         "code": 0,
        //         "msg": "Success",
        //         "data": {
        //             "list": [{
        //                 "orderId": "145221985",
        //                 "clientId": "201515331fd64d03aedbe687a38152e3",
        //                 "bOrderId": "35239632",
        //                 "bOrderListId": "0",
        //                 "symbol": "USDT_BIDR",
        //                 "symbolType": 1,
        //                 "side": 0,
        //                 "type": 1,
        //                 "price": "11907",
        //                 "origQty": "2",
        //                 "origQuoteQty": "23814",
        //                 "executedQty": "0",
        //                 "executedPrice": "0",
        //                 "executedQuoteQty": "0",
        //                 "timeInForce": 1,
        //                 "stopPrice": "0",
        //                 "icebergQty": "0",
        //                 "status": 0,
        //                 "createTime": 1662699360000
        //             }]
        //         },
        //         "timestamp": 1662710056523
        //     }
        //
        const data = this.safeValue(response, 'data', {});
        const list = this.safeValue(data, 'list', []);
        const rawOrder = this.safeDict(list, 0, {});
        return this.parseOrder(rawOrder);
    }
    /**
     * @method
     * @name tokocrypto#fetchOrders
     * @see https://www.tokocrypto.com/apidocs/#all-orders-signed
     * @description fetches information on multiple orders made by the user
     * @param {string} symbol unified market symbol of the market orders were made in
     * @param {int} [since] the earliest time in ms to fetch orders for
     * @param {int} [limit] the maximum number of order structures to retrieve
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
     */
    async fetchOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
        if (symbol === undefined) {
            throw new errors.ArgumentsRequired(this.id + ' fetchOrders() requires a symbol argument');
        }
        await this.loadMarkets();
        const market = this.market(symbol);
        const request = {
            'symbol': market['id'],
            // 'type': -1, // -1 = all, 1 = open, 2 = closed
            // 'side': 1, // or 2
            // 'startTime': since,
            // 'endTime': this.milliseconds (),
            // 'fromId': 'starting order ID', // if defined, the "direct" field becomes mandatory
            // 'direct': 'prev', // prev, next
            // 'limit': 500, // default 500, max 1000
        };
        if (since !== undefined) {
            request['startTime'] = since;
        }
        if (limit !== undefined) {
            request['limit'] = limit;
        }
        const response = await this.privateGetOpenV1Orders(this.extend(request, params));
        //
        //     {
        //         "code": 0,
        //         "msg": "success",
        //         "data": {
        //             "list": [
        //                 {
        //                     "orderId": "4", // order id
        //                     "bOrderId": "100001", // binance order id
        //                     "bOrderListId": -1, // Unless part of an OCO, the value will always be -1.
        //                     "clientId": "1aa4f99ad7bc4fab903395afd25d0597", // client custom order id
        //                     "symbol": "ADA_USDT",
        //                     "symbolType": 1,
        //                     "side": 1,
        //                     "type": 1,
        //                     "price": "0.1",
        //                     "origQty": "10",
        //                     "origQuoteQty": "1",
        //                     "executedQty": "0",
        //                     "executedPrice": "0",
        //                     "executedQuoteQty": "0",
        //                     "timeInForce": 1,
        //                     "stopPrice": "0.0000000000000000",
        //                     "icebergQty": "0.0000000000000000",
        //                     "status": 0,
        //                     "isWorking": 0,
        //                     "createTime": 1572692016811
        //                 }
        //             ]
        //         },
        //         "timestamp": 1572860756458
        //     }
        //
        const data = this.safeValue(response, 'data', {});
        const orders = this.safeList(data, 'list', []);
        return this.parseOrders(orders, market, since, limit);
    }
    /**
     * @method
     * @name tokocrypto#fetchOpenOrders
     * @see https://www.tokocrypto.com/apidocs/#all-orders-signed
     * @description fetch all unfilled currently open orders
     * @param {string} symbol unified market symbol
     * @param {int} [since] the earliest time in ms to fetch open orders for
     * @param {int} [limit] the maximum number of  open orders structures to retrieve
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
     */
    async fetchOpenOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
        const request = { 'type': 1 }; // -1 = all, 1 = open, 2 = closed
        return await this.fetchOrders(symbol, since, limit, this.extend(request, params));
    }
    /**
     * @method
     * @name tokocrypto#fetchClosedOrders
     * @see https://www.tokocrypto.com/apidocs/#all-orders-signed
     * @description fetches information on multiple closed orders made by the user
     * @param {string} symbol unified market symbol of the market orders were made in
     * @param {int} [since] the earliest time in ms to fetch orders for
     * @param {int} [limit] the maximum number of order structures to retrieve
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
     */
    async fetchClosedOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
        const request = { 'type': 2 }; // -1 = all, 1 = open, 2 = closed
        return await this.fetchOrders(symbol, since, limit, this.extend(request, params));
    }
    /**
     * @method
     * @name tokocrypto#cancelOrder
     * @see https://www.tokocrypto.com/apidocs/#cancel-order-signed
     * @description cancels an open order
     * @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
     * @returns {object} An [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
     */
    async cancelOrder(id, symbol = undefined, params = {}) {
        const request = {
            'orderId': id,
        };
        const response = await this.privatePostOpenV1OrdersCancel(this.extend(request, params));
        //
        //     {
        //         "code": 0,
        //         "msg": "Success",
        //         "data": {
        //             "orderId": "145221985",
        //             "bOrderListId": "0",
        //             "clientId": "201515331fd64d03aedbe687a38152e3",
        //             "bOrderId": "35239632",
        //             "symbol": "USDT_BIDR",
        //             "symbolType": 1,
        //             "type": 1,
        //             "side": 0,
        //             "price": "11907.0000000000000000",
        //             "origQty": "2.0000000000000000",
        //             "origQuoteQty": "23814.0000000000000000",
        //             "executedPrice": "0.0000000000000000",
        //             "executedQty": "0.00000000",
        //             "executedQuoteQty": "0.00",
        //             "timeInForce": 1,
        //             "stopPrice": "0.0000000000000000",
        //             "icebergQty": "0.0000000000000000",
        //             "status": 3
        //         },
        //         "timestamp": 1662710683634
        //     }
        //
        const rawOrder = this.safeDict(response, 'data', {});
        return this.parseOrder(rawOrder);
    }
    /**
     * @method
     * @name tokocrypto#fetchMyTrades
     * @see https://www.tokocrypto.com/apidocs/#account-trade-list-signed
     * @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
     * @returns {Trade[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=trade-structure}
     */
    async fetchMyTrades(symbol = undefined, since = undefined, limit = undefined, params = {}) {
        if (symbol === undefined) {
            throw new errors.ArgumentsRequired(this.id + ' fetchMyTrades() requires a symbol argument');
        }
        await this.loadMarkets();
        const market = this.market(symbol);
        const request = {
            'symbol': market['id'],
        };
        const endTime = this.safeInteger2(params, 'until', 'endTime');
        if (since !== undefined) {
            request['startTime'] = since;
        }
        if (endTime !== undefined) {
            request['endTime'] = endTime;
            params = this.omit(params, ['endTime', 'until']);
        }
        if (limit !== undefined) {
            request['limit'] = limit;
        }
        const response = await this.privateGetOpenV1OrdersTrades(this.extend(request, params));
        //
        //     {
        //         "code": 0,
        //         "msg": "success",
        //         "data": {
        //             "list": [
        //                 {
        //                     "tradeId": "3",
        //                     "orderId": "2",
        //                     "symbol": "ADA_USDT",
        //                     "price": "0.04398",
        //                     "qty": "250",
        //                     "quoteQty": "10.995",
        //                     "commission": "0.25",
        //                     "commissionAsset": "ADA",
        //                     "isBuyer": 1,
        //                     "isMaker": 0,
        //                     "isBestMatch": 1,
        //                     "time": "1572920872276"
        //                 }
        //             ]
        //         },
        //         "timestamp": 1573723498893
        //     }
        //
        const data = this.safeValue(response, 'data', {});
        const trades = this.safeList(data, 'list', []);
        return this.parseTrades(trades, market, since, limit);
    }
    /**
     * @method
     * @name tokocrypto#fetchDepositAddress
     * @description fetch the deposit address for a currency associated with this account
     * @see https://www.tokocrypto.com/apidocs/#deposit-address-signed
     * @param {string} code unified currency code
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @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 = {
            'asset': currency['id'],
            // 'network': 'ETH', // 'BSC', 'XMR', you can get network and isDefault in networkList in the response of sapiGetCapitalConfigDetail
        };
        const networks = this.safeValue(this.options, 'networks', {});
        let network = this.safeStringUpper(params, 'network'); // this line allows the user to specify either ERC20 or ETH
        network = this.safeString(networks, network, network); // handle ERC20>ETH alias
        if (network !== undefined) {
            request['network'] = network;
            params = this.omit(params, 'network');
        }
        // has support for the 'network' parameter
        // https://binance-docs.github.io/apidocs/spot/en/#deposit-address-supporting-network-user_data
        const response = await this.privateGetOpenV1DepositsAddress(this.extend(request, params));
        //
        //     {
        //         "code":0,
        //         "msg":"Success",
        //         "data":{
        //             "uid":"182395",
        //             "asset":"USDT",
        //             "network":"ETH",
        //             "address":"0x101a925704f6ff13295ab8dd7a60988d116aaedf",
        //             "addressTag":"",
        //             "status":1
        //         },
        //         "timestamp":1660685915746
        //     }
        //
        const data = this.safeValue(response, 'data', {});
        const address = this.safeString(data, 'address');
        let tag = this.safeString(data, 'addressTag', '');
        if (tag.length === 0) {
            tag = undefined;
        }
        this.checkAddress(address);
        return {
            'info': response,
            'currency': code,
            'network': this.safeString(data, 'network'),
            'address': address,
            'tag': tag,
        };
    }
    /**
     * @method
     * @name tokocrypto#fetchDeposits
     * @see https://www.tokocrypto.com/apidocs/#deposit-history-signed
     * @description fetch all deposits made to an account
     * @param {string} code unified currency code
     * @param {int} [since] the earliest time in ms to fetch deposits for
     * @param {int} [limit] the maximum number of deposits structures to retrieve
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @param {int} [params.until] the latest time in ms to fetch deposits for
     * @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 currency = undefined;
        const request = {};
        const until = this.safeInteger(params, 'until');
        if (code !== undefined) {
            currency = this.currency(code);
            request['coin'] = currency['id'];
        }
        if (since !== undefined) {
            request['startTime'] = since;
            // max 3 months range https://github.com/ccxt/ccxt/issues/6495
            let endTime = this.sum(since, 7776000000);
            if (until !== undefined) {
                endTime = Math.min(endTime, until);
            }
            request['endTime'] = endTime;
        }
        if (limit !== undefined) {
            request['limit'] = limit;
        }
        const response = await this.privateGetOpenV1Deposits(this.extend(request, params));
        //
        //     {
        //         "code":0,
        //         "msg":"Success",
        //         "data":{
        //             "list":[
        //                 {
        //                     "id":5167969,
        //                     "asset":"BIDR",
        //                     "network":"BSC",
        //                     "address":"0x101a925704f6ff13295ab8dd7a60988d116aaedf",
        //                     "addressTag":"",
        //                     "txId":"113409337867",
        //                     "amount":"15000",
        //                     "transferType":1,
        //                     "status":1,
        //                     "insertTime":"1659429390000"
        //                 },
        //             ]
        //         },
        //         "timestamp":1659758865998
        //     }
        //
        const data = this.safeValue(response, 'data', {});
        const deposits = this.safeList(data, 'list', []);
        return this.parseTransactions(deposits, currency, since, limit);
    }
    /**
     * @method
     * @name tokocrypto#fetchWithdrawals
     * @see https://www.tokocrypto.com/apidocs/#withdraw-signed
     * @description fetch all withdrawals made from an account
     * @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
     * @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();
        const request = {};
        let currency = undefined;
        if (code !== undefined) {
            currency = this.currency(code);
            request['coin'] = currency['id'];
        }
        if (since !== undefined) {
            request['startTime'] = since;
            // max 3 months range https://github.com/ccxt/ccxt/issues/6495
            request['endTime'] = this.sum(since, 7776000000);
        }
        if (limit !== undefined) {
            request['limit'] = limit;
        }
        const response = await this.privateGetOpenV1Withdraws(this.extend(request, params));
        //
        //     {
        //         "code":0,
        //         "msg":"Success",
        //         "data":{
        //             "list":[
        //                 {
        //                     "id":4245859,
        //                     "clientId":"198",
        //                     "asset":"BIDR",
        //                     "network":"BSC",
        //                     "address":"0xff1c75149cc492e7d5566145b859fcafc900b6e9",
        //                     "addressTag":"",
        //                     "amount":"10000",
        //                     "fee":"0",
        //                     "txId":"113501794501",
        //                     "transferType":1,
        //                     "status":10,
        //                     "createTime":1659521314413
        //                 }
        //             ]
        //         },
        //         "timestamp":1659759062187
        //     }
        //
        const data = this.safeValue(response, 'data', {});
        const withdrawals = this.safeList(data, 'list', []);
        return this.parseTransactions(withdrawals, currency, since, limit);
    }
    parseTransactionStatusByType(status, type = undefined) {
        const statusesByType = {
            'deposit': {
                '0': 'pending',
                '1': 'ok',
            },
            'withdrawal': {
                '0': 'pending',
                '1': 'canceled',
                '2': 'pending',
                '3': 'failed',
                '4': 'pending',
                '5': 'failed',
                '10': 'ok', // Completed
            },
        };
        const statuses = this.safeValue(statusesByType, type, {});
        return this.safeString(statuses, status, status);
    }
    parseTransaction(transaction, currency = undefined) {
        //
        // fetchDeposits
        //
        //     {
        //         "id": 5167969,
        //         "asset": "BIDR",
        //         "network": "BSC",
        //         "address": "0x101a925704f6ff13295ab8dd7a60988d116aaedf",
        //         "addressTag": "",
        //         "txId": "113409337867",
        //         "amount": "15000",
        //         "transferType": 1,
        //         "status": 1,
        //         "insertTime": "1659429390000"
        //     }
        //
        // fetchWithdrawals
        //
        //     {
        //         "id": 4245859,
        //         "clientId": "198",
        //         "asset": "BIDR",
        //         "network": "BSC",
        //         "address": "0xff1c75149cc492e7d5566145b859fcafc900b6e9",
        //         "addressTag": "",
        //         "amount": "10000",
        //         "fee": "0",
        //         "txId": "113501794501",
        //         "transferType": 1,
        //         "status": 10,
        //         "createTime": 1659521314413
        //     }
        //
        // withdraw
        //
        //     {
        //         "code": 0,
        //         "msg": "成功",
        //         "data": {
        //             "withdrawId":"12"
        //         },
        //         "timestamp": 1571745049095
        //     }
        //
        const address = this.safeString(transaction, 'address');
        let tag = this.safeString(transaction, 'addressTag'); // set but unused
        if (tag !== undefined) {
            if (tag.length < 1) {
                tag = undefined;
            }
        }
        let txid = this.safeString(transaction, 'txId');
        if ((txid !== undefined) && (txid.indexOf('Internal transfer ') >= 0)) {
            txid = txid.slice(18);
        }
        const currencyId = this.safeString2(transaction, 'coin', 'fiatCurrency');
        const code = this.safeCurrencyCode(currencyId, currency);
        let timestamp = undefined;
        const insertTime = this.safeInteger(transaction, 'insertTime');
        const createTime = this.safeInteger2(transaction, 'createTime', 'timestamp');
        let type = this.safeString(transaction, 'type');
        if (type === undefined) {
            if ((insertTime !== undefined) && (createTime === undefined)) {
                type = 'deposit';
                timestamp = insertTime;
            }
            else if ((insertTime === undefined) && (createTime !== undefined)) {
                type = 'withdrawal';
                timestamp = createTime;
            }
        }
        const feeCost = this.safeNumber2(transaction, 'transactionFee', 'totalFee');
        const fee = {
            'currency': undefined,
            'cost': undefined,
            'rate': undefined,
        };
        if (feeCost !== undefined) {
            fee['currency'] = code;
            fee['cost'] = feeCost;
        }
        const internalRaw = this.safeInteger(transaction, 'transferType');
        let internal = false;
        if (internalRaw !== undefined) {
            internal = true;
        }
        let id = this.safeString(transaction, 'id');
        if (id === undefined) {
            const data = this.safeValue(transaction, 'data', {});
            id = this.safeString(data, 'withdrawId');
            type = 'withdrawal';
        }
        return {
            'info': transaction,
            'id': id,
            'txid': txid,
            'type': type,
            'currency': code,
            'network': this.safeString(transaction, 'network'),
            'amount': this.safeNumber(transaction, 'amount'),
            'status': this.parseTransactionStatusByType(this.safeString(transaction, 'status'), type),
            'timestamp': timestamp,
            'datetime': this.iso8601(timestamp),
            'address': address,
            'addressFrom': undefined,
            'addressTo': address,
            'tag': tag,
            'tagFrom': undefined,
            'tagTo': tag,
            'updated': this.safeInteger2(transaction, 'successTime', 'updateTime'),
            'comment': undefined,
            'internal': internal,
            'fee': fee,
        };
    }
    /**
     * @method
     * @name tokocrypto#withdraw
     * @see https://www.tokocrypto.com/apidocs/#withdraw-signed
     * @description make a withdrawal
     * @param {string} code unified currency code
     * @param {float} amount the amount to withdraw
     * @param {string} address the address to withdraw to
     * @param {string} tag
     * @param {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 = {
            'asset': currency['id'],
            // 'clientId': 'string', // // client's custom id for withdraw order, server does not check it's uniqueness, automatically generated if not sent
            // 'network': 'string',
            'address': address,
            // 'addressTag': 'string', // for coins like XRP, XMR, etc
            'amount': this.numberToString(amount),
        };
        if (tag !== undefined) {
            request['addressTag'] = tag;
        }
        const [networkCode, query] = this.handleNetworkCodeAndParams(params);
        const networkId = this.networkCodeToId(networkCode);
        if (networkId !== undefined) {
            request['network'] = networkId.toUpperCase();
        }
        const response = await this.privatePostOpenV1Withdraws(this.extend(request, query));
        //
        //     {
        //         "code": 0,
        //         "msg": "成功",
        //         "data": {
        //             "withdrawId":"12"
        //         },
        //         "timestamp": 1571745049095
        //     }
        //
        return this.parseTransaction(response, currency);
    }
    sign(path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
        if (!(api in this.urls['api']['rest'])) {
            throw new errors.NotSupported(this.id + ' does not have a testnet/sandbox URL for ' + api + ' endpoints');
        }
        let url = this.urls['api']['rest'][api];
        url += '/' + path;
        if (api === 'wapi') {
            url += '.html';
        }
        const userDataStream = (path === 'userDataStream') || (path === 'listenKey');
        if (userDataStream) {
            if (this.apiKey) {
                // v1 special case for userDataStream
                headers = {
                    'X-MBX-APIKEY': this.apiKey,
                    'Content-Type': 'application/x-www-form-urlencoded',
                };
                if (method !== 'GET') {
                    body = this.urlencode(params);
                }
            }
            else {
                throw new errors.AuthenticationError(this.id + ' userDataStream endpoint requires `apiKey` credential');
            }
        }
        else if ((api === 'private') || (api === 'sapi' && path !== 'system/status') || (api === 'sapiV3') || (api === 'wapi' && path !== 'systemStatus') || (api === 'dapiPrivate') || (api === 'dapiPrivateV2') || (api === 'fapiPrivate') || (api === 'fapiPrivateV2')) {
            this.checkRequiredCredentials();
            let query = undefined;
            const defaultRecvWindow = this.safeInteger(this.options, 'recvWindow');
            const extendedParams = this.extend({
                'timestamp': this.nonce(),
            }, params);
            if (defaultRecvWindow !== undefined) {
                extendedParams['recvWindow'] = defaultRecvWindow;
            }
            const recvWindow = this.safeInteger(params, 'recvWindow');
            if (recvWindow !== undefined) {
                extendedParams['recvWindow'] = recvWindow;
            }
            if ((api === 'sapi') && (path === 'asset/dust')) {
                query = this.urlencodeWithArrayRepeat(extendedParams);
            }
            else if ((path === 'batchOrders') || (path.indexOf('sub-account') >= 0) || (path === 'capital/withdraw/apply') || (path.indexOf('staking') >= 0)) {
                query = this.rawencode(extendedParams);
            }
            else {
                query = this.urlencode(extendedParams);
            }
            const signature = this.hmac(this.encode(query), this.encode(this.secret), sha256.sha256);
            query += '&' + 'signature=' + signature;
            headers = {
                'X-MBX-APIKEY': this.apiKey,
            };
            if ((method === 'GET') || (method === 'DELETE') || (api === 'wapi')) {
                url += '?' + query;
            }
            else {
                body = query;
                headers['Content-Type'] = 'application/x-www-form-urlencoded';
            }
        }
        else {
            if (Object.keys(params).length) {
                url += '?' + this.urlencode(params);
            }
        }
        return { 'url': url, 'method': method, 'body': body, 'headers': headers };
    }
    handleErrors(code, reason, url, method, headers, body, response, requestHeaders, requestBody) {
        if ((code === 418) || (code === 429)) {
            throw new errors.DDoSProtection(this.id + ' ' + code.toString() + ' ' + reason + ' ' + body);
        }
        // error response in a form: { "code": -1013, "msg": "Invalid quantity." }
        // following block cointains legacy checks against message patterns in "msg" property
        // will switch "code" checks eventually, when we know all of them
        if (code >= 400) {
            if (body.indexOf('Price * QTY is zero or less') >= 0) {
                throw new errors.InvalidOrder(this.id + ' order cost = amount * price is zero or less ' + body);
            }
            if (body.indexOf('LOT_SIZE') >= 0) {
                throw new errors.InvalidOrder(this.id + ' order amount should be evenly divisible by lot size ' + body);
            }
            if (body.indexOf('PRICE_FILTER') >= 0) {
                throw new errors.InvalidOrder(this.id + ' order price is invalid, i.e. exceeds allowed price precision, exceeds min price or max price limits or is invalid value in general, use this.priceToPrecision (symbol, amount) ' + body);
            }
        }
        if (response === undefined) {
            return undefined; // fallback to default error handler
        }
        // check success value for wapi endpoints
        // response in format {'msg': 'The coin does not exist.', 'success': true/false}
        const success = this.safeBool(response, 'success', true);
        if (!success) {
            const messageInner = this.safeString(response, 'msg');
            let parsedMessage = undefined;
            if (messageInner !== undefined) {
                try {
                    parsedMessage = JSON.parse(messageInner);
                }
                catch (e) {
                    // do nothing
                    parsedMessage = undefined;
                }
                if (parsedMessage !== undefined) {
                    response = parsedMessage;
                }
            }
        }
        const message = this.safeString(response, 'msg');
        if (message !== undefined) {
            this.throwExactlyMatchedException(this.exceptions['exact'], message, this.id + ' ' + message);
            this.throwBroadlyMatchedException(this.exceptions['broad'], message, this.id + ' ' + message);
        }
        // checks against error codes
        const error = this.safeString(response, 'code');
        if (error !== undefined) {
            // https://github.com/ccxt/ccxt/issues/6501
            // https://github.com/ccxt/ccxt/issues/7742
            if ((error === '200') || Precise["default"].stringEquals(error, '0')) {
                return undefined;
            }
            // a workaround for {"code":-2015,"msg":"Invalid API-key, IP, or permissions for action."}
            // despite that their message is very confusing, it is raised by Binance
            // on a temporary ban, the API key is valid, but disabled for a while
            if ((error === '-2015') && this.options['hasAlreadyAuthenticatedSuccessfully']) {
                throw new errors.DDoSProtection(this.id + ' ' + body);
            }
            const feedback = this.id + ' ' + body;
            if (message === 'No need to change margin type.') {
                // not an error
                // https://github.com/ccxt/ccxt/issues/11268
                // https://github.com/ccxt/ccxt/pull/11624
                // POST https://fapi.binance.com/fapi/v1/marginType 400 Bad Request
                // binanceusdm {"code":-4046,"msg":"No need to change margin type."}
                throw new errors.MarginModeAlreadySet(feedback);
            }
            this.throwExactlyMatchedException(this.exceptions['exact'], error, feedback);
            throw new errors.ExchangeError(feedback);
        }
        if (!success) {
            throw new errors.ExchangeError(this.id + ' ' + body);
        }
        return undefined;
    }
    calculateRateLimiterCost(api, method, path, params, config = {}) {
        if (('noCoin' in config) && !('coin' in params)) {
            return config['noCoin'];
        }
        else if (('noSymbol' in config) && !('symbol' in params)) {
            return config['noSymbol'];
        }
        else if (('noPoolId' in config) && !('poolId' in params)) {
            return config['noPoolId'];
        }
        else if (('byLimit' in config) && ('limit' in params)) {
            const limit = params['limit'];
            const byLimit = config['byLimit'];
            for (let i = 0; i < byLimit.length; i++) {
                const entry = byLimit[i];
                if (limit <= entry[0]) {
                    return entry[1];
                }
            }
        }
        return this.safeInteger(config, 'cost', 1);
    }
}

module.exports = tokocrypto;