UNPKG

consequunturatque

Version:

A JavaScript / Python / PHP cryptocurrency trading library with support for 130+ exchanges

1,006 lines (995 loc) 150 kB
'use strict'; // --------------------------------------------------------------------------- const Exchange = require ('./base/Exchange'); const { ExchangeError, ArgumentsRequired, ExchangeNotAvailable, InsufficientFunds, OrderNotFound, InvalidOrder, DDoSProtection, InvalidNonce, AuthenticationError, RateLimitExceeded, PermissionDenied, NotSupported, BadRequest, BadSymbol, AccountSuspended, OrderImmediatelyFillable } = require ('./base/errors'); const { TRUNCATE } = require ('./base/functions/number'); const Precise = require ('./base/Precise'); // --------------------------------------------------------------------------- module.exports = class binance extends Exchange { describe () { return this.deepExtend (super.describe (), { 'id': 'binance', 'name': 'Binance', 'countries': [ 'JP', 'MT' ], // Japan, Malta 'rateLimit': 500, 'certified': true, 'pro': true, // new metainfo interface 'has': { 'cancelAllOrders': true, 'cancelOrder': true, 'CORS': false, 'createOrder': true, 'fetchCurrencies': true, 'fetchBalance': true, 'fetchBidsAsks': true, 'fetchClosedOrders': 'emulated', 'fetchDepositAddress': true, 'fetchDeposits': true, 'fetchFundingFees': true, 'fetchMarkets': true, 'fetchMyTrades': true, 'fetchOHLCV': true, 'fetchOpenOrders': true, 'fetchOrder': true, 'fetchOrders': true, 'fetchOrderBook': true, 'fetchStatus': true, 'fetchTicker': true, 'fetchTickers': true, 'fetchTime': true, 'fetchTrades': true, 'fetchTradingFee': true, 'fetchTradingFees': true, 'fetchTransactions': false, 'fetchWithdrawals': true, 'withdraw': true, 'transfer': true, 'fetchTransfers': 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/29604020-d5483cdc-87ee-11e7-94c7-d1a8d9169293.jpg', 'test': { 'dapiPublic': 'https://testnet.binancefuture.com/dapi/v1', 'dapiPrivate': 'https://testnet.binancefuture.com/dapi/v1', 'fapiPublic': 'https://testnet.binancefuture.com/fapi/v1', 'fapiPrivate': 'https://testnet.binancefuture.com/fapi/v1', 'fapiPrivateV2': 'https://testnet.binancefuture.com/fapi/v2', 'public': 'https://testnet.binance.vision/api/v3', 'private': 'https://testnet.binance.vision/api/v3', 'v3': 'https://testnet.binance.vision/api/v3', 'v1': 'https://testnet.binance.vision/api/v1', }, 'api': { 'wapi': 'https://api.binance.com/wapi/v3', 'sapi': 'https://api.binance.com/sapi/v1', 'dapiPublic': 'https://dapi.binance.com/dapi/v1', 'dapiPrivate': 'https://dapi.binance.com/dapi/v1', 'dapiData': 'https://dapi.binance.com/futures/data', 'fapiPublic': 'https://fapi.binance.com/fapi/v1', 'fapiPrivate': 'https://fapi.binance.com/fapi/v1', 'fapiData': 'https://fapi.binance.com/futures/data', 'fapiPrivateV2': 'https://fapi.binance.com/fapi/v2', 'public': 'https://api.binance.com/api/v3', 'private': 'https://api.binance.com/api/v3', 'v3': 'https://api.binance.com/api/v3', 'v1': 'https://api.binance.com/api/v1', }, 'www': 'https://www.binance.com', 'referral': 'https://www.binance.com/?ref=10205187', 'doc': [ 'https://binance-docs.github.io/apidocs/spot/en', ], 'api_management': 'https://www.binance.com/en/usercenter/settings/api-management', 'fees': 'https://www.binance.com/en/fee/schedule', }, 'api': { // the API structure below will need 3-layer apidefs 'sapi': { 'get': [ 'accountSnapshot', // these endpoints require this.apiKey 'margin/asset', 'margin/pair', 'margin/allAssets', 'margin/allPairs', 'margin/priceIndex', // these endpoints require this.apiKey + this.secret 'asset/assetDividend', 'asset/transfer', 'asset/assetDetail', 'asset/tradeFee', 'margin/loan', 'margin/repay', 'margin/account', 'margin/transfer', 'margin/interestHistory', 'margin/forceLiquidationRec', 'margin/order', 'margin/openOrders', 'margin/allOrders', 'margin/myTrades', 'margin/maxBorrowable', 'margin/maxTransferable', 'margin/isolated/transfer', 'margin/isolated/account', 'margin/isolated/pair', 'margin/isolated/allPairs', 'fiatpayment/query/deposit/history', 'fiatpayment/query/withdraw/history', 'futures/transfer', 'futures/loan/borrow/history', 'futures/loan/repay/history', 'futures/loan/wallet', 'futures/loan/configs', 'futures/loan/calcAdjustLevel', 'futures/loan/calcMaxAdjustAmount', 'futures/loan/adjustCollateral/history', 'futures/loan/liquidationHistory', // https://binance-docs.github.io/apidocs/spot/en/#withdraw-sapi 'capital/config/getall', // get networks for withdrawing USDT ERC20 vs USDT Omni 'capital/deposit/address', 'capital/deposit/hisrec', 'capital/deposit/subAddress', 'capital/deposit/subHisrec', 'capital/withdraw/history', 'sub-account/futures/account', 'sub-account/futures/accountSummary', 'sub-account/futures/positionRisk', 'sub-account/futures/internalTransfer', 'sub-account/margin/account', 'sub-account/margin/accountSummary', 'sub-account/spotSummary', 'sub-account/status', 'sub-account/transfer/subUserHistory', 'sub-account/universalTransfer', // lending endpoints 'lending/daily/product/list', 'lending/daily/userLeftQuota', 'lending/daily/userRedemptionQuota', 'lending/daily/token/position', 'lending/union/account', 'lending/union/purchaseRecord', 'lending/union/redemptionRecord', 'lending/union/interestHistory', 'lending/project/list', 'lending/project/position/list', // mining endpoints 'mining/pub/algoList', 'mining/pub/coinList', 'mining/worker/detail', 'mining/worker/list', 'mining/payment/list', 'mining/statistics/user/status', 'mining/statistics/user/list', // liquid swap endpoints 'bswap/pools', 'bswap/liquidity', 'bswap/liquidityOps', 'bswap/quote', 'bswap/swap', // leveraged token endpoints 'blvt/tokenInfo', 'blvt/subscribe/record', 'blvt/redeem/record', 'blvt/userLimit', // broker api 'apiReferral/ifNewUser', 'apiReferral/customization', 'apiReferral/userCustomization', 'apiReferral/rebate/recentRecord', 'apiReferral/rebate/historicalRecord', 'apiReferral/kickback/recentRecord', 'apiReferral/kickback/historicalRecord', // brokerage API 'broker/subAccountApi', 'broker/subAccount', 'broker/subAccountApi/commission/futures', 'broker/subAccountApi/commission/coinFutures', 'broker/info', 'broker/transfer', 'broker/transfer/futures', 'broker/rebate/recentRecord', 'broker/rebate/historicalRecord', 'broker/subAccount/bnbBurn/status', 'broker/subAccount/depositHist', 'broker/subAccount/spotSummary', 'broker/subAccount/marginSummary', 'broker/subAccount/futuresSummary', 'broker/rebate/futures/recentRecord', 'broker/subAccountApi/ipRestriction', 'broker/universalTransfer', // v2 not supported yet // GET /sapi/v2/broker/subAccount/futuresSummary ], 'post': [ 'asset/dust', 'asset/transfer', 'account/disableFastWithdrawSwitch', 'account/enableFastWithdrawSwitch', 'capital/withdraw/apply', 'margin/transfer', 'margin/loan', 'margin/repay', 'margin/order', 'margin/isolated/create', 'margin/isolated/transfer', 'sub-account/margin/transfer', 'sub-account/margin/enable', 'sub-account/margin/enable', 'sub-account/futures/enable', 'sub-account/futures/transfer', 'sub-account/futures/internalTransfer', 'sub-account/transfer/subToSub', 'sub-account/transfer/subToMaster', 'sub-account/universalTransfer', 'userDataStream', 'userDataStream/isolated', 'futures/transfer', 'futures/loan/borrow', 'futures/loan/repay', 'futures/loan/adjustCollateral', // lending 'lending/customizedFixed/purchase', 'lending/daily/purchase', 'lending/daily/redeem', // liquid swap endpoints 'bswap/liquidityAdd', 'bswap/liquidityRemove', 'bswap/swap', // leveraged token endpoints 'blvt/subscribe', 'blvt/redeem', // brokerage API 'apiReferral/customization', 'apiReferral/userCustomization', 'apiReferral/rebate/historicalRecord', 'apiReferral/kickback/historicalRecord', 'broker/subAccount', 'broker/subAccount/margin', 'broker/subAccount/futures', 'broker/subAccountApi', 'broker/subAccountApi/permission', 'broker/subAccountApi/commission', 'broker/subAccountApi/commission/futures', 'broker/subAccountApi/commission/coinFutures', 'broker/transfer', 'broker/transfer/futures', 'broker/rebate/historicalRecord', 'broker/subAccount/bnbBurn/spot', 'broker/subAccount/bnbBurn/marginInterest', 'broker/subAccount/blvt', 'broker/subAccountApi/ipRestriction', 'broker/subAccountApi/ipRestriction/ipList', 'broker/universalTransfer', 'broker/subAccountApi/permission/universalTransfer', 'broker/subAccountApi/permission/vanillaOptions', ], 'put': [ 'userDataStream', 'userDataStream/isolated', ], 'delete': [ 'margin/openOrders', 'margin/order', 'userDataStream', 'userDataStream/isolated', // brokerage API 'broker/subAccountApi', 'broker/subAccountApi/ipRestriction/ipList', ], }, // deprecated 'wapi': { 'post': [ 'withdraw', 'sub-account/transfer', ], 'get': [ 'depositHistory', 'withdrawHistory', 'depositAddress', 'accountStatus', 'systemStatus', 'apiTradingStatus', 'userAssetDribbletLog', 'tradeFee', 'assetDetail', 'sub-account/list', 'sub-account/transfer/history', 'sub-account/assets', ], }, 'dapiPublic': { 'get': [ 'ping', 'time', 'exchangeInfo', 'depth', 'trades', 'historicalTrades', 'aggTrades', 'premiumIndex', 'fundingRate', 'klines', 'continuousKlines', 'indexPriceKlines', 'markPriceKlines', 'ticker/24hr', 'ticker/price', 'ticker/bookTicker', 'allForceOrders', 'openInterest', ], }, 'dapiData': { 'get': [ 'openInterestHist', 'topLongShortAccountRatio', 'topLongShortPositionRatio', 'globalLongShortAccountRatio', 'takerBuySellVol', 'basis', ], }, 'dapiPrivate': { 'get': [ 'positionSide/dual', 'order', 'openOrder', 'openOrders', 'allOrders', 'balance', 'account', 'positionMargin/history', 'positionRisk', 'userTrades', 'income', 'leverageBracket', 'forceOrders', 'adlQuantile', ], 'post': [ 'positionSide/dual', 'order', 'batchOrders', 'countdownCancelAll', 'leverage', 'marginType', 'positionMargin', 'listenKey', ], 'put': [ 'listenKey', ], 'delete': [ 'order', 'allOpenOrders', 'batchOrders', 'listenKey', ], }, 'fapiPublic': { 'get': [ 'ping', 'time', 'exchangeInfo', 'depth', 'trades', 'historicalTrades', 'aggTrades', 'klines', 'continuousKlines', 'fundingRate', 'premiumIndex', 'ticker/24hr', 'ticker/price', 'ticker/bookTicker', 'allForceOrders', 'openInterest', 'indexInfo', ], }, 'fapiData': { 'get': [ 'openInterestHist', 'topLongShortAccountRatio', 'topLongShortPositionRatio', 'globalLongShortAccountRatio', 'takerlongshortRatio', ], }, 'fapiPrivate': { 'get': [ 'allForceOrders', 'allOrders', 'openOrder', 'openOrders', 'order', 'account', 'balance', 'leverageBracket', 'positionMargin/history', 'positionRisk', 'positionSide/dual', 'userTrades', 'income', 'commissionRate', 'apiTradingStatus', // broker endpoints 'apiReferral/ifNewUser', 'apiReferral/customization', 'apiReferral/userCustomization', 'apiReferral/traderNum', 'apiReferral/overview', 'apiReferral/tradeVol', 'apiReferral/rebateVol', 'apiReferral/traderSummary', ], 'post': [ 'batchOrders', 'positionSide/dual', 'positionMargin', 'marginType', 'order', 'leverage', 'listenKey', 'countdownCancelAll', // broker endpoints 'apiReferral/customization', 'apiReferral/userCustomization', ], 'put': [ 'listenKey', ], 'delete': [ 'batchOrders', 'order', 'allOpenOrders', 'listenKey', ], }, 'fapiPrivateV2': { 'get': [ 'account', 'balance', 'positionRisk', ], }, 'v3': { 'get': [ 'ticker/price', 'ticker/bookTicker', ], }, 'public': { 'get': [ 'ping', 'time', 'depth', 'trades', 'aggTrades', 'historicalTrades', 'klines', 'ticker/24hr', 'ticker/price', 'ticker/bookTicker', 'exchangeInfo', ], 'put': [ 'userDataStream' ], 'post': [ 'userDataStream' ], 'delete': [ 'userDataStream' ], }, 'private': { 'get': [ 'allOrderList', // oco 'openOrderList', // oco 'orderList', // oco 'order', 'openOrders', 'allOrders', 'account', 'myTrades', ], 'post': [ 'order/oco', 'order', 'order/test', ], 'delete': [ 'openOrders', // added on 2020-04-25 for canceling all open orders per symbol 'orderList', // oco 'order', ], }, }, 'fees': { 'trading': { 'feeSide': 'get', 'tierBased': false, 'percentage': true, 'taker': 0.001, 'maker': 0.001, }, }, 'commonCurrencies': { 'BCC': 'BCC', // kept for backward-compatibility https://github.com/ccxt/ccxt/issues/4848 'YOYO': 'YOYOW', }, // exchange-specific options 'options': { 'fetchCurrencies': false, // this is a private call and it requires API keys // 'fetchTradesMethod': 'publicGetAggTrades', // publicGetTrades, publicGetHistoricalTrades 'defaultTimeInForce': 'GTC', // 'GTC' = Good To Cancel (default), 'IOC' = Immediate Or Cancel 'defaultType': 'spot', // 'spot', 'future', 'margin', 'delivery' 'hasAlreadyAuthenticatedSuccessfully': false, 'warnOnFetchOpenOrdersWithoutSymbol': true, 'recvWindow': 5 * 1000, // 5 sec, binance default 'timeDifference': 0, // the difference between system clock and Binance clock 'adjustForTimeDifference': false, // controls the adjustment logic upon instantiation 'parseOrderToPrecision': false, // force amounts and costs in parseOrder to precision 'newOrderRespType': { 'market': 'FULL', // 'ACK' for order id, 'RESULT' for full order or 'FULL' for order with fills 'limit': 'FULL', // we change it from 'ACK' by default to 'FULL' (returns immediately if limit is not hit) }, 'quoteOrderQty': true, // whether market orders support amounts in quote currency 'broker': { 'spot': 'x-R4BD3S82', 'margin': 'x-R4BD3S82', 'future': 'x-xcKtGhcu', 'delivery': 'x-xcKtGhcu', }, 'fetchPositions': { 'future': 'fapiPrivateV2GetAccount', // 'fapiPrivateGetPositionRisk' 'delivery': 'dapiPrivateGetAccount', // 'dapiPrivateGetPositionRisk' }, 'accountsByType': { 'main': 'MAIN', 'spot': 'MAIN', 'margin': 'MARGIN', 'future': 'UMFUTURE', 'delivery': 'CMFUTURE', 'mining': 'MINING', }, 'typesByAccount': { 'MAIN': 'spot', 'MARGIN': 'margin', 'UMFUTURE': 'future', 'CMFUTURE': 'delivery', 'MINING': 'mining', }, }, // https://binance-docs.github.io/apidocs/spot/en/#error-codes-2 'exceptions': { 'System abnormality': ExchangeError, // {"code":-1000,"msg":"System abnormality"} 'You are not authorized to execute this request.': PermissionDenied, // {"msg":"You are not authorized to execute this request."} 'API key does not exist': AuthenticationError, 'Order would trigger immediately.': OrderImmediatelyFillable, 'Stop price would trigger immediately.': OrderImmediatelyFillable, // {"code":-2010,"msg":"Stop price would trigger immediately."} 'Order would immediately match and take.': OrderImmediatelyFillable, // {"code":-2010,"msg":"Order would immediately match and take."} 'Account has insufficient balance for requested action.': InsufficientFunds, 'Rest API trading is not enabled.': ExchangeNotAvailable, "You don't have permission.": PermissionDenied, // {"msg":"You don't have permission.","success":false} 'Market is closed.': ExchangeNotAvailable, // {"code":-1013,"msg":"Market is closed."} 'Too many requests.': DDoSProtection, // {"msg":"Too many requests. Please try again later.","success":false} '-1000': ExchangeNotAvailable, // {"code":-1000,"msg":"An unknown error occured while processing the request."} '-1001': ExchangeNotAvailable, // 'Internal error; unable to process your request. Please try again.' '-1002': AuthenticationError, // 'You are not authorized to execute this request.' '-1003': RateLimitExceeded, // {"code":-1003,"msg":"Too much request weight used, current limit is 1200 request weight per 1 MINUTE. Please use the websocket for live updates to avoid polling the API."} '-1013': InvalidOrder, // createOrder -> 'invalid quantity'/'invalid price'/MIN_NOTIONAL '-1015': RateLimitExceeded, // 'Too many new orders; current limit is %s orders per %s.' '-1016': ExchangeNotAvailable, // 'This service is no longer available.', '-1020': BadRequest, // 'This operation is not supported.' '-1021': InvalidNonce, // 'your time is ahead of server' '-1022': AuthenticationError, // {"code":-1022,"msg":"Signature for this request is not valid."} '-1100': BadRequest, // createOrder(symbol, 1, asdf) -> 'Illegal characters found in parameter 'price' '-1101': BadRequest, // Too many parameters; expected %s and received %s. '-1102': BadRequest, // Param %s or %s must be sent, but both were empty '-1103': BadRequest, // An unknown parameter was sent. '-1104': BadRequest, // Not all sent parameters were read, read 8 parameters but was sent 9 '-1105': BadRequest, // Parameter %s was empty. '-1106': BadRequest, // Parameter %s sent when not required. '-1111': BadRequest, // Precision is over the maximum defined for this asset. '-1112': InvalidOrder, // No orders on book for symbol. '-1114': BadRequest, // TimeInForce parameter sent when not required. '-1115': BadRequest, // Invalid timeInForce. '-1116': BadRequest, // Invalid orderType. '-1117': BadRequest, // Invalid side. '-1118': BadRequest, // New client order ID was empty. '-1119': BadRequest, // Original client order ID was empty. '-1120': BadRequest, // Invalid interval. '-1121': BadSymbol, // Invalid symbol. '-1125': AuthenticationError, // This listenKey does not exist. '-1127': BadRequest, // More than %s hours between startTime and endTime. '-1128': BadRequest, // {"code":-1128,"msg":"Combination of optional parameters invalid."} '-1130': BadRequest, // Data sent for paramter %s is not valid. '-1131': BadRequest, // recvWindow must be less than 60000 '-2010': ExchangeError, // generic error code for createOrder -> 'Account has insufficient balance for requested action.', {"code":-2010,"msg":"Rest API trading is not enabled."}, etc... '-2011': OrderNotFound, // cancelOrder(1, 'BTC/USDT') -> 'UNKNOWN_ORDER' '-2013': OrderNotFound, // fetchOrder (1, 'BTC/USDT') -> 'Order does not exist' '-2014': AuthenticationError, // { "code":-2014, "msg": "API-key format invalid." } '-2015': AuthenticationError, // "Invalid API-key, IP, or permissions for action." '-2019': InsufficientFunds, // {"code":-2019,"msg":"Margin is insufficient."} '-3005': InsufficientFunds, // {"code":-3005,"msg":"Transferring out not allowed. Transfer out amount exceeds max amount."} '-3008': InsufficientFunds, // {"code":-3008,"msg":"Borrow not allowed. Your borrow amount has exceed maximum borrow amount."} '-3010': ExchangeError, // {"code":-3010,"msg":"Repay not allowed. Repay amount exceeds borrow amount."} '-3022': AccountSuspended, // You account's trading is banned. '-4028': BadRequest, // {"code":-4028,"msg":"Leverage 100 is not valid"} '-3020': InsufficientFunds, // {"code":-3020,"msg":"Transfer out amount exceeds max amount."} '-3041': InsufficientFunds, // {"code":-3041,"msg":"Balance is not enough"} '-5013': InsufficientFunds, // Asset transfer failed: insufficient balance" }, }); } currencyToPrecision (currency, fee) { return this.numberToString (fee); } nonce () { return this.milliseconds () - this.options['timeDifference']; } async fetchTime (params = {}) { const type = this.safeString2 (this.options, 'fetchTime', 'defaultType', 'spot'); let method = 'publicGetTime'; if (type === 'future') { method = 'fapiPublicGetTime'; } else if (type === 'delivery') { method = 'dapiPublicGetTime'; } const response = await this[method] (params); return this.safeInteger (response, 'serverTime'); } async loadTimeDifference (params = {}) { const serverTime = await this.fetchTime (params); const after = this.milliseconds (); this.options['timeDifference'] = after - serverTime; return this.options['timeDifference']; } async fetchCurrencies (params = {}) { const fetchCurrenciesEnabled = this.safeValue (this.options, 'fetchCurrencies'); if (!fetchCurrenciesEnabled) { return undefined; } // this endpoint requires authentication // while fetchCurrencies is a public API method by design // therefore we check the keys here // and fallback to generating the currencies from the markets if (!this.checkRequiredCredentials (false)) { return undefined; } // sandbox/testnet does not support sapi endpoints const apiBackup = this.safeString (this.urls, 'apiBackup'); if (apiBackup !== undefined) { return undefined; } const response = await this.sapiGetCapitalConfigGetall (params); const result = {}; for (let i = 0; i < response.length; i++) { // // { // coin: 'LINK', // depositAllEnable: true, // withdrawAllEnable: true, // name: 'ChainLink', // free: '0.06168', // locked: '0', // freeze: '0', // withdrawing: '0', // ipoing: '0', // ipoable: '0', // storage: '0', // isLegalMoney: false, // trading: true, // networkList: [ // { // network: 'BNB', // coin: 'LINK', // withdrawIntegerMultiple: '0', // isDefault: false, // depositEnable: true, // withdrawEnable: true, // depositDesc: '', // withdrawDesc: '', // specialTips: 'Both a MEMO and an Address are required to successfully deposit your LINK BEP2 tokens to Binance.', // name: 'BEP2', // resetAddressStatus: false, // addressRegex: '^(bnb1)[0-9a-z]{38}$', // memoRegex: '^[0-9A-Za-z\\-_]{1,120}$', // withdrawFee: '0.002', // withdrawMin: '0.01', // withdrawMax: '9999999', // minConfirm: 1, // unLockConfirm: 0 // }, // { // network: 'BSC', // coin: 'LINK', // withdrawIntegerMultiple: '0.00000001', // isDefault: false, // depositEnable: true, // withdrawEnable: true, // depositDesc: '', // withdrawDesc: '', // specialTips: '', // name: 'BEP20 (BSC)', // resetAddressStatus: false, // addressRegex: '^(0x)[0-9A-Fa-f]{40}$', // memoRegex: '', // withdrawFee: '0.005', // withdrawMin: '0.01', // withdrawMax: '9999999', // minConfirm: 15, // unLockConfirm: 0 // }, // { // network: 'ETH', // coin: 'LINK', // withdrawIntegerMultiple: '0.00000001', // isDefault: true, // depositEnable: true, // withdrawEnable: true, // depositDesc: '', // withdrawDesc: '', // name: 'ERC20', // resetAddressStatus: false, // addressRegex: '^(0x)[0-9A-Fa-f]{40}$', // memoRegex: '', // withdrawFee: '0.34', // withdrawMin: '0.68', // withdrawMax: '0', // minConfirm: 12, // unLockConfirm: 0 // } // ] // } // const entry = response[i]; const id = this.safeString (entry, 'coin'); const name = this.safeString (entry, 'name'); const code = this.safeCurrencyCode (id); const precision = undefined; let isWithdrawEnabled = true; let isDepositEnabled = true; const networkList = this.safeValue (entry, 'networkList', []); const fees = {}; let fee = undefined; for (let j = 0; j < networkList.length; j++) { const networkItem = networkList[j]; const network = this.safeString (networkItem, 'network'); // const name = this.safeString (networkItem, 'name'); const withdrawFee = this.safeNumber (networkItem, 'withdrawFee'); const depositEnable = this.safeValue (networkItem, 'depositEnable'); const withdrawEnable = this.safeValue (networkItem, 'withdrawEnable'); isDepositEnabled = isDepositEnabled || depositEnable; isWithdrawEnabled = isWithdrawEnabled || withdrawEnable; fees[network] = withdrawFee; const isDefault = this.safeValue (networkItem, 'isDefault'); if (isDefault || fee === undefined) { fee = withdrawFee; } } const trading = this.safeValue (entry, 'trading'); const active = (isWithdrawEnabled && isDepositEnabled && trading); result[code] = { 'id': id, 'name': name, 'code': code, 'precision': precision, 'info': entry, 'active': active, 'fee': fee, 'fees': fees, 'limits': this.limits, }; } return result; } async fetchMarkets (params = {}) { const defaultType = this.safeString2 (this.options, 'fetchMarkets', 'defaultType', 'spot'); const type = this.safeString (params, 'type', defaultType); const query = this.omit (params, 'type'); if ((type !== 'spot') && (type !== 'future') && (type !== 'margin') && (type !== 'delivery')) { throw new ExchangeError (this.id + " does not support '" + type + "' type, set exchange.options['defaultType'] to 'spot', 'margin', 'delivery' or 'future'"); // eslint-disable-line quotes } let method = 'publicGetExchangeInfo'; if (type === 'future') { method = 'fapiPublicGetExchangeInfo'; } else if (type === 'delivery') { method = 'dapiPublicGetExchangeInfo'; } const response = await this[method] (query); // // spot / margin // // { // "timezone":"UTC", // "serverTime":1575416692969, // "rateLimits":[ // {"rateLimitType":"REQUEST_WEIGHT","interval":"MINUTE","intervalNum":1,"limit":1200}, // {"rateLimitType":"ORDERS","interval":"SECOND","intervalNum":10,"limit":100}, // {"rateLimitType":"ORDERS","interval":"DAY","intervalNum":1,"limit":200000} // ], // "exchangeFilters":[], // "symbols":[ // { // "symbol":"ETHBTC", // "status":"TRADING", // "baseAsset":"ETH", // "baseAssetPrecision":8, // "quoteAsset":"BTC", // "quotePrecision":8, // "baseCommissionPrecision":8, // "quoteCommissionPrecision":8, // "orderTypes":["LIMIT","LIMIT_MAKER","MARKET","STOP_LOSS_LIMIT","TAKE_PROFIT_LIMIT"], // "icebergAllowed":true, // "ocoAllowed":true, // "quoteOrderQtyMarketAllowed":true, // "isSpotTradingAllowed":true, // "isMarginTradingAllowed":true, // "filters":[ // {"filterType":"PRICE_FILTER","minPrice":"0.00000100","maxPrice":"100000.00000000","tickSize":"0.00000100"}, // {"filterType":"PERCENT_PRICE","multiplierUp":"5","multiplierDown":"0.2","avgPriceMins":5}, // {"filterType":"LOT_SIZE","minQty":"0.00100000","maxQty":"100000.00000000","stepSize":"0.00100000"}, // {"filterType":"MIN_NOTIONAL","minNotional":"0.00010000","applyToMarket":true,"avgPriceMins":5}, // {"filterType":"ICEBERG_PARTS","limit":10}, // {"filterType":"MARKET_LOT_SIZE","minQty":"0.00000000","maxQty":"63100.00000000","stepSize":"0.00000000"}, // {"filterType":"MAX_NUM_ALGO_ORDERS","maxNumAlgoOrders":5} // ] // }, // ], // } // // futures/usdt-margined (fapi) // // { // "timezone":"UTC", // "serverTime":1575417244353, // "rateLimits":[ // {"rateLimitType":"REQUEST_WEIGHT","interval":"MINUTE","intervalNum":1,"limit":1200}, // {"rateLimitType":"ORDERS","interval":"MINUTE","intervalNum":1,"limit":1200} // ], // "exchangeFilters":[], // "symbols":[ // { // "symbol":"BTCUSDT", // "status":"TRADING", // "maintMarginPercent":"2.5000", // "requiredMarginPercent":"5.0000", // "baseAsset":"BTC", // "quoteAsset":"USDT", // "pricePrecision":2, // "quantityPrecision":3, // "baseAssetPrecision":8, // "quotePrecision":8, // "filters":[ // {"minPrice":"0.01","maxPrice":"100000","filterType":"PRICE_FILTER","tickSize":"0.01"}, // {"stepSize":"0.001","filterType":"LOT_SIZE","maxQty":"1000","minQty":"0.001"}, // {"stepSize":"0.001","filterType":"MARKET_LOT_SIZE","maxQty":"1000","minQty":"0.001"}, // {"limit":200,"filterType":"MAX_NUM_ORDERS"}, // {"multiplierDown":"0.8500","multiplierUp":"1.1500","multiplierDecimal":"4","filterType":"PERCENT_PRICE"} // ], // "orderTypes":["LIMIT","MARKET","STOP"], // "timeInForce":["GTC","IOC","FOK","GTX"] // } // ] // } // // delivery/coin-margined (dapi) // // { // "timezone": "UTC", // "serverTime": 1597667052958, // "rateLimits": [ // {"rateLimitType":"REQUEST_WEIGHT","interval":"MINUTE","intervalNum":1,"limit":6000}, // {"rateLimitType":"ORDERS","interval":"MINUTE","intervalNum":1,"limit":6000} // ], // "exchangeFilters": [], // "symbols": [ // { // "symbol": "BTCUSD_200925", // "pair": "BTCUSD", // "contractType": "CURRENT_QUARTER", // "deliveryDate": 1601020800000, // "onboardDate": 1590739200000, // "contractStatus": "TRADING", // "contractSize": 100, // "marginAsset": "BTC", // "maintMarginPercent": "2.5000", // "requiredMarginPercent": "5.0000", // "baseAsset": "BTC", // "quoteAsset": "USD", // "pricePrecision": 1, // "quantityPrecision": 0, // "baseAssetPrecision": 8, // "quotePrecision": 8, // "equalQtyPrecision": 4, // "filters": [ // {"minPrice":"0.1","maxPrice":"100000","filterType":"PRICE_FILTER","tickSize":"0.1"}, // {"stepSize":"1","filterType":"LOT_SIZE","maxQty":"100000","minQty":"1"}, // {"stepSize":"0","filterType":"MARKET_LOT_SIZE","maxQty":"100000","minQty":"1"}, // {"limit":200,"filterType":"MAX_NUM_ORDERS"}, // {"multiplierDown":"0.9500","multiplierUp":"1.0500","multiplierDecimal":"4","filterType":"PERCENT_PRICE"} // ], // "orderTypes": ["LIMIT","MARKET","STOP","STOP_MARKET","TAKE_PROFIT","TAKE_PROFIT_MARKET","TRAILING_STOP_MARKET"], // "timeInForce": ["GTC","IOC","FOK","GTX"] // }, // { // "symbol": "BTCUSD_PERP", // "pair": "BTCUSD", // "contractType": "PERPETUAL", // "deliveryDate": 4133404800000, // "onboardDate": 1596006000000, // "contractStatus": "TRADING", // "contractSize": 100, // "marginAsset": "BTC", // "maintMarginPercent": "2.5000", // "requiredMarginPercent": "5.0000", // "baseAsset": "BTC", // "quoteAsset": "USD", // "pricePrecision": 1, // "quantityPrecision": 0, // "baseAssetPrecision": 8, // "quotePrecision": 8, // "equalQtyPrecision": 4, // "filters": [ // {"minPrice":"0.1","maxPrice":"100000","filterType":"PRICE_FILTER","tickSize":"0.1"}, // {"stepSize":"1","filterType":"LOT_SIZE","maxQty":"100000","minQty":"1"}, // {"stepSize":"1","filterType":"MARKET_LOT_SIZE","maxQty":"100000","minQty":"1"}, // {"limit":200,"filterType":"MAX_NUM_ORDERS"}, // {"multiplierDown":"0.8500","multiplierUp":"1.1500","multiplierDecimal":"4","filterType":"PERCENT_PRICE"} // ], // "orderTypes": ["LIMIT","MARKET","STOP","STOP_MARKET","TAKE_PROFIT","TAKE_PROFIT_MARKET","TRAILING_STOP_MARKET"], // "timeInForce": ["GTC","IOC","FOK","GTX"] // } // ] // } // if (this.options['adjustForTimeDifference']) { await this.loadTimeDifference (); } const markets = this.safeValue (response, 'symbols', []); const result = []; for (let i = 0; i < markets.length; i++) { const market = markets[i]; const spot = (type === 'spot'); const future = (type === 'future'); const delivery = (type === 'delivery'); const id = this.safeString (market, 'symbol'); const lowercaseId = this.safeStringLower (market, 'symbol'); const baseId = this.safeString (market, 'baseAsset'); const quoteId = this.safeString (market, 'quoteAsset'); const base = this.safeCurrencyCode (baseId); const quote = this.safeCurrencyCode (quoteId); const contractType = this.safeString (market, 'contractType'); const idSymbol = (future || delivery) && (contractType !== 'PERPETUAL'); const symbol = idSymbol ? id : (base + '/' + quote); const filters = this.safeValue (market, 'filters', []); const filtersByType = this.indexBy (filters, 'filterType'); const precision = { 'base': this.safeInteger (market, 'baseAssetPrecision'), 'quote': this.safeInteger (market, 'quotePrecision'), 'amount': this.safeInteger (market, 'baseAssetPrecision'), 'price': this.safeInteger (market, 'quotePrecision'), }; const status = this.safeString2 (market, 'status', 'contractStatus'); const active = (status === 'TRADING'); const margin = this.safeValue (market, 'isMarginTradingAllowed', future || delivery); const entry = { 'id': id, 'lowercaseId': lowercaseId,