UNPKG

ccxt-mxc

Version:

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

1,084 lines (1,063 loc) 102 kB
'use strict'; // --------------------------------------------------------------------------- const Exchange = require ('./base/Exchange'); const { ExchangeError, ArgumentsRequired, ExchangeNotAvailable, InsufficientFunds, OrderNotFound, InvalidOrder, DDoSProtection, InvalidNonce, AuthenticationError, InvalidAddress, RateLimitExceeded, PermissionDenied, NotSupported, BadRequest, BadSymbol, AccountSuspended } = require ('./base/errors'); const { ROUND, TRUNCATE } = require ('./base/functions/number'); // --------------------------------------------------------------------------- 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, '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, }, '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': { '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', 'fapiPublic': 'https://fapi.binance.com/fapi/v1', 'fapiPrivate': 'https://fapi.binance.com/fapi/v1', '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', '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', 'futures/transfer', // 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/margin/account', 'sub-account/margin/accountSummary', 'sub-account/status', 'sub-account/transfer/subUserHistory', // 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', ], 'post': [ 'asset/dust', 'account/disableFastWithdrawSwitch', 'account/enableFastWithdrawSwitch', 'capital/withdraw/apply', 'margin/transfer', 'margin/loan', 'margin/repay', 'margin/order', 'margin/isolated/create', 'margin/isolated/transfer', 'sub-account/margin/enable', 'sub-account/margin/enable', 'sub-account/futures/enable', 'userDataStream', 'userDataStream/isolated', 'futures/transfer', // lending 'lending/customizedFixed/purchase', 'lending/daily/purchase', 'lending/daily/redeem', ], 'put': [ 'userDataStream', 'userDataStream/isolated', ], 'delete': [ 'margin/order', 'userDataStream', 'userDataStream/isolated', ], }, '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', ], }, 'fapiPublic': { 'get': [ 'ping', 'time', 'exchangeInfo', 'depth', 'trades', 'historicalTrades', 'aggTrades', 'klines', 'fundingRate', 'premiumIndex', 'ticker/24hr', 'ticker/price', 'ticker/bookTicker', 'allForceOrders', 'openInterest', 'leverageBracket', ], }, 'fapiPrivate': { 'get': [ 'allForceOrders', 'allOrders', 'openOrder', 'openOrders', 'order', 'account', 'balance', 'positionMargin/history', 'positionRisk', 'positionSide/dual', 'userTrades', 'income', ], 'post': [ 'batchOrders', 'positionSide/dual', 'positionMargin', 'marginType', 'order', 'leverage', 'listenKey', 'countdownCancelAll', ], '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': { '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': { 'fetchTradesMethod': 'publicGetAggTrades', // publicGetTrades, publicGetHistoricalTrades 'fetchTickersMethod': 'publicGetTicker24hr', 'defaultTimeInForce': 'GTC', // 'GTC' = Good To Cancel (default), 'IOC' = Immediate Or Cancel 'defaultType': 'spot', // 'spot', 'future', 'margin' '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': 'RESULT', // we change it from 'ACK' by default to 'RESULT' }, 'quoteOrderQty': true, // whether market orders support amounts in quote currency }, // https://binance-docs.github.io/apidocs/spot/en/#error-codes-2 'exceptions': { 'API key does not exist': AuthenticationError, 'Order would trigger immediately.': InvalidOrder, '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."} '-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." '-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. }, }); } nonce () { return this.milliseconds () - this.options['timeDifference']; } async fetchTime (params = {}) { const type = this.safeString2 (this.options, 'fetchTime', 'defaultType', 'spot'); const method = (type === 'spot') ? 'publicGetTime' : 'fapiPublicGetTime'; 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 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')) { throw new ExchangeError (this.id + " does not support '" + type + "' type, set exchange.options['defaultType'] to 'spot', 'margin' or 'future'"); // eslint-disable-line quotes } const method = (type === 'future') ? 'fapiPublicGetExchangeInfo' : 'publicGetExchangeInfo'; 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 (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"] // } // ] // } // 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 future = ('maintMarginPercent' in market); const spot = !future; const marketType = spot ? 'spot' : 'future'; 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 symbol = 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.safeString (market, 'status'); const active = (status === 'TRADING'); const margin = this.safeValue (market, 'isMarginTradingAllowed', future); const entry = { 'id': id, 'lowercaseId': lowercaseId, 'symbol': symbol, 'base': base, 'quote': quote, 'baseId': baseId, 'quoteId': quoteId, 'info': market, 'type': marketType, 'spot': spot, 'margin': margin, 'future': future, 'active': active, 'precision': precision, 'limits': { 'amount': { 'min': Math.pow (10, -precision['amount']), 'max': undefined, }, 'price': { 'min': undefined, 'max': undefined, }, 'cost': { 'min': undefined, 'max': undefined, }, }, }; if ('PRICE_FILTER' in filtersByType) { const filter = this.safeValue (filtersByType, 'PRICE_FILTER', {}); // 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.safeFloat (filter, 'minPrice'), 'max': undefined, }; const maxPrice = this.safeFloat (filter, 'maxPrice'); if ((maxPrice !== undefined) && (maxPrice > 0)) { entry['limits']['price']['max'] = maxPrice; } entry['precision']['price'] = this.precisionFromString (filter['tickSize']); } if ('LOT_SIZE' in filtersByType) { const filter = this.safeValue (filtersByType, 'LOT_SIZE', {}); const stepSize = this.safeString (filter, 'stepSize'); entry['precision']['amount'] = this.precisionFromString (stepSize); entry['limits']['amount'] = { 'min': this.safeFloat (filter, 'minQty'), 'max': this.safeFloat (filter, 'maxQty'), }; } if ('MARKET_LOT_SIZE' in filtersByType) { const filter = this.safeValue (filtersByType, 'MARKET_LOT_SIZE', {}); entry['limits']['market'] = { 'min': this.safeFloat (filter, 'minQty'), 'max': this.safeFloat (filter, 'maxQty'), }; } if ('MIN_NOTIONAL' in filtersByType) { const filter = this.safeValue (filtersByType, 'MIN_NOTIONAL', {}); entry['limits']['cost']['min'] = this.safeFloat (filter, 'minNotional'); } result.push (entry); } return result; } calculateFee (symbol, type, side, amount, price, takerOrMaker = 'taker', params = {}) { const market = this.markets[symbol]; let key = 'quote'; const rate = market[takerOrMaker]; let cost = amount * rate; let precision = market['precision']['price']; if (side === 'sell') { cost *= price; } else { key = 'base'; precision = market['precision']['amount']; } cost = this.decimalToPrecision (cost, ROUND, precision, this.precisionMode); return { 'type': takerOrMaker, 'currency': market[key], 'rate': rate, 'cost': parseFloat (cost), }; } async fetchBalance (params = {}) { await this.loadMarkets (); const defaultType = this.safeString2 (this.options, 'fetchBalance', 'defaultType', 'spot'); const type = this.safeString (params, 'type', defaultType); let method = 'privateGetAccount'; if (type === 'future') { const options = this.safeValue (this.options, 'future', {}); const fetchBalanceOptions = this.safeValue (options, 'fetchBalance', {}); method = this.safeString (fetchBalanceOptions, 'method', 'fapiPrivateV2GetAccount'); } else if (type === 'margin') { method = 'sapiGetMarginAccount'; } const query = this.omit (params, 'type'); const response = await this[method] (query); // // spot // // { // makerCommission: 10, // takerCommission: 10, // buyerCommission: 0, // sellerCommission: 0, // canTrade: true, // canWithdraw: true, // canDeposit: true, // updateTime: 1575357359602, // accountType: "MARGIN", // balances: [ // { asset: "BTC", free: "0.00219821", locked: "0.00000000" }, // ] // } // // margin // // { // "borrowEnabled":true, // "marginLevel":"999.00000000", // "totalAssetOfBtc":"0.00000000", // "totalLiabilityOfBtc":"0.00000000", // "totalNetAssetOfBtc":"0.00000000", // "tradeEnabled":true, // "transferEnabled":true, // "userAssets":[ // {"asset":"MATIC","borrowed":"0.00000000","free":"0.00000000","interest":"0.00000000","locked":"0.00000000","netAsset":"0.00000000"}, // {"asset":"VET","borrowed":"0.00000000","free":"0.00000000","interest":"0.00000000","locked":"0.00000000","netAsset":"0.00000000"}, // {"asset":"USDT","borrowed":"0.00000000","free":"0.00000000","interest":"0.00000000","locked":"0.00000000","netAsset":"0.00000000"} // ], // } // // futures (fapi) // // fapiPrivateGetAccount // // { // "feeTier":0, // "canTrade":true, // "canDeposit":true, // "canWithdraw":true, // "updateTime":0, // "totalInitialMargin":"0.00000000", // "totalMaintMargin":"0.00000000", // "totalWalletBalance":"4.54000000", // "totalUnrealizedProfit":"0.00000000", // "totalMarginBalance":"4.54000000", // "totalPositionInitialMargin":"0.00000000", // "totalOpenOrderInitialMargin":"0.00000000", // "maxWithdrawAmount":"4.54000000", // "assets":[ // { // "asset":"USDT", // "walletBalance":"4.54000000", // "unrealizedProfit":"0.00000000", // "marginBalance":"4.54000000", // "maintMargin":"0.00000000", // "initialMargin":"0.00000000", // "positionInitialMargin":"0.00000000", // "openOrderInitialMargin":"0.00000000", // "maxWithdrawAmount":"4.54000000" // } // ], // "positions":[ // { // "symbol":"BTCUSDT", // "initialMargin":"0.00000", // "maintMargin":"0.00000", // "unrealizedProfit":"0.00000000", // "positionInitialMargin":"0.00000", // "openOrderInitialMargin":"0.00000" // } // ] // } // // fapiPrivateV2GetAccount // // { // "feeTier":0, // "canTrade":true, // "canDeposit":true, // "canWithdraw":true, // "updateTime":0, // "totalInitialMargin":"0.00000000", // "totalMaintMargin":"0.00000000", // "totalWalletBalance":"0.00000000", // "totalUnrealizedProfit":"0.00000000", // "totalMarginBalance":"0.00000000", // "totalPositionInitialMargin":"0.00000000", // "totalOpenOrderInitialMargin":"0.00000000", // "totalCrossWalletBalance":"0.00000000", // "totalCrossUnPnl":"0.00000000", // "availableBalance":"0.00000000", // "maxWithdrawAmount":"0.00000000", // "assets":[ // { // "asset":"BNB", // "walletBalance":"0.01000000", // "unrealizedProfit":"0.00000000", // "marginBalance":"0.01000000", // "maintMargin":"0.00000000", // "initialMargin":"0.00000000", // "positionInitialMargin":"0.00000000", // "openOrderInitialMargin":"0.00000000", // "maxWithdrawAmount":"0.01000000", // "crossWalletBalance":"0.01000000", // "crossUnPnl":"0.00000000", // "availableBalance":"0.01000000" // } // ], // "positions":[ // { // "symbol":"BTCUSDT", // "initialMargin":"0", // "maintMargin":"0", // "unrealizedProfit":"0.00000000", // "positionInitialMargin":"0", // "openOrderInitialMargin":"0", // "leverage":"20", // "isolated":false, // "entryPrice":"0.00000", // "maxNotional":"5000000", // "positionSide":"BOTH" // }, // ] // } // // fapiPrivateV2GetBalance // // [ // { // "accountAlias":"FzFzXquXXqoC", // "asset":"BNB", // "balance":"0.01000000", // "crossWalletBalance":"0.01000000", // "crossUnPnl":"0.00000000", // "availableBalance":"0.01000000", // "maxWithdrawAmount":"0.01000000" // } // ] // const result = { 'info': response }; if ((type === 'spot') || (type === 'margin')) { const balances = this.safeValue2 (response, 'balances', 'userAssets', []); 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.safeFloat (balance, 'free'); account['used'] = this.safeFloat (balance, 'locked'); result[code] = account; } } else { let balances = response; if (!Array.isArray (response)) { balances = this.safeValue (response, 'assets', []); } 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.safeFloat (balance, 'availableBalance'); account['used'] = this.safeFloat (balance, 'initialMargin'); account['total'] = this.safeFloat2 (balance, 'marginBalance', 'balance'); result[code] = account; } } return this.parseBalance (result); } async fetchOrderBook (symbol, limit = undefined, params = {}) { await this.loadMarkets (); const market = this.market (symbol); const request = { 'symbol': market['id'], }; if (limit !== undefined) { request['limit'] = limit; // default 100, max 5000, see https://github.com/binance-exchange/binance-official-api-docs/blob/master/rest-api.md#order-book } const method = market['spot'] ? 'publicGetDepth' : 'fapiPublicGetDepth'; const response = await this[method] (this.extend (request, params)); const orderbook = this.parseOrderBook (response); orderbook['nonce'] = this.safeInteger (response, 'lastUpdateId'); return orderbook; } parseTicker (ticker, market = undefined) { const timestamp = this.safeInteger (ticker, 'closeTime'); let symbol = undefined; const marketId = this.safeString (ticker, 'symbol'); if (marketId in this.markets_by_id) { market = this.markets_by_id[marketId]; } if (market !== undefined) { symbol = market['symbol']; } const last = this.safeFloat (ticker, 'lastPrice'); return { 'symbol': symbol, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'high': this.safeFloat (ticker, 'highPrice'), 'low': this.safeFloat (ticker, 'lowPrice'), 'bid': this.safeFloat (ticker, 'bidPrice'), 'bidVolume': this.safeFloat (ticker, 'bidQty'), 'ask': this.safeFloat (ticker, 'askPrice'), 'askVolume': this.safeFloat (ticker, 'askQty'), 'vwap': this.safeFloat (ticker, 'weightedAvgPrice'), 'open': this.safeFloat (ticker, 'openPrice'), 'close': last, 'last': last, 'previousClose': this.safeFloat (ticker, 'prevClosePrice'), // previous day close 'change': this.safeFloat (ticker, 'priceChange'), 'percentage': this.safeFloat (ticker, 'priceChangePercent'), 'average': undefined, 'baseVolume': this.safeFloat (ticker, 'volume'), 'quoteVolume': this.safeFloat (ticker, 'quoteVolume'), 'info': ticker, }; } async fetchStatus (params = {}) { const response = await this.wapiGetSystemStatus (params); let status = this.safeValue (response, 'status'); if (status !== undefined) { status = (status === 0) ? 'ok' : 'maintenance'; this.status = this.extend (this.status, { 'status': status, 'updated': this.milliseconds (), }); } return this.status; } async fetchTicker (symbol, params = {}) { await this.loadMarkets (); const market = this.market (symbol); const request = { 'symbol': market['id'], }; const method = market['spot'] ? 'publicGetTicker24hr' : 'fapiPublicGetTicker24hr'; const response = await this[method] (this.extend (request, params)); return this.parseTicker (response, market); } parseTickers (rawTickers, symbols = undefined) { const tickers = []; for (let i = 0; i < rawTickers.length; i++) { tickers.push (this.parseTicker (rawTickers[i])); } return this.filterByArray (tickers, 'symbol', symbols); } async fetchBidsAsks (symbols = undefined, params = {}) { await this.loadMarkets (); const defaultType = this.safeString2 (this.options, 'fetchBidsAsks', 'defaultType', 'spot'); const type = this.safeString (params, 'type', defaultType); const query = this.omit (params, 'type'); const method = (type === 'spot') ? 'publicGetTickerBookTicker' : 'fapiPublicGetTickerBookTicker'; const response = await this[method] (query); return this.parseTickers (response, symbols); } async fetchTickers (symbols = undefined, params = {}) { await this.loadMarkets (); const method = this.options['fetchTickersMethod']; const response = await this[method] (params); return this.parseTickers (response, symbols); } parseOHLCV (ohlcv, market = undefined) { // // [ // 1591478520000, // "0.02501300", // "0.02501800", // "0.02500000", // "0.02500000", // "22.19000000", // 1591478579999, // "0.55490906", // 40, // "10.92900000", // "0.27336462", // "0" // ] // return [ this.safeInteger (ohlcv, 0), this.safeFloat (ohlcv, 1), this.safeFloat (ohlcv, 2), this.safeFloat (ohlcv, 3), this.safeFloat (ohlcv, 4), this.safeFloat (ohlcv, 5), ]; } async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) { await this.loadMarkets (); const market = this.market (symbol); const request = { 'symbol': market['id'], 'interval': this.timeframes[timeframe], }; if (since !== undefined) { request['startTime'] = since; } if (limit !== undefined) { request['limit'] = limit; // default == max == 500 } const method = market['spot'] ? 'publicGetKlines' : 'fapiPublicGetKlines'; const response = await this[method] (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"], // ] // return this.parseOHLCVs (response, market, timeframe, since, limit); } parseTrade (trade, market = undefined) { if ('isDustTrade' in trade) { return this.parseDustTrade (trade, market); } // // 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 // } // const timestamp = this.safeInteger2 (trade, 'T', 'time'); const price = this.safeFloat2 (trade, 'p', 'price'); const amount = this.safeFloat2 (trade, 'q', 'qty'); const id = this.safeString2 (trade, 'a', 'id'); let side = undefined; const orderId = this.safeString (trade, 'orderId'); if ('m' in trade) { side = trade['m'] ? 'sell' : 'buy'; // this is reversed intentionally } else if ('isBuyerMaker' in trade) { side = trade['isBuyerMaker'] ? 'sell' : 'buy'; } 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.safeFloat (trade, 'commission'), 'currency': this.safeCurrencyCode (this.safeString (trade, 'commissionAsset')), }; } let takerOrMaker = undefined; if ('isMaker' in trade) { takerOrMaker = trade['isMaker'] ? 'maker' : 'taker'; } let symbol = undefined; if (market === undefined) { const marketId = this.safeString (trade, 'symbol'); market = this.safeValue (this.markets_by_id, marketId); } if (market !== undefined) { symbol = market['symbol']; } let cost = undefined; if ((price !== undefined) && (amount !== undefined)) { cost = price * amount; } return { 'info': trade, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'symbol': symbol,