UNPKG

ccxt-look

Version:

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

427 lines (340 loc) 12.7 kB
'use strict' // ---------------------------------------------------------------------------- const [processPath, , exchangeId = null, exchangeSymbol = null] = process.argv.filter ((x) => !x.startsWith ('--')) const verbose = process.argv.includes ('--verbose') || false const debug = process.argv.includes ('--debug') || false // ---------------------------------------------------------------------------- const fs = require ('fs') , assert = require ('assert') , { Agent } = require ('https') , ccxt = require ('../../ccxt.js') // eslint-disable-line import/order // ---------------------------------------------------------------------------- process.on ('uncaughtException', (e) => { console.log (e, e.stack); process.exit (1) }) process.on ('unhandledRejection', (e) => { console.log (e, e.stack); process.exit (1) }) // ---------------------------------------------------------------------------- console.log ('\nTESTING', { 'exchange': exchangeId, 'symbol': exchangeSymbol || 'all' }, '\n') // ---------------------------------------------------------------------------- const proxies = [ '', 'https://cors-anywhere.herokuapp.com/' ] //----------------------------------------------------------------------------- const enableRateLimit = true const httpsAgent = new Agent ({ 'ecdhCurve': 'auto', }) const timeout = 20000 const exchange = new (ccxt)[exchangeId] ({ httpsAgent, verbose, enableRateLimit, debug, timeout, }) //----------------------------------------------------------------------------- const tests = {} const properties = Object.keys (exchange.has) properties // eslint-disable-next-line no-path-concat .filter ((property) => fs.existsSync (__dirname + '/Exchange/test.' + property + '.js')) .forEach ((property) => { // eslint-disable-next-line global-require, import/no-dynamic-require, no-path-concat tests[property] = require (__dirname + '/Exchange/test.' + property + '.js') }) const errors = require ('../base/errors.js') Object.keys (errors) // eslint-disable-next-line no-path-concat .filter ((error) => fs.existsSync (__dirname + '/errors/test.' + error + '.js')) .forEach ((error) => { // eslint-disable-next-line global-require, import/no-dynamic-require, no-path-concat tests[error] = require (__dirname + '/errors/test.' + error + '.js') }) //----------------------------------------------------------------------------- const keysGlobal = 'keys.json' const keysLocal = 'keys.local.json' const keysFile = fs.existsSync (keysLocal) ? keysLocal : keysGlobal // eslint-disable-next-line import/no-dynamic-require, no-path-concat const settings = require (__dirname + '/../../' + keysFile)[exchangeId] if (settings) { const keys = Object.keys (settings) for (let i = 0; i < keys.length; i++) { const key = keys[i] if (settings[key]) { settings[key] = ccxt.deepExtend (exchange[key] || {}, settings[key]) } } } Object.assign (exchange, settings) if (settings && settings.skip) { console.log ('[Skipped]', { 'exchange': exchangeId, 'symbol': exchangeSymbol || 'all' }) process.exit () } //----------------------------------------------------------------------------- async function test (methodName, exchange, ... args) { console.log ('Testing', exchange.id, methodName, '(', ... args, ')') return await (tests[methodName] (exchange, ... args)) } async function testSymbol (exchange, symbol) { await test ('loadMarkets', exchange); await test ('fetchCurrencies', exchange); await test ('fetchTicker', exchange, symbol); await test ('fetchTickers', exchange, symbol); await test ('fetchOHLCV', exchange, symbol); await test ('fetchTrades', exchange, symbol); if (exchange.id === 'coinbase') { // nothing for now } else { await test ('fetchOrderBook', exchange, symbol); await test ('fetchL2OrderBook', exchange, symbol); await test ('fetchOrderBooks', exchange); } } //----------------------------------------------------------------------------- async function loadExchange (exchange) { const markets = await exchange.loadMarkets () assert (typeof exchange.markets === 'object', '.markets is not an object') assert (Array.isArray (exchange.symbols), '.symbols is not an array') assert (exchange.symbols.length > 0, '.symbols.length <= 0 (less than or equal to zero)') assert (Object.keys (exchange.markets).length > 0, 'Object.keys (.markets).length <= 0 (less than or equal to zero)') assert (exchange.symbols.length === Object.keys (exchange.markets).length, 'number of .symbols is not equal to the number of .markets') const symbols = [ 'BTC/CNY', 'BTC/USD', 'BTC/USDT', 'BTC/EUR', 'BTC/ETH', 'ETH/BTC', 'BTC/JPY', 'ETH/EUR', 'ETH/JPY', 'ETH/CNY', 'ETH/USD', 'LTC/CNY', 'DASH/BTC', 'DOGE/BTC', 'BTC/AUD', 'BTC/PLN', 'USD/SLL', 'BTC/RUB', 'BTC/UAH', 'LTC/BTC', 'EUR/USD', ] let result = exchange.symbols.filter ((symbol) => symbols.indexOf (symbol) >= 0) if (result.length > 0) { if (exchange.symbols.length > result.length) { result = result.join (', ') + ' + more...' } else { result = result.join (', ') } } console.log (exchange.symbols.length, 'symbols', result) } //----------------------------------------------------------------------------- function getTestSymbol (exchange, symbols) { let symbol = undefined for (let i = 0; i < symbols.length; i++) { const s = symbols[i] const market = exchange.safeValue (exchange.markets, s) if (market !== undefined) { const active = exchange.safeValue (market, 'active') if (active || (active === undefined)) { symbol = s break; } } } return symbol } async function testExchange (exchange) { await loadExchange (exchange) const codes = [ 'BTC', 'ETH', 'XRP', 'LTC', 'BCH', 'EOS', 'BNB', 'BSV', 'USDT', 'ATOM', 'BAT', 'BTG', 'DASH', 'DOGE', 'ETC', 'IOTA', 'LSK', 'MKR', 'NEO', 'PAX', 'QTUM', 'TRX', 'TUSD', 'USD', 'USDC', 'WAVES', 'XEM', 'XMR', 'ZEC', 'ZRX', ] let code = undefined for (let i = 0; i < codes.length; i++) { if (codes[i] in exchange.currencies) { code = codes[i] } } let symbol = getTestSymbol (exchange, [ 'BTC/USD', 'BTC/USDT', 'BTC/CNY', 'BTC/EUR', 'BTC/ETH', 'ETH/BTC', 'ETH/USD', 'ETH/USDT', 'BTC/JPY', 'LTC/BTC', 'ZRX/WETH', 'EUR/USD', ]) if (symbol === undefined) { for (let i = 0; i < codes.length; i++) { const markets = Object.values (exchange.markets) const activeMarkets = markets.filter ((market) => (market['base'] === codes[i])) if (activeMarkets.length) { const activeSymbols = activeMarkets.map (market => market['symbol']) symbol = getTestSymbol (exchange, activeSymbols) break; } } } if (symbol === undefined) { const markets = Object.values (exchange.markets) const activeMarkets = markets.filter ((market) => !exchange.safeValue (market, 'active', false)) const activeSymbols = activeMarkets.map (market => market['symbol']) symbol = getTestSymbol (exchange, activeSymbols) } if (symbol === undefined) { symbol = getTestSymbol (exchange, exchange.symbols) } if (symbol === undefined) { symbol = exchange.symbols[0] } console.log ('SYMBOL:', symbol) if ((symbol.indexOf ('.d') < 0)) { await testSymbol (exchange, symbol) } if (!exchange.privateKey && (!exchange.apiKey || (exchange.apiKey.length < 1))) { return true } exchange.checkRequiredCredentials () if (exchange['has']['signIn']) { await exchange.signIn () } // move to testnet/sandbox if possible before accessing the balance // if (exchange.urls['test']) // exchange.urls['api'] = exchange.urls['test'] const balance = await test ('fetchBalance', exchange) await test ('fetchFundingFees', exchange) await test ('fetchTradingFees', exchange) await test ('fetchStatus', exchange) await test ('fetchOrders', exchange, symbol) await test ('fetchOpenOrders', exchange, symbol) await test ('fetchClosedOrders', exchange, symbol) await test ('fetchMyTrades', exchange, symbol) await test ('fetchLeverageTiers', exchange, symbol) await test ('fetchPositions', exchange, symbol) if ('fetchLedger' in tests) { await test ('fetchLedger', exchange, code) } await test ('fetchTransactions', exchange, code) await test ('fetchDeposits', exchange, code) await test ('fetchWithdrawals', exchange, code) await test ('fetchBorrowRate', exchange, code) await test ('fetchBorrowRates', exchange) await test ('fetchBorrowInterest', exchange, code) await test ('fetchBorrowInterest', exchange, code, symbol) if (exchange.extendedTest) { await test ('InvalidNonce', exchange, symbol) await test ('OrderNotFound', exchange, symbol) await test ('InvalidOrder', exchange, symbol) await test ('InsufficientFunds', exchange, symbol, balance) // danger zone - won't execute with non-empty balance } // try { // let marketSellOrder = // await exchange.createMarketSellOrder (exchange.symbols[0], 1) // console.log (exchange.id, 'ok', marketSellOrder) // } catch (e) { // console.log (exchange.id, 'error', 'market sell', e) // } // // try { // let marketBuyOrder = await exchange.createMarketBuyOrder (exchange.symbols[0], 1) // console.log (exchange.id, 'ok', marketBuyOrder) // } catch (e) { // console.log (exchange.id, 'error', 'market buy', e) // } // // try { // let limitSellOrder = await exchange.createLimitSellOrder (exchange.symbols[0], 1, 3000) // console.log (exchange.id, 'ok', limitSellOrder) // } catch (e) { // console.log (exchange.id, 'error', 'limit sell', e) // } // // try { // let limitBuyOrder = await exchange.createLimitBuyOrder (exchange.symbols[0], 1, 3000) // console.log (exchange.id, 'ok', limitBuyOrder) // } catch (e) { // console.log (exchange.id, 'error', 'limit buy', e) // } } //----------------------------------------------------------------------------- async function tryAllProxies (exchange, proxies) { const index = proxies.indexOf (exchange.proxy) let currentProxy = (index >= 0) ? index : 0 const maxRetries = proxies.length if (settings && ('proxy' in settings)) { currentProxy = proxies.indexOf (settings.proxy) } for (let numRetries = 0; numRetries < maxRetries; numRetries++) { try { exchange.proxy = proxies[currentProxy] // add random origin for proxies if (exchange.proxy.length > 0) { exchange.origin = exchange.uuid () } await testExchange (exchange) break } catch (e) { currentProxy = ++currentProxy % proxies.length console.log ('[' + e.constructor.name + '] ' + e.message.slice (0, 200)) if (e instanceof ccxt.DDoSProtection) { continue } else if (e instanceof ccxt.RequestTimeout) { continue } else if (e instanceof ccxt.ExchangeNotAvailable) { continue } else if (e instanceof ccxt.AuthenticationError) { return } else if (e instanceof ccxt.InvalidNonce) { return } else { throw e } } } } //----------------------------------------------------------------------------- async function main () { if (exchangeSymbol) { await loadExchange (exchange) await testSymbol (exchange, exchangeSymbol) } else { await tryAllProxies (exchange, proxies) } } main ()