consequunturatque
Version:
A JavaScript / Python / PHP cryptocurrency trading library with support for 130+ exchanges
1,006 lines (995 loc) • 150 kB
JavaScript
'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,