diff --git a/TaskServer/TradingBot.js b/TaskServer/TradingBot.js index 1a2852487..c0af44f59 100644 --- a/TaskServer/TradingBot.js +++ b/TaskServer/TradingBot.js @@ -121,6 +121,7 @@ const CONDITIONS_FOLDER_NAME = "Simulation-Conditions"; const STRATEGIES_FOLDER_NAME = "Simulation-Strategies"; const TRADES_FOLDER_NAME = "Simulation-Trades"; + const SNAPSHOTS_FOLDER_NAME = "Snapshots"; const ONE_DAY_IN_MILISECONDS = 24 * 60 * 60 * 1000; @@ -129,6 +130,10 @@ let strategiesArray let tradesArray + let snapshotHeaders + let triggerOnSnapshot + let takePositionSnapshot + let tradingSystem = {}; tradingSimulation.runSimulation( @@ -142,7 +147,7 @@ writeFiles, callBackFunction) - function writeFiles(pTradingSystem, pRecordsArray, pConditionsArray, pStrategiesArray, pTradesArray) { + function writeFiles(pTradingSystem, pRecordsArray, pConditionsArray, pStrategiesArray, pTradesArray, pSnapshotHeaders, pTriggerOnSnapshot, pTakePositionSnapshot) { tradingSystem = pTradingSystem recordsArray = pRecordsArray @@ -150,11 +155,16 @@ strategiesArray = pStrategiesArray tradesArray = pTradesArray + snapshotHeaders = pSnapshotHeaders + triggerOnSnapshot = pTriggerOnSnapshot + takePositionSnapshot = pTakePositionSnapshot + if (timeFrame > global.dailyFilePeriods[0][0]) { writeMarketFiles() } else { writeDailyFiles() } + } function writeMarketFiles() { @@ -474,7 +484,7 @@ } - callBackFunction(global.DEFAULT_OK_RESPONSE); + writeSnapshotFiles(); } catch (err) { @@ -489,97 +499,52 @@ } } - } + function writeSnapshotFiles() { - function writeDailyFiles() { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDailyFiles -> Entering function."); } + writeSnapshotFile(triggerOnSnapshot, 'Trigger-On', onFinish) - writeRecordsFile(); + function onFinish() { + writeSnapshotFile(takePositionSnapshot, 'Take-Position', callBackFunction) + } + + } - /* TODO : NEXT function is a work in progress, not used today */ - function writeFinalResults() { + function writeSnapshotFile(snapshotArray, pFileName, callBack) { try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDailyFiles -> writeFinalResults -> Entering function."); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeMarketFiles -> writeSnapshotFile -> Entering function."); } - if ( // We only write this file if we are at the head of the market. - Math.trunc(currentDay.valueOf() / ONE_DAY_IN_MILISECONDS) * ONE_DAY_IN_MILISECONDS - !== - Math.trunc((new Date()).valueOf() / ONE_DAY_IN_MILISECONDS) * ONE_DAY_IN_MILISECONDS - ) { - writeRecordsFile(); - return; - } - - let separator = ""; let fileRecordCounter = 0; let fileContent = ""; + let separator = "\r\n"; - for (let i = 0; i < recordsArray.length; i++) { - - let record = recordsArray[i]; - - /* Will only add to the file the records of the current day */ - - if (record.begin < currentDay.valueOf()) { continue; } - - fileContent = fileContent + separator + '[' + - record.begin + "," + - record.end + "," + - record.type + "," + - record.marketRate + "," + - record.amount + "," + - record.balanceA + "," + - record.balanceB + "," + - record.profit + "," + - record.lastTradeProfitLoss + "," + - record.stopLoss + "," + - record.roundtrips + "," + - record.hits + "," + - record.fails + "," + - record.hitRatio + "," + - record.ROI + "," + - record.periods + "," + - record.days + "," + - record.anualizedRateOfReturn + "," + - record.positionRate + "," + - record.lastTradeROI + "," + - record.strategy + "," + - record.strategyStageNumber + "," + - record.takeProfit + "," + - record.stopLossPhase + "," + - record.takeProfitPhase + "," + - JSON.stringify(record.executionRecord) + "," + - record.positionSize + "," + - record.initialBalanceA + "," + - record.minimumBalanceA + "," + - record.maximumBalanceA + "," + - record.initialBalanceB + "," + - record.minimumBalanceB + "," + - record.maximumBalanceB + "," + - record.baseAsset + "," + - record.quotedAsset + "," + - record.marketBaseAsset + "," + - record.marketQuotedAsset + "," + - record.positionPeriods + "," + - record.positionDays + "," + - record.distanceToLastTriggerOn + "," + - record.distanceToLastTriggerOff + "," + - record.distanceToLastTakePosition + "," + - record.distanceToLastClosePosition + "]"; - - if (separator === "") { separator = ","; } + parseRecord(snapshotHeaders) + for (let i = 0; i < snapshotArray.length; i++) { + let record = snapshotArray[i]; + parseRecord(record) fileRecordCounter++; + } + + function parseRecord(record) { + for (let j = 0; j < record.length; j++) { + let property = record[j] + + fileContent = fileContent + '' + property + if (j !== record.length - 1) { + fileContent = fileContent + "," + } + } + fileContent = fileContent + separator } - fileContent = "[" + fileContent + "]"; + fileContent = "" + fileContent + ""; - let fileName = 'Data.json'; - let filePath = bot.filePathRoot + "/Output/" + bot.SESSION.folderName + "/" + SIMULATED_RECORDS_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + timeFrameLabel; + let fileName = pFileName + '.csv'; + let filePath = bot.filePathRoot + "/Output/" + bot.SESSION.folderName + "/" + SNAPSHOTS_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timeFrameLabel; filePath += '/' + fileName fileStorage.createTextFile(filePath, fileContent + '\n', onFileCreated); @@ -588,35 +553,42 @@ try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDailyFiles -> writeFinalResults -> onFileCreated -> Entering function."); } - if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDailyFiles -> writeFinalResults -> onFileCreated -> fileContent = " + fileContent); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeMarketFiles -> writeSnapshotFile -> onFileCreated -> Entering function."); } + if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> writeMarketFiles -> writeSnapshotFile -> onFileCreated -> fileContent = " + fileContent); } if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - logger.write(MODULE_NAME, "[ERROR] start -> writeDailyFiles -> writeFinalResults -> onFileCreated -> err = " + err.stack); - logger.write(MODULE_NAME, "[ERROR] start -> writeDailyFiles -> writeFinalResults -> onFileCreated -> filePath = " + filePath); - logger.write(MODULE_NAME, "[ERROR] start -> writeDailyFiles -> writeFinalResults -> onFileCreated -> market = " + market.baseAsset + "_" + market.quotedAsset); + logger.write(MODULE_NAME, "[ERROR] start -> writeMarketFiles -> writeSnapshotFile -> onFileCreated -> err = " + err.stack); + logger.write(MODULE_NAME, "[ERROR] start -> writeMarketFiles -> writeSnapshotFile -> onFileCreated -> filePath = " + filePath); + logger.write(MODULE_NAME, "[ERROR] start -> writeMarketFiles -> writeSnapshotFile -> onFileCreated -> market = " + market.baseAsset + "_" + market.quotedAsset); callBackFunction(err); return; } - writeRecordsFile(); + callBack(global.DEFAULT_OK_RESPONSE); } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> writeDailyFiles -> writeFinalResults -> onFileCreated -> err = " + err.stack); + logger.write(MODULE_NAME, "[ERROR] start -> writeMarketFiles -> writeSnapshotFile -> onFileCreated -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> writeDailyFiles -> writeFinalResults -> err = " + err.stack); + logger.write(MODULE_NAME, "[ERROR] start -> writeMarketFiles -> writeSnapshotFile -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } + } + + function writeDailyFiles() { + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDailyFiles -> Entering function."); } + + writeRecordsFile(); + function writeRecordsFile() { try { diff --git a/TaskServer/TradingSimulation.js b/TaskServer/TradingSimulation.js index 1e924e89c..9fc408d30 100644 --- a/TaskServer/TradingSimulation.js +++ b/TaskServer/TradingSimulation.js @@ -39,6 +39,10 @@ } else { processingDailyFiles = true } + + let snapshotHeaders + let triggerOnSnapshot = []; + let takePositionSnapshot = []; let recordsArray = []; let conditionsArray = []; @@ -500,6 +504,14 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Entering function."); } if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Processing candle # " + currentCandleIndex); } + /* We are going to take snapshots of the values of indicators at key moments of the sumulation. */ + + let snapshotKeys = new Map() + snapshotLoopHeaders = [] + snapshotDataRecord = [] + addToTriggerOnSnapshot = false + addToTakePositionSnapshot = false + let announcementsToBeMade = [] let candle = candles[currentCandleIndex]; @@ -767,7 +779,9 @@ if (initialDefinition.positionSize !== undefined) { if (initialDefinition.positionSize.formula !== undefined) { try { - positionSize = eval(initialDefinition.positionSize.formula.code); + let code = initialDefinition.positionSize.formula.code + positionSize = eval(code); + addCodeToSnapshot(code) } catch (err) { initialDefinition.positionSize.formula.error = err.message } @@ -794,7 +808,9 @@ if (initialDefinition.positionRate !== undefined) { if (initialDefinition.positionRate.formula !== undefined) { try { + let code = initialDefinition.positionRate.formula.code positionRate = eval(initialDefinition.positionRate.formula.code); + addCodeToSnapshot(code) } catch (err) { initialDefinition.positionRate.formula.error = err.message } @@ -821,7 +837,9 @@ if (phase.formula !== undefined) { try { - formulaValue = eval(phase.formula.code); + let code = phase.formula.code + formulaValue = eval(code); + addCodeToSnapshot(code) if (formulaValue === Infinity) { formulaError = "Formula evaluates to Infinity." formulaValue = MAX_STOP_LOSS_VALUE @@ -910,7 +928,9 @@ if (phase.formula !== undefined) { try { - formulaValue = eval(phase.formula.code); + let code = phase.formula.code + formulaValue = eval(code); + addCodeToSnapshot(code) if (formulaValue === Infinity) { formulaValue = MAX_TAKE_PROFIT_VALUE if (takeProfitStage === 'Open Stage') { @@ -1007,7 +1027,9 @@ if (phase.formula !== undefined) { try { - formulaValue = eval(phase.formula.code); + let code = phase.formula.code + formulaValue = eval(code); + addCodeToSnapshot(code) if (formulaValue === Infinity) { formulaError = "" formulaValue = MAX_STOP_LOSS_VALUE @@ -1096,7 +1118,9 @@ if (phase.formula !== undefined) { try { - formulaValue = eval(phase.formula.code); + let code = phase.formula.code + formulaValue = eval(code); + addCodeToSnapshot(code) if (formulaValue === Infinity) { formulaError = "Formula evaluates to Infinity." formulaValue = MAX_TAKE_PROFIT_VALUE @@ -1181,7 +1205,9 @@ let value try { - value = eval(node.code); + let code = node.code + value = eval(code); + addCodeToSnapshot(code) } catch (err) { /* One possible error is that the conditions references a .previous that is undefined. For this @@ -1319,6 +1345,7 @@ } checkAnnouncements(triggerStage.triggerOn) + addToTriggerOnSnapshot = true if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Switching to Trigger Stage because conditions at Trigger On Event were met."); } break; @@ -1452,6 +1479,7 @@ currentTrade.takePositionSituation = situation.name checkAnnouncements(triggerStage.takePosition) + addToTakePositionSnapshot = true if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Conditions at the Take Position Event were met."); } break; @@ -2186,6 +2214,7 @@ } takePositionAtSimulation() + return function putOpeningOrder() { @@ -2914,6 +2943,21 @@ } } + /* Add to Snapshot */ + if (addToTakePositionSnapshot === true) { + takePositionSnapshot.push(snapshotDataRecord) + addToTakePositionSnapshot = false + } + + if (addToTriggerOnSnapshot === true) { + triggerOnSnapshot.push(snapshotDataRecord) + addToTriggerOnSnapshot = false + } + + if (snapshotHeaders === undefined) { + snapshotHeaders = JSON.parse(JSON.stringify(snapshotLoopHeaders)) + } + makeAnnoucements() // After everything at the simulation level was done, we will do the annoucements that are pending. } @@ -3005,10 +3049,63 @@ } } } + + function addCodeToSnapshot(code) { + if (code === undefined) { return } + + try { + let instructionsArray = code.split(' ') + for (let i = 0; i < instructionsArray.length; i++) { + let instruction = instructionsArray[i] + instruction = instruction.replace('(', '') + instruction = instruction.replace(')', '') + instruction = instruction.replace(//g, '') + instruction = instruction.replace(/<=/g, '') + instruction = instruction.replace(/>=/g, '') + instruction = instruction.replace(/!=/g, '') + instruction = instruction.replace(/!==/g, '') + instruction = instruction.replace(/==/g, '') + instruction = instruction.replace(/===/g, '') + if (instruction.indexOf('chart') >= 0) { + let parts = instruction.split('.') + let timeFrame = parts[1] + let product = parts[2] + let property + checkPrevious(3) + function checkPrevious(index) { + property = parts[index] + if (property === 'previous') { + product = product + '.previous' + checkPrevious(index + 1) + } + } + + // Example: chart.at01hs.popularSMA.sma200 - chart.at01hs.popularSMA.sma100 < 10 + if (timeFrame !== 'atAnyTimeFrame') { + timeFrame = timeFrame.substring(2, 4) + '-' + timeFrame.substring(4, 7) + } + let key = timeFrame + '-' + product + '-' + property + let existingKey = snapshotKeys.get(key) + + if (existingKey === undefined) {// means that at the current loop this property of this product was not used before. + snapshotKeys.set(key, key) + snapshotLoopHeaders.push(key) + + let value = eval(instruction) + snapshotDataRecord.push(value) + } + } + } + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] runSimulation -> addCodeToSnapshot -> code = " + code); + logger.write(MODULE_NAME, "[ERROR] runSimulation -> addCodeToSnapshot -> err = " + err.stack); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } } - - function controlLoop() { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> controlLoop -> Entering function."); } @@ -3114,7 +3211,7 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> callback -> recordsArray.length = " + recordsArray.length); } - callback(tradingSystem, recordsArray, conditionsArray, strategiesArray, tradesArray); + callback(tradingSystem, recordsArray, conditionsArray, strategiesArray, tradesArray, snapshotHeaders, triggerOnSnapshot, takePositionSnapshot); } function getElement(pArray, currentCandle, datasetName) { @@ -3156,6 +3253,7 @@ } } } + catch (err) { logger.write(MODULE_NAME, "[ERROR] runSimulation -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); diff --git a/TaskServer/node_modules/ccxt/build/export-exchanges.js b/TaskServer/node_modules/ccxt/build/export-exchanges.js index 6ed8fd0cd..e46845674 100644 --- a/TaskServer/node_modules/ccxt/build/export-exchanges.js +++ b/TaskServer/node_modules/ccxt/build/export-exchanges.js @@ -333,9 +333,21 @@ function exportKeywordsToPackageJson (exchanges) { // ---------------------------------------------------------------------------- -function exportEverything () { +function flatten (nested, result = []) { + for (const key in nested) { + result.push (key) + if (Object.keys (nested[key]).length) + flatten (nested[key], result) + } + return result +} + +function exportEverything () { const ids = getIncludedExchangeIds () + const errorHierarchy = require ('../js/base/errorHierarchy.js') + const flat = flatten (errorHierarchy) + flat.push ('error_hierarchy') const replacements = [ { @@ -353,6 +365,16 @@ function exportEverything () { regex: /(?:from ccxt\.[^\.]+ import [^\s]+\s+\# noqa\: F401[\r]?[\n])+[\r]?[\n]exchanges/, replacement: ids.map (id => ('from ccxt.' + id + ' import ' + id).padEnd (60) + '# noqa: F401').join ("\n") + "\n\nexchanges", }, + { + file: './python/ccxt/__init__.py', + regex: /(?:from ccxt\.base\.errors import [^\s]+\s+\# noqa\: F401[\r]?[\n])+[\r]?[\n]/, + replacement: flat.map (error => ('from ccxt.base.errors' + ' import ' + error).padEnd (60) + '# noqa: F401').join ("\n") + "\n\n", + }, + { + file: './python/ccxt/async_support/__init__.py', + regex: /(?:from ccxt\.base\.errors import [^\s]+\s+\# noqa\: F401[\r]?[\n])+[\r]?[\n]/, + replacement: flat.map (error => ('from ccxt.base.errors' + ' import ' + error).padEnd (60) + '# noqa: F401').join ("\n") + "\n\n", + }, { file: './python/ccxt/async_support/__init__.py', regex: /(?:from ccxt\.async_support\.[^\.]+ import [^\s]+\s+\# noqa\: F401[\r]?[\n])+[\r]?[\n]exchanges/, diff --git a/TaskServer/node_modules/ccxt/build/transpile.js b/TaskServer/node_modules/ccxt/build/transpile.js index b55ffae59..10854e928 100644 --- a/TaskServer/node_modules/ccxt/build/transpile.js +++ b/TaskServer/node_modules/ccxt/build/transpile.js @@ -199,6 +199,7 @@ class Transpiler { [ /(^|[^a-zA-Z0-9_])(?:let|const|var)\s/g, '$1' ], [ /Object\.keys\s*\((.*)\)\.length/g, '$1' ], [ /Object\.keys\s*\((.*)\)/g, 'list($1.keys())' ], + [ /Object\.values\s*\((.*)\)/g, 'list($1.values())' ], [ /\[([^\]]+)\]\.join\s*\(([^\)]+)\)/g, "$2.join([$1])" ], [ /hash \(([^,]+)\, \'(sha[0-9])\'/g, "hash($1, '$2'" ], [ /hmac \(([^,]+)\, ([^,]+)\, \'(md5)\'/g, 'hmac($1, $2, hashlib.$3' ], @@ -330,6 +331,7 @@ class Transpiler { [ /(^|[^a-zA-Z0-9_])(?:let|const|var)\s/g, '$1' ], [ /Object\.keys\s*\((.*)\)\.length/g, '$1' ], [ /Object\.keys\s*\((.*)\)/g, 'is_array($1) ? array_keys($1) : array()' ], + [ /Object\.values\s*\((.*)\)/g, 'is_array($1) ? array_values($1) : array()' ], [ /([^\s]+\s*\(\))\.toString \(\)/g, '(string) $1' ], [ /([^\s]+)\.toString \(\)/g, '(string) $1' ], [ /throw new Error \((.*)\)/g, 'throw new \\Exception($1)' ], diff --git a/TaskServer/node_modules/ccxt/ccxt.js b/TaskServer/node_modules/ccxt/ccxt.js index 15b32440d..d6ed88a1f 100644 --- a/TaskServer/node_modules/ccxt/ccxt.js +++ b/TaskServer/node_modules/ccxt/ccxt.js @@ -35,7 +35,7 @@ const Exchange = require ('./js/base/Exchange') //----------------------------------------------------------------------------- // this is updated by vss.js when building -const version = '1.25.80' +const version = '1.27.45' Exchange.ccxtVersion = version @@ -44,7 +44,6 @@ Exchange.ccxtVersion = version const exchanges = { '_1btcxe': require ('./js/_1btcxe.js'), 'acx': require ('./js/acx.js'), - 'adara': require ('./js/adara.js'), 'anxpro': require ('./js/anxpro.js'), 'aofex': require ('./js/aofex.js'), 'bcex': require ('./js/bcex.js'), @@ -115,8 +114,8 @@ const exchanges = { 'fybse': require ('./js/fybse.js'), 'gateio': require ('./js/gateio.js'), 'gemini': require ('./js/gemini.js'), + 'hbtc': require ('./js/hbtc.js'), 'hitbtc': require ('./js/hitbtc.js'), - 'hitbtc2': require ('./js/hitbtc2.js'), 'hollaex': require ('./js/hollaex.js'), 'huobipro': require ('./js/huobipro.js'), 'huobiru': require ('./js/huobiru.js'), diff --git a/TaskServer/node_modules/ccxt/dist/ccxt.browser.js b/TaskServer/node_modules/ccxt/dist/ccxt.browser.js index 9ff7c58aa..acbb6ec4f 100644 --- a/TaskServer/node_modules/ccxt/dist/ccxt.browser.js +++ b/TaskServer/node_modules/ccxt/dist/ccxt.browser.js @@ -43,7 +43,7 @@ const Exchange = require ('./js/base/Exchange') //----------------------------------------------------------------------------- // this is updated by vss.js when building -const version = '1.25.80' +const version = '1.27.45' Exchange.ccxtVersion = version @@ -52,7 +52,6 @@ Exchange.ccxtVersion = version const exchanges = { '_1btcxe': require ('./js/_1btcxe.js'), 'acx': require ('./js/acx.js'), - 'adara': require ('./js/adara.js'), 'anxpro': require ('./js/anxpro.js'), 'aofex': require ('./js/aofex.js'), 'bcex': require ('./js/bcex.js'), @@ -123,8 +122,8 @@ const exchanges = { 'fybse': require ('./js/fybse.js'), 'gateio': require ('./js/gateio.js'), 'gemini': require ('./js/gemini.js'), + 'hbtc': require ('./js/hbtc.js'), 'hitbtc': require ('./js/hitbtc.js'), - 'hitbtc2': require ('./js/hitbtc2.js'), 'hollaex': require ('./js/hollaex.js'), 'huobipro': require ('./js/huobipro.js'), 'huobiru': require ('./js/huobiru.js'), @@ -178,7 +177,7 @@ module.exports = Object.assign ({ version, Exchange, 'exchanges': Object.keys (e //----------------------------------------------------------------------------- -},{"./js/_1btcxe.js":3,"./js/acx.js":4,"./js/adara.js":5,"./js/anxpro.js":6,"./js/aofex.js":7,"./js/base/Exchange":8,"./js/base/errors":10,"./js/base/functions":11,"./js/bcex.js":22,"./js/bequant.js":23,"./js/bibox.js":24,"./js/bigone.js":25,"./js/binance.js":26,"./js/binanceje.js":27,"./js/binanceus.js":28,"./js/bit2c.js":29,"./js/bitbank.js":30,"./js/bitbay.js":31,"./js/bitfinex.js":32,"./js/bitfinex2.js":33,"./js/bitflyer.js":34,"./js/bitforex.js":35,"./js/bithumb.js":36,"./js/bitkk.js":37,"./js/bitmart.js":38,"./js/bitmax.js":39,"./js/bitmex.js":40,"./js/bitso.js":41,"./js/bitstamp.js":42,"./js/bitstamp1.js":43,"./js/bittrex.js":44,"./js/bitz.js":45,"./js/bl3p.js":46,"./js/bleutrade.js":47,"./js/braziliex.js":48,"./js/btcalpha.js":49,"./js/btcbox.js":50,"./js/btcmarkets.js":51,"./js/btctradeim.js":52,"./js/btctradeua.js":53,"./js/btcturk.js":54,"./js/buda.js":55,"./js/bw.js":56,"./js/bybit.js":57,"./js/bytetrade.js":58,"./js/cex.js":59,"./js/chilebit.js":60,"./js/coinbase.js":61,"./js/coinbaseprime.js":62,"./js/coinbasepro.js":63,"./js/coincheck.js":64,"./js/coinegg.js":65,"./js/coinex.js":66,"./js/coinfalcon.js":67,"./js/coinfloor.js":68,"./js/coingi.js":69,"./js/coinmarketcap.js":70,"./js/coinmate.js":71,"./js/coinone.js":72,"./js/coinspot.js":73,"./js/coolcoin.js":74,"./js/coss.js":75,"./js/crex24.js":76,"./js/deribit.js":77,"./js/digifinex.js":78,"./js/dsx.js":79,"./js/exmo.js":80,"./js/exx.js":81,"./js/fcoin.js":82,"./js/fcoinjp.js":83,"./js/flowbtc.js":84,"./js/foxbit.js":85,"./js/ftx.js":86,"./js/fybse.js":87,"./js/gateio.js":88,"./js/gemini.js":89,"./js/hitbtc.js":90,"./js/hitbtc2.js":91,"./js/hollaex.js":92,"./js/huobipro.js":93,"./js/huobiru.js":94,"./js/ice3x.js":95,"./js/idex.js":96,"./js/independentreserve.js":97,"./js/indodax.js":98,"./js/itbit.js":99,"./js/kkex.js":100,"./js/kraken.js":101,"./js/kucoin.js":102,"./js/kuna.js":103,"./js/lakebtc.js":104,"./js/latoken.js":105,"./js/lbank.js":106,"./js/liquid.js":107,"./js/livecoin.js":108,"./js/luno.js":109,"./js/lykke.js":110,"./js/mercado.js":111,"./js/mixcoins.js":112,"./js/oceanex.js":113,"./js/okcoin.js":114,"./js/okex.js":115,"./js/paymium.js":116,"./js/poloniex.js":117,"./js/rightbtc.js":118,"./js/southxchange.js":119,"./js/stex.js":157,"./js/stronghold.js":158,"./js/surbitcoin.js":159,"./js/theocean.js":160,"./js/therock.js":161,"./js/tidebit.js":162,"./js/tidex.js":163,"./js/timex.js":164,"./js/topq.js":165,"./js/upbit.js":166,"./js/vaultoro.js":167,"./js/vbtc.js":168,"./js/whitebit.js":169,"./js/xbtce.js":170,"./js/yobit.js":171,"./js/zaif.js":172,"./js/zb.js":173}],3:[function(require,module,exports){ +},{"./js/_1btcxe.js":3,"./js/acx.js":4,"./js/anxpro.js":5,"./js/aofex.js":6,"./js/base/Exchange":7,"./js/base/errors":9,"./js/base/functions":10,"./js/bcex.js":21,"./js/bequant.js":22,"./js/bibox.js":23,"./js/bigone.js":24,"./js/binance.js":25,"./js/binanceje.js":26,"./js/binanceus.js":27,"./js/bit2c.js":28,"./js/bitbank.js":29,"./js/bitbay.js":30,"./js/bitfinex.js":31,"./js/bitfinex2.js":32,"./js/bitflyer.js":33,"./js/bitforex.js":34,"./js/bithumb.js":35,"./js/bitkk.js":36,"./js/bitmart.js":37,"./js/bitmax.js":38,"./js/bitmex.js":39,"./js/bitso.js":40,"./js/bitstamp.js":41,"./js/bitstamp1.js":42,"./js/bittrex.js":43,"./js/bitz.js":44,"./js/bl3p.js":45,"./js/bleutrade.js":46,"./js/braziliex.js":47,"./js/btcalpha.js":48,"./js/btcbox.js":49,"./js/btcmarkets.js":50,"./js/btctradeim.js":51,"./js/btctradeua.js":52,"./js/btcturk.js":53,"./js/buda.js":54,"./js/bw.js":55,"./js/bybit.js":56,"./js/bytetrade.js":57,"./js/cex.js":58,"./js/chilebit.js":59,"./js/coinbase.js":60,"./js/coinbaseprime.js":61,"./js/coinbasepro.js":62,"./js/coincheck.js":63,"./js/coinegg.js":64,"./js/coinex.js":65,"./js/coinfalcon.js":66,"./js/coinfloor.js":67,"./js/coingi.js":68,"./js/coinmarketcap.js":69,"./js/coinmate.js":70,"./js/coinone.js":71,"./js/coinspot.js":72,"./js/coolcoin.js":73,"./js/coss.js":74,"./js/crex24.js":75,"./js/deribit.js":76,"./js/digifinex.js":77,"./js/dsx.js":78,"./js/exmo.js":79,"./js/exx.js":80,"./js/fcoin.js":81,"./js/fcoinjp.js":82,"./js/flowbtc.js":83,"./js/foxbit.js":84,"./js/ftx.js":85,"./js/fybse.js":86,"./js/gateio.js":87,"./js/gemini.js":88,"./js/hbtc.js":89,"./js/hitbtc.js":90,"./js/hollaex.js":91,"./js/huobipro.js":92,"./js/huobiru.js":93,"./js/ice3x.js":94,"./js/idex.js":95,"./js/independentreserve.js":96,"./js/indodax.js":97,"./js/itbit.js":98,"./js/kkex.js":99,"./js/kraken.js":100,"./js/kucoin.js":101,"./js/kuna.js":102,"./js/lakebtc.js":103,"./js/latoken.js":104,"./js/lbank.js":105,"./js/liquid.js":106,"./js/livecoin.js":107,"./js/luno.js":108,"./js/lykke.js":109,"./js/mercado.js":110,"./js/mixcoins.js":111,"./js/oceanex.js":112,"./js/okcoin.js":113,"./js/okex.js":114,"./js/paymium.js":115,"./js/poloniex.js":116,"./js/rightbtc.js":117,"./js/southxchange.js":118,"./js/stex.js":156,"./js/stronghold.js":157,"./js/surbitcoin.js":158,"./js/theocean.js":159,"./js/therock.js":160,"./js/tidebit.js":161,"./js/tidex.js":162,"./js/timex.js":163,"./js/topq.js":164,"./js/upbit.js":165,"./js/vaultoro.js":166,"./js/vbtc.js":167,"./js/whitebit.js":168,"./js/xbtce.js":169,"./js/yobit.js":170,"./js/zaif.js":171,"./js/zb.js":172}],3:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -485,7 +484,7 @@ module.exports = class _1btcxe extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10}],4:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9}],4:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -960,1264 +959,7 @@ module.exports = class acx extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10}],5:[function(require,module,exports){ -'use strict'; - -// --------------------------------------------------------------------------- - -const Exchange = require ('./base/Exchange'); -const { ExchangeError, BadRequest, AuthenticationError, InvalidOrder, InsufficientFunds, OrderNotFound } = require ('./base/errors'); - -// --------------------------------------------------------------------------- - -module.exports = class adara extends Exchange { - describe () { - return this.deepExtend (super.describe (), { - 'id': 'adara', - 'name': 'Adara', - 'countries': [ 'MT' ], - 'version': 'v1', - 'rateLimit': 1000, - 'certified': false, - // new metainfo interface - 'has': { - 'CORS': false, - 'fetchCurrencies': true, - 'fetchOrderBooks': false, - 'createMarketOrder': false, - 'fetchDepositAddress': false, - 'fetchClosedOrders': true, - 'fetchMyTrades': false, - 'fetchOHLCV': false, - 'fetchOrder': true, - 'fetchOpenOrders': true, - 'fetchTickers': true, - 'withdraw': false, - 'fetchDeposits': false, - 'fetchWithdrawals': false, - 'fetchTransactions': false, - }, - 'requiredCredentials': { - 'apiKey': true, - 'secret': true, - 'token': false, - }, - 'urls': { - 'logo': 'https://user-images.githubusercontent.com/1294454/49189583-0466a780-f380-11e8-9248-57a631aad2d6.jpg', - 'api': 'https://api.adara.io', - 'www': 'https://adara.io', - 'doc': 'https://api.adara.io/v1', - 'fees': 'https://adara.io/fees', - }, - 'api': { - 'public': { - 'get': [ - 'currencies', - 'limits', - 'market', - 'marketDepth', - 'marketInfo', - 'orderBook', - 'quote/', - 'quote/{id}', - 'symbols', - 'trade', - ], - 'post': [ - 'confirmContactEmail', - 'restorePassword', - 'user', // sign up - ], - }, - 'private': { - 'get': [ - 'balance', - 'order', - 'order/{id}', - 'currencyBalance', - 'apiKey', // the list of apiKeys - 'user/{id}', - ], - 'post': [ - 'order', - 'recovery', - 'user', - 'apiKey', // sign in and optionally create an apiKey - 'contact', - ], - 'patch': [ - 'order/{id}', - 'user/{id}', // change password - 'customer', // update user info - ], - 'delete': [ - 'apiKey', - ], - }, - }, - 'fees': { - 'trading': { - 'tierBased': false, - 'percentage': true, - 'maker': 0.001, - 'taker': 0.001, - }, - 'funding': { - 'tierBased': false, - 'percentage': false, - 'withdraw': {}, - 'deposit': {}, - }, - }, - 'exceptions': { - 'exact': { - 'Insufficient funds': InsufficientFunds, - 'Amount is too small': InvalidOrder, - 'operation has invalid value': InvalidOrder, - "closed order can't be changed": InvalidOrder, - 'Order is not found': OrderNotFound, - 'AUTH': AuthenticationError, - 'You are not authorized': AuthenticationError, - 'Bad Request': BadRequest, - '500': ExchangeError, - }, - 'broad': {}, - }, - }); - } - - async fetchMarkets (params = {}) { - const request = { - 'include': 'from,to', - }; - const response = await this.publicGetSymbols (this.extend (request, params)); - const included = this.safeValue (response, 'included', []); - const includedByType = this.groupBy (included, 'type'); - const currencies = this.safeValue (includedByType, 'currency', []); - const currenciesById = this.indexBy (currencies, 'id'); - // - // { meta: { total: 61 }, - // data: [ { id: "XRPUSD", - // type: "symbol", - // attributes: { allowTrade: false, - // createdAt: "2018-10-23T09:31:06.830Z", - // digits: 5, - // fullName: "XRPUSD", - // makerFee: "0.0250", - // name: "XRPUSD", - // takerFee: "0.0250", - // updatedAt: "2018-10-23T09:31:06.830Z" }, - // relationships: { from: { data: { id: "XRP", type: "currency" } }, - // to: { data: { id: "USD", type: "currency" } } } }, - // { id: "XRPETH", - // type: "symbol", - // attributes: { allowTrade: true, - // createdAt: "2018-10-09T22:34:28.268Z", - // digits: 8, - // fullName: "XRPETH", - // makerFee: "0.0025", - // name: "XRPETH", - // takerFee: "0.0025", - // updatedAt: "2018-10-09T22:34:28.268Z" }, - // relationships: { from: { data: { id: "XRP", type: "currency" } }, - // to: { data: { id: "ETH", type: "currency" } } } } ], - // included: [ { id: "XRP", - // type: "currency", - // attributes: { accuracy: 4, - // active: true, - // allowDeposit: true, - // allowTrade: false, - // allowWallet: true, - // allowWithdraw: true, - // name: "Ripple", - // shortName: "XRP", - // transactionUriTemplate: "https://www.ripplescan.com/transactions/:txId", - // walletUriTemplate: "https://www.ripplescan.com/accounts/:address", - // withdrawFee: "0.20000000", - // withdrawMinAmount: "22.00000000" }, - // relationships: { } }, - // { id: "ETH", - // type: "currency", - // attributes: { accuracy: 8, - // active: true, - // allowDeposit: true, - // allowTrade: true, - // allowWallet: true, - // allowWithdraw: true, - // name: "Ethereum", - // shortName: "ETH", - // transactionUriTemplate: "https://etherscan.io/tx/:txId", - // walletUriTemplate: "https://etherscan.io/address/:address", - // withdrawFee: "0.00800000", - // withdrawMinAmount: "0.02000000" }, - // relationships: { } }, - // { id: "USD", - // type: "currency", - // attributes: { accuracy: 6, - // active: true, - // allowDeposit: false, - // allowTrade: true, - // allowWallet: false, - // allowWithdraw: false, - // name: "USD", - // shortName: "USD", - // transactionUriTemplate: null, - // walletUriTemplate: null, - // withdrawFee: "0.00000000", - // withdrawMinAmount: "0.00000000" }, - // relationships: { } } ] } - // - const result = []; - const markets = response['data']; - for (let i = 0; i < markets.length; i++) { - const market = markets[i]; - const id = this.safeString (market, 'id'); - const attributes = this.safeValue (market, 'attributes', {}); - const relationships = this.safeValue (market, 'relationships', {}); - const fromRelationship = this.safeValue (relationships, 'from', {}); - const toRelationship = this.safeValue (relationships, 'to', {}); - const fromRelationshipData = this.safeValue (fromRelationship, 'data', {}); - const toRelationshipData = this.safeValue (toRelationship, 'data', {}); - const baseId = this.safeString (fromRelationshipData, 'id'); - const quoteId = this.safeString (toRelationshipData, 'id'); - const base = this.commonCurrencyCode (baseId); - const quote = this.commonCurrencyCode (quoteId); - const baseCurrency = this.safeValue (currenciesById, baseId, {}); - const baseCurrencyAttributes = this.safeValue (baseCurrency, 'attributes', {}); - const symbol = base + '/' + quote; - const amountPrecision = this.safeInteger (baseCurrencyAttributes, 'accuracy', 8); - const pricePrecision = this.safeInteger (attributes, 'digits', 8); - const precision = { - 'amount': amountPrecision, - 'price': pricePrecision, - }; - const active = this.safeValue (attributes, 'allowTrade'); - const maker = this.safeFloat (attributes, 'makerFee'); - const taker = this.safeFloat (attributes, 'takerFee'); - result.push ({ - 'info': market, - 'id': id, - 'symbol': symbol, - 'base': base, - 'quote': quote, - 'baseId': baseId, - 'quoteId': quoteId, - 'active': active, - 'maker': maker, - 'taker': taker, - 'precision': precision, - 'limits': { - 'amount': { - 'min': Math.pow (10, -precision['amount']), - 'max': undefined, - }, - 'price': { - 'min': Math.pow (10, -precision['price']), - 'max': undefined, - }, - 'cost': { - 'min': undefined, - 'max': undefined, - }, - }, - }); - } - return result; - } - - async fetchCurrencies (params = {}) { - const response = await this.publicGetCurrencies (params); - // - // { meta: { total: 22 }, - // data: [ { id: "USD", - // type: "currency", - // attributes: { accuracy: 6, - // active: true, - // allowDeposit: false, - // allowTrade: true, - // allowWallet: false, - // allowWithdraw: false, - // name: "USD", - // shortName: "USD", - // transactionUriTemplate: null, - // walletUriTemplate: null, - // withdrawFee: "0.00000000", - // withdrawMinAmount: "0.00000000" }, - // relationships: { } }, - // { id: "BTC", - // type: "currency", - // attributes: { accuracy: 8, - // active: true, - // allowDeposit: true, - // allowTrade: true, - // allowWallet: true, - // allowWithdraw: true, - // name: "Bitcoin", - // shortName: "BTC", - // transactionUriTemplate: "https://blockexplorer.com/tx/:txId", - // walletUriTemplate: "https://blockexplorer.com/address/:address", - // withdrawFee: "0.00050000", - // withdrawMinAmount: "0.00200000" }, - // relationships: { } } ], - // included: [] } - // - const currencies = response['data']; - const result = {}; - for (let i = 0; i < currencies.length; i++) { - const currency = currencies[i]; - const id = this.safeString (currency, 'id'); - const attributes = this.safeValue (currency, 'attributes', {}); - const code = this.commonCurrencyCode (id); - const precision = this.safeInteger (attributes, 'accuracy'); - const fee = this.safeFloat (attributes, 'withdrawFee'); - const active = this.safeValue (attributes, 'active'); - const allowDeposit = this.safeValue (attributes, 'allowDeposit'); - const allowWithdraw = this.safeValue (attributes, 'allowWithdraw'); - result[code] = { - 'id': id, - 'code': code, - 'info': currency, - 'name': this.safeString (attributes, 'name'), - 'active': (active && allowDeposit && allowWithdraw), - 'fee': fee, - 'precision': precision, - 'limits': { - 'amount': { - 'min': Math.pow (10, -precision), - 'max': Math.pow (10, precision), - }, - 'price': { - 'min': Math.pow (10, -precision), - 'max': Math.pow (10, precision), - }, - 'cost': { - 'min': undefined, - 'max': undefined, - }, - 'withdraw': { - 'min': this.safeFloat (attributes, 'withdrawMinAmount'), - 'max': Math.pow (10, precision), - }, - }, - }; - } - return result; - } - - async fetchBalance (params = {}) { - await this.loadMarkets (); - const response = await this.privateGetBalance (params); - // - // { data: [ { type: "balance", - // id: "U4f0f0940-39bf-45a8-90bc-12d2899db4f1_BALANCE_FOR_ETH", - // attributes: { totalBalance: 10000, - // onOrders: 0, - // normalizedTotalBalance: 310, - // normalizedOnOrders: 0, - // percentage: 3.004116443856034, - // serializedAt: 1543324487949 }, - // relationships: { currency: { data: { type: "currency", id: "ETH" } }, - // normalizedCurrency: { data: { type: "currency", id: "BTC" } } } } ], - // included: [ { type: "currency", - // id: "BTC", - // attributes: { name: "Bitcoin", - // shortName: "BTC", - // active: true, - // accuracy: 8, - // allowDeposit: true, - // allowWithdraw: true, - // allowWallet: true, - // allowTrade: true, - // serializedAt: 1543324487948 }, - // relationships: { } }, - // { type: "currency", - // id: "ETH", - // attributes: { name: "Ethereum", - // shortName: "ETH", - // active: true, - // accuracy: 8, - // allowDeposit: true, - // allowWithdraw: true, - // allowWallet: true, - // allowTrade: true, - // serializedAt: 1543324487948 } } ] } - // - const result = { 'info': response }; - const data = this.safeValue (response, 'data'); - if (data !== undefined) { - for (let i = 0; i < data.length; i++) { - const balance = data[i]; - const attributes = this.safeValue (balance, 'attributes', {}); - const relationships = this.safeValue (balance, 'relationships', {}); - const currencyRelationship = this.safeValue (relationships, 'currency', {}); - const currencyRelationshipData = this.safeValue (currencyRelationship, 'data'); - const currencyId = this.safeString (currencyRelationshipData, 'id'); - const code = this.commonCurrencyCode (currencyId); - const account = this.account (); - account['total'] = this.safeFloat (attributes, 'totalBalance'); - account['used'] = this.safeFloat (attributes, 'onOrders'); - result[code] = account; - } - } - return this.parseBalance (result); - } - - getSymbolFromMarketId (marketId, market = undefined) { - if (marketId === undefined) { - return undefined; - } - market = this.safeValue (this.markets_by_id, marketId, market); - if (market !== undefined) { - return market['symbol']; - } - const [ baseId, quoteId ] = marketId.split ('-'); - const base = this.commonCurrencyCode (baseId); - const quote = this.commonCurrencyCode (quoteId); - return base + '/' + quote; - } - - parseOrderBook (orderbook, timestamp = undefined, bidsKey = 'bids', asksKey = 'asks', priceKey = 'price', amountKey = 'amount') { - const bids = []; - const asks = []; - const numBidAsks = orderbook.length; - if (numBidAsks > 0) { - timestamp = this.safeInteger (orderbook[0]['attributes'], 'serializedAt'); - } - for (let i = 0; i < orderbook.length; i++) { - const bidask = orderbook[i]; - const attributes = this.safeValue (bidask, 'attributes', {}); - const currenTimestamp = this.safeInteger (attributes, 'serializedAt'); - timestamp = Math.max (timestamp, currenTimestamp); - const id = this.safeString (bidask, 'id'); - if (id.indexOf ('OBID') >= 0) { - bids.push (this.parseBidAsk (bidask['attributes'], priceKey, amountKey)); - } else if (id.indexOf ('OSID') >= 0) { - asks.push (this.parseBidAsk (bidask['attributes'], priceKey, amountKey)); - } else { - throw new ExchangeError (this.id + ' parseOrderBook encountered an unrecognized bidask format: ' + this.json (bidask)); - } - } - return { - 'bids': this.sortBy (bids, 0, true), - 'asks': this.sortBy (asks, 0), - 'timestamp': timestamp, - 'datetime': this.iso8601 (timestamp), - 'nonce': undefined, - }; - } - - async fetchOrderBook (symbol, limit = undefined, params = {}) { - await this.loadMarkets (); - const market = this.market (symbol); - const filters = 'filters[symbol]'; - const request = {}; - request[filters] = market['id']; - const response = await this.publicGetOrderBook (this.extend (request, params)); - // - // { data: [ { type: "orderBook", - // id: "OBID0SLTCETHS0", - // attributes: { price: 1, - // amount: 4, - // serializedAt: 1543116143473 } }, - // { type: "orderBook", - // id: "OSID3SLTCETHS0", - // attributes: { price: 12, - // amount: 12, - // serializedAt: 1543116143474 } } ] } - // - return this.parseOrderBook (response['data'], undefined, 'bids', 'asks', 'price', 'amount'); - } - - parseTicker (ticker, market = undefined) { - // - // { type: "quote", - // id: "XRPETH", - // attributes: { currentPrice: 1, - // low: 1, - // high: 1, - // baseVolume: 0, - // quoteVolume: 0, - // change: 0, - // percentChange: 0, - // serializedAt: 1543109275996 }, - // relationships: { symbol: { data: { type: "symbol", id: "ETHBTC" } } } } - // - const symbol = this.getSymbolFromMarketId (this.safeString (ticker, 'id'), market); - const attributes = this.safeValue (ticker, 'attributes', {}); - const timestamp = this.safeInteger (attributes, 'serializedAt'); - const last = this.safeFloat (attributes, 'currentPrice'); - const change = this.safeFloat (attributes, 'change'); - let open = undefined; - if (change !== undefined) { - if (last !== undefined) { - open = last - change; - } - } - const percentage = this.safeFloat (attributes, 'percentChange'); - return { - 'symbol': symbol, - 'timestamp': timestamp, - 'datetime': this.iso8601 (timestamp), - 'high': this.safeFloat (attributes, 'high'), - 'low': this.safeFloat (attributes, 'low'), - 'bid': undefined, - 'bidVolume': undefined, - 'ask': undefined, - 'askVolume': undefined, - 'vwap': undefined, - 'open': open, - 'close': last, - 'last': last, - 'previousClose': undefined, - 'change': change, - 'percentage': percentage, - 'average': undefined, - 'baseVolume': this.safeFloat (ticker, 'baseVolume'), - 'quoteVolume': this.safeFloat (ticker, 'quoteVolume'), - 'info': ticker, - }; - } - - async fetchTickers (symbols = undefined, params = {}) { - await this.loadMarkets (); - const response = await this.publicGetQuote (params); - const data = this.safeValue (response, 'data', []); - // - // { data: [ { type: "quote", - // id: "XRPETH", - // attributes: { currentPrice: 1, - // low: 1, - // high: 1, - // baseVolume: 0, - // quoteVolume: 0, - // change: 0, - // percentChange: 0, - // serializedAt: 1543109275996 }, - // relationships: { symbol: { data: { type: "symbol", id: "ETHBTC" } } } } ], - // included: [ { type: "currency", - // id: "XRP", - // attributes: { name: "Ripple", - // shortName: "XRP", - // active: true, - // accuracy: 4, - // allowDeposit: true, - // allowWithdraw: true, - // allowWallet: true, - // allowTrade: false, - // serializedAt: 1543109275996 }, - // relationships: { } }, - // { type: "symbol", - // id: "XRPETH", - // attributes: { fullName: "XRPETH", - // digits: 8, - // allowTrade: true, - // serializedAt: 1543109275996 }, - // relationships: { from: { data: { type: "currency", id: "XRP" } }, - // to: { data: { type: "currency", id: "ETH" } } } } ] } - // - const result = {}; - for (let t = 0; t < data.length; t++) { - const ticker = this.parseTicker (data[t]); - const symbol = ticker['symbol']; - result[symbol] = ticker; - } - return result; - } - - async fetchTicker (symbol, params = {}) { - await this.loadMarkets (); - const market = this.market (symbol); - const request = { - 'id': market['id'], - }; - const response = await this.publicGetQuoteId (this.extend (request, params)); - // - // { included: [ { type: "currency", - // id: "ETH", - // attributes: { name: "Ethereum", - // shortName: "ETH", - // active: true, - // accuracy: 8, - // allowDeposit: true, - // allowWithdraw: true, - // allowWallet: true, - // allowTrade: true, - // serializedAt: 1543111444033 } }, - // { type: "currency", - // id: "BTC", - // attributes: { name: "Bitcoin", - // shortName: "BTC", - // active: true, - // accuracy: 8, - // allowDeposit: true, - // allowWithdraw: true, - // allowWallet: true, - // allowTrade: true, - // serializedAt: 1543111444033 } }, - // { type: "symbol", - // id: "ETHBTC", - // attributes: { fullName: "ETHBTC", - // digits: 6, - // allowTrade: true, - // serializedAt: 1543111444033 }, - // relationships: { from: { data: { type: "currency", id: "ETH" } }, - // to: { data: { type: "currency", id: "BTC" } } } } ], - // data: { type: "quote", - // id: "ETHBTC", - // attributes: { currentPrice: 34, - // low: 34, - // high: 34, - // baseVolume: 0, - // quoteVolume: 0, - // change: 0, - // percentChange: 0, - // serializedAt: 1543111444033 }, - // relationships: { symbol: { data: { type: "symbol", id: "ETHBTC" } } } } } (fetchTicker @ adara.js:546) - // - return this.parseTicker (response['data']); - } - - parseTrade (trade, market = undefined) { - // - // fetchTrades - // - // - // { type: "trade", - // id: "1542988964359136846136847", - // attributes: { price: 34, - // amount: 4, - // total: 136, - // operation: "buy", - // createdAt: "2018-11-23T16:02:44.359Z", - // serializedAt: 1543112364995 }, - // relationships: { symbol: { data: { type: "symbol", id: "ETHBTC" } } } } ], - // - const id = this.safeString (trade, 'id', 'uuid'); - const attributes = this.safeValue (trade, 'attributes', {}); - const relationships = this.safeValue (trade, 'relationships', {}); - const symbolRelationship = this.safeValue (relationships, 'symbol', {}); - const symbolRelationshipData = this.safeValue (symbolRelationship, 'data', {}); - const marketId = this.safeString (symbolRelationshipData, 'id'); - market = this.safeValue (this.markets_by_id, marketId, market); - let symbol = undefined; - let feeCurrency = undefined; - if (market !== undefined) { - symbol = market['symbol']; - feeCurrency = market['quote']; - } else if (marketId !== undefined) { - const baseIdLength = marketId.length - 3; - const baseId = marketId.slice (0, baseIdLength); - const quoteId = marketId.slice (baseIdLength); - const base = this.commonCurrencyCode (baseId); - const quote = this.commonCurrencyCode (quoteId); - symbol = base + '/' + quote; - feeCurrency = quote; - } - const orderId = undefined; - const timestamp = this.parse8601 (this.safeString (attributes, 'createdAt')); - const side = this.safeString (attributes, 'operation'); - const price = this.safeFloat (attributes, 'price'); - const amount = this.safeFloat (attributes, 'amount'); - let cost = this.safeFloat (attributes, 'total'); - if (cost === undefined) { - if (amount !== undefined) { - if (price !== undefined) { - cost = parseFloat (this.costToPrecision (symbol, price * amount)); - } - } - } - const feeCost = this.safeFloat (attributes, 'fee'); - let fee = undefined; - if (feeCost !== undefined) { - fee = { - 'cost': feeCost, - 'currency': feeCurrency, - }; - } - return { - 'id': id, - 'info': trade, - 'order': orderId, - 'timestamp': timestamp, - 'datetime': this.iso8601 (timestamp), - 'symbol': symbol, - 'type': undefined, - 'side': side, - 'takerOrMaker': undefined, - 'price': price, - 'amount': amount, - 'cost': cost, - 'fee': fee, - }; - } - - async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) { - await this.loadMarkets (); - let market = undefined; - if (symbol !== undefined) { - market = this.market (symbol); - } - const request = { - // 'id': market['id'], - }; - const response = await this.publicGetTrade (this.extend (request, params)); - // - // { data: [ { type: "trade", - // id: "1542988964359136846136847", - // attributes: { price: 34, - // amount: 4, - // total: 136, - // operation: "buy", - // createdAt: "2018-11-23T16:02:44.359Z", - // serializedAt: 1543112364995 }, - // relationships: { symbol: { data: { type: "symbol", id: "ETHBTC" } } } } ], - // included: [ { type: "currency", - // id: "ETH", - // attributes: { name: "Ethereum", - // shortName: "ETH", - // active: true, - // accuracy: 8, - // allowDeposit: true, - // allowWithdraw: true, - // allowWallet: true, - // allowTrade: true, - // serializedAt: 1543112364995 }, - // relationships: { } }, - // { type: "currency", - // id: "BTC", - // attributes: { name: "Bitcoin", - // ... - // serializedAt: 1543112364995 }, - // relationships: { } }, - // { type: "symbol", - // id: "ETHBTC", - // attributes: { fullName: "ETHBTC", - // digits: 6, - // allowTrade: true, - // serializedAt: 1543112364995 }, - // relationships: { from: { data: { type: "currency", id: "ETH" } }, - // to: { data: { type: "currency", id: "BTC" } } } } } - // - return this.parseTrades (response['data'], market, since, limit); - } - - async createOrder (symbol, type, side, amount, price = undefined, params = {}) { - await this.loadMarkets (); - const market = this.market (symbol); - const request = { - 'data': { - 'type': 'order', - 'attributes': { - 'amount': parseFloat (this.amountToPrecision (symbol, amount)), - 'operation': side, - 'orderType': type, - 'price': parseFloat (this.priceToPrecision (symbol, price)), - }, - 'relationships': { - 'symbol': { - 'data': { - 'id': market['id'], - 'type': 'symbol', - }, - }, - }, - }, - 'included': [ - { - 'id': market['id'], - 'type': 'symbol', - }, - ], - }; - const response = await this.privatePostOrder (this.extend (request, params)); - // - // { included: [ { type: "currency", - // id: "XLM", - // attributes: { name: "Stellar", - // shortName: "XLM", - // active: true, - // accuracy: 8, - // allowDeposit: true, - // allowWithdraw: true, - // allowWallet: true, - // allowTrade: false, - // serializedAt: 1543434477449 } }, - // { type: "currency", - // id: "BTC", - // attributes: { name: "Bitcoin", - // shortName: "BTC", - // active: true, - // accuracy: 8, - // allowDeposit: true, - // allowWithdraw: true, - // allowWallet: true, - // allowTrade: true, - // serializedAt: 1543434477449 } }, - // { type: "symbol", - // id: "XLMBTC", - // attributes: { fullName: "XLMBTC", - // digits: 6, - // allowTrade: true, - // serializedAt: 1543434477449 }, - // relationships: { from: { data: { type: "currency", id: "XLM" } }, - // to: { data: { type: "currency", id: "BTC" } } } } ], - // data: { type: "order", - // id: "34793", - // attributes: { serializedAt: 1543434477449, - // operation: "buy", - // orderType: "limit", - // clientId: "4733ea40-7d5c-4ddc-aec5-eb41baf90555", - // amount: 220, - // price: 0.000035, - // averagePrice: 0, - // fee: 0, - // timeOpen: "2018-11-28T19:47:57.435Z", - // timeClose: null, - // status: "open", - // filled: 0, - // flags: [] }, - // relationships: { symbol: { data: { type: "symbol", id: "XLMBTC" } } } } } - // - return this.parseOrder (response['data']); - } - - async cancelOrder (id, symbol = undefined, params = {}) { - await this.loadMarkets (); - const request = { - 'id': id, - 'data': { - 'attributes': { - 'status': 'canceled', - }, - }, - }; - const response = await this.privatePatchOrderId (this.extend (request, params)); - // - // { included: [ { type: "currency", - // id: "XLM", - // attributes: { name: "Stellar", - // shortName: "XLM", - // active: true, - // accuracy: 8, - // allowDeposit: true, - // allowWithdraw: true, - // allowWallet: true, - // allowTrade: false, - // serializedAt: 1543437874742 } }, - // { type: "currency", - // id: "BTC", - // attributes: { name: "Bitcoin", - // shortName: "BTC", - // active: true, - // accuracy: 8, - // allowDeposit: true, - // allowWithdraw: true, - // allowWallet: true, - // allowTrade: true, - // serializedAt: 1543437874742 } }, - // { type: "symbol", - // id: "XLMBTC", - // attributes: { fullName: "XLMBTC", - // digits: 6, - // allowTrade: true, - // serializedAt: 1543437874742 }, - // relationships: { from: { data: { type: "currency", id: "XLM" } }, - // to: { data: { type: "currency", id: "BTC" } } } } ], - // data: { type: "order", - // id: "34794", - // attributes: { serializedAt: 1543437874742, - // operation: "buy", - // orderType: "limit", - // clientId: "4733ea40-7d5c-4ddc-aec5-eb41baf90555", - // amount: 110, - // price: 0.000034, - // averagePrice: 0, - // fee: 0, - // timeOpen: "2018-11-28T20:42:35.486Z", - // timeClose: null, - // status: "canceled", - // filled: 0, - // flags: [] }, - // relationships: { symbol: { data: { type: "symbol", id: "XLMBTC" } } } } } - // - return this.parseOrder (response['data']); - } - - parseOrderStatus (status) { - const statuses = { - 'open': 'open', - 'closed': 'closed', - 'canceled': 'canceled', - }; - return this.safeString (statuses, status, status); - } - - parseOrder (order, market = undefined) { - // - // { type: "order", - // id: "34793", - // attributes: { serializedAt: 1543435013349, - // operation: "buy", - // orderType: "limit", - // clientId: "4733ea40-7d5c-4ddc-aec5-eb41baf90555", - // amount: 220, - // price: 0.000035, - // averagePrice: 0.000035, - // fee: 0.0001925, - // timeOpen: "2018-11-28T19:47:57.435Z", - // timeClose: "2018-11-28T19:47:57.452Z", - // status: "closed", - // filled: 220, - // flags: null }, - // relationships: { symbol: { data: { type: "symbol", id: "XLMBTC" } } } } - // - const id = this.safeString (order, 'id'); - const attributes = this.safeValue (order, 'attributes', {}); - const relationships = this.safeValue (order, 'relationships', {}); - const symbolRelationship = this.safeValue (relationships, 'symbol', {}); - const symbolRelationshipData = this.safeValue (symbolRelationship, 'data', {}); - const tradesRelationship = this.safeValue (relationships, 'trades', {}); - const tradesRelationshipData = this.safeValue (tradesRelationship, 'data'); - const marketId = this.safeString (symbolRelationshipData, 'id'); - market = this.safeValue (this.markets_by_id, marketId, market); - let feeCurrency = undefined; - let symbol = undefined; - if (market !== undefined) { - symbol = market['symbol']; - feeCurrency = market['quote']; - } else if (marketId !== undefined) { - const baseIdLength = marketId.length - 3; - const baseId = marketId.slice (0, baseIdLength); - const quoteId = marketId.slice (baseIdLength); - const base = this.commonCurrencyCode (baseId); - const quote = this.commonCurrencyCode (quoteId); - symbol = base + '/' + quote; - feeCurrency = quote; - } - const timestamp = this.parse8601 (this.safeString (attributes, 'timeOpen')); - const side = this.safeString (attributes, 'operation'); - const type = this.safeString (attributes, 'orderType'); - const status = this.parseOrderStatus (this.safeString (attributes, 'status')); - const lastTradeTimestamp = this.parse8601 (this.safeString (attributes, 'timeClose')); - const price = this.safeFloat (attributes, 'price'); - const amount = this.safeFloat (attributes, 'amount'); - const filled = this.safeFloat (attributes, 'filled'); - let remaining = undefined; - if (amount !== undefined) { - if (filled !== undefined) { - remaining = Math.max (0, amount - filled); - } - } - let cost = undefined; - const average = this.safeFloat (attributes, 'averagePrice'); - if (cost === undefined) { - if ((average !== undefined) && (filled !== undefined)) { - cost = parseFloat (this.costToPrecision (symbol, average * filled)); - } - } - let fee = undefined; - const feeCost = this.safeFloat (attributes, 'fee'); - if (feeCost !== undefined) { - fee = { - 'currency': feeCurrency, - 'cost': feeCost, - }; - } - let trades = undefined; - if (tradesRelationshipData !== undefined) { - const numTrades = tradesRelationshipData.length; - if (numTrades > 0) { - trades = this.parseTrades (tradesRelationshipData, market); - } - } - const result = { - 'info': order, - 'id': id, - 'clientOrderId': undefined, - 'timestamp': timestamp, - 'datetime': this.iso8601 (timestamp), - 'lastTradeTimestamp': lastTradeTimestamp, - 'symbol': symbol, - 'type': type, - 'side': side, - 'price': price, - 'cost': cost, - 'average': average, - 'amount': amount, - 'filled': filled, - 'remaining': remaining, - 'status': status, - 'fee': fee, - 'trades': trades, - }; - return result; - } - - async fetchOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) { - await this.loadMarkets (); - const request = { - 'include': 'trades', - }; - let market = undefined; - if (symbol !== undefined) { - market = this.market (symbol); - const filters = 'filters[symbol]'; - request[filters] = market['id']; - } - const response = await this.privateGetOrder (this.extend (request, params)); - // - // { data: [ { type: "order", - // id: "34793", - // attributes: { serializedAt: 1543436770259, - // operation: "buy", - // orderType: "limit", - // amount: 220, - // price: 0.000035, - // averagePrice: 0.000035, - // fee: 0.0001925, - // timeOpen: "2018-11-28T19:47:57.435Z", - // timeClose: "2018-11-28T19:47:57.452Z", - // status: "closed", - // filled: 220, - // flags: null }, - // relationships: { symbol: { data: { type: "symbol", id: "XLMBTC" } }, - // trades: { data: [{ type: "trade", id: "34789_34793" }] } } } ], - // included: [ { type: "currency", - // id: "XLM", - // attributes: { name: "Stellar", - // shortName: "XLM", - // active: true, - // accuracy: 8, - // allowDeposit: true, - // allowWithdraw: true, - // allowWallet: true, - // allowTrade: false, - // serializedAt: 1543436770259 } }, - // { type: "currency", - // id: "BTC", - // attributes: { name: "Bitcoin", - // shortName: "BTC", - // active: true, - // accuracy: 8, - // allowDeposit: true, - // allowWithdraw: true, - // allowWallet: true, - // allowTrade: true, - // serializedAt: 1543436770259 } }, - // { type: "symbol", - // id: "XLMBTC", - // attributes: { fullName: "XLMBTC", - // digits: 6, - // allowTrade: true, - // serializedAt: 1543436770259 }, - // relationships: { from: { data: { type: "currency", id: "XLM" } }, - // to: { data: { type: "currency", id: "BTC" } } } }, - // { type: "trade", - // id: "34789_34793", - // attributes: { fee: 0.0001925, - // price: 0.000035, - // amount: 220, - // total: 0.0077, - // operation: "buy", - // createdAt: "2018-11-28T19:47:57.451Z" } } ], - // meta: { total: 1 } } - // - return this.parseOrdersResponse (response, market, since, limit); - } - - async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) { - const filters = 'filters[status][]'; - const request = {}; - request[filters] = 'open'; - return await this.fetchOrders (symbol, since, limit, this.extend (request, params)); - } - - async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) { - const filters = 'filters[status][]'; - const request = {}; - request[filters] = 'closed'; - return await this.fetchOrders (symbol, since, limit, this.extend (request, params)); - } - - parseOrdersResponse (response, market = undefined, since = undefined, limit = undefined) { - const included = this.safeValue (response, 'included', []); - const includedByType = this.groupBy (included, 'type'); - const unparsedTrades = this.safeValue (includedByType, 'trade', []); - const trades = this.parseTrades (unparsedTrades, market); - const tradesById = this.indexBy (trades, 'id'); - const orders = this.parseOrders (this.safeValue (response, 'data', []), market, since, limit); - const result = []; - for (let i = 0; i < orders.length; i++) { - const order = orders[i]; - const orderTrades = []; - const orderFee = this.safeValue (order, 'fee', {}); - const orderFeeCurrency = this.safeString (orderFee, 'currency'); - if (order['trades'] !== undefined) { - for (let j = 0; j < order['trades'].length; j++) { - const orderTrade = order['trades'][j]; - const orderTradeId = orderTrade['id']; - if (orderTradeId in tradesById) { - orderTrades.push (this.deepExtend (tradesById[orderTradeId], { - 'order': order['id'], - 'type': order['type'], - 'symbol': order['symbol'], - 'fee': { - 'currency': orderFeeCurrency, - }, - })); - } - } - } - const numOrderTrades = orderTrades.length; - if (numOrderTrades > 0) { - order['trades'] = orderTrades; - } - result.push (order); - } - return result; - } - - async fetchOrder (id, symbol = undefined, params = {}) { - await this.loadMarkets (); - const request = { - 'id': id, - 'include': 'trades', - }; - const response = await this.privateGetOrderId (this.extend (request, params)); - // - // { included: [ { type: "currency", - // id: "XLM", - // attributes: { name: "Stellar", - // shortName: "XLM", - // active: true, - // accuracy: 8, - // allowDeposit: true, - // allowWithdraw: true, - // allowWallet: true, - // allowTrade: false, - // serializedAt: 1543436451996 } }, - // { type: "currency", - // id: "BTC", - // attributes: { name: "Bitcoin", - // shortName: "BTC", - // active: true, - // accuracy: 8, - // allowDeposit: true, - // allowWithdraw: true, - // allowWallet: true, - // allowTrade: true, - // serializedAt: 1543436451996 } }, - // { type: "symbol", - // id: "XLMBTC", - // attributes: { fullName: "XLMBTC", - // digits: 6, - // allowTrade: true, - // serializedAt: 1543436451996 }, - // relationships: { from: { data: { type: "currency", id: "XLM" } }, - // to: { data: { type: "currency", id: "BTC" } } } }, - // { type: "trade", - // id: "34789_34793", - // attributes: { fee: 0.0001925, - // price: 0.000035, - // amount: 220, - // total: 0.0077, - // operation: "buy", - // createdAt: "2018-11-28T19:47:57.451Z" } } ], - // data: { type: "order", - // id: "34793", - // attributes: { serializedAt: 1543436451996, - // operation: "buy", - // orderType: "limit", - // clientId: "4733ea40-7d5c-4ddc-aec5-eb41baf90555", - // amount: 220, - // price: 0.000035, - // averagePrice: 0.000035, - // fee: 0.0001925, - // timeOpen: "2018-11-28T19:47:57.435Z", - // timeClose: "2018-11-28T19:47:57.452Z", - // status: "closed", - // filled: 220, - // flags: null }, - // relationships: { symbol: { data: { type: "symbol", id: "XLMBTC" } }, - // trades: { data: [{ type: "trade", id: "34789_34793" }] } } } } - // - const data = this.safeValue (response, 'data'); - response['data'] = []; - response['data'].push (data); - const orders = this.parseOrdersResponse (response); - const ordersById = this.indexBy (orders, 'id'); - if (id in ordersById) { - return ordersById[id]; - } - throw new OrderNotFound (this.id + ' fetchOrder could not find order id ' + id.toString ()); - } - - nonce () { - return this.milliseconds (); - } - - sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) { - let payload = '/' + this.implodeParams (path, params); - let url = this.urls['api'] + '/' + this.version + payload; - const query = this.omit (params, this.extractParams (path)); - if (method === 'GET') { - if (Object.keys (query).length) { - url += '?' + this.urlencode (query); - } - } - if (api === 'private') { - const nonce = this.nonce (); - let expiredAt = this.sum (nonce, this.safeInteger (this.options, 'expiredAt', 10000)); - expiredAt = expiredAt.toString (); - if ((method === 'POST') || (method === 'PATCH')) { - body = this.json (query); - payload = body; - } - if (this.token) { - headers = { - 'Cookie': 'token=' + this.token, - }; - } else { - this.checkRequiredCredentials (); - const auth = method + payload + 'expiredAt=' + expiredAt; - const signature = this.hmac (this.encode (auth), this.encode (this.secret), 'sha512', 'base64'); - headers = { - 'X-ADX-EXPIRE': expiredAt, - 'X-ADX-APIKEY': this.apiKey, - 'X-ADX-SIGNATURE': signature, - }; - } - if (method !== 'GET') { - headers['Content-Type'] = 'application/json'; - } - } - return { 'url': url, 'method': method, 'body': body, 'headers': headers }; - } - - handleErrors (code, reason, url, method, headers, body, response, requestHeaders, requestBody) { - if (response === undefined) { - return; // fallback to default error handler - } - const errors = this.safeValue (response, 'errors', []); - const numErrors = errors.length; - if (numErrors > 0) { - const error = errors[0]; - const code = this.safeString (error, 'code'); - const status = this.safeString (error, 'status'); - const title = this.safeString (error, 'title'); - const detail = this.safeString (error, 'detail'); - const feedback = this.id + ' ' + this.json (response); - this.throwExactlyMatchedException (this.exceptions['exact'], code, feedback); - this.throwExactlyMatchedException (this.exceptions['exact'], status, feedback); - this.throwExactlyMatchedException (this.exceptions['exact'], title, feedback); - this.throwExactlyMatchedException (this.exceptions['exact'], detail, feedback); - this.throwBroadlyMatchedException (this.exceptions['broad'], body, feedback); - throw new ExchangeError (feedback); // unknown message - } - } -}; - -},{"./base/Exchange":8,"./base/errors":10}],6:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9}],5:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -3440,7 +2182,7 @@ module.exports = class anxpro extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10}],7:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9}],6:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -3473,6 +2215,7 @@ module.exports = class aofex extends Exchange { 'fetchOpenOrders': true, 'fetchClosedOrders': true, 'fetchClosedOrder': true, + 'fetchOrderTrades': true, 'fetchTradingFee': true, }, 'timeframes': { @@ -4002,7 +2745,7 @@ module.exports = class aofex extends Exchange { // const id = this.safeString (trade, 'id'); const ctime = this.parse8601 (this.safeString (trade, 'ctime')); - const timestamp = this.safeTimestamp (trade, 'ts', ctime); + const timestamp = this.safeTimestamp (trade, 'ts', ctime) - 28800000; // 8 hours, adjust to UTC; let symbol = undefined; if ((symbol === undefined) && (market !== undefined)) { symbol = market['symbol']; @@ -4168,7 +2911,7 @@ module.exports = class aofex extends Exchange { base = market['base']; quote = market['quote']; } - const timestamp = this.parse8601 (this.safeString (order, 'ctime')); + const timestamp = this.parse8601 (this.safeString (order, 'ctime')) - 28800000; // 8 hours, adjust to UTC const orderType = this.safeString (order, 'type'); const type = (orderType === '2') ? 'limit' : 'market'; const side = this.safeString (order, 'side'); @@ -4326,11 +3069,16 @@ module.exports = class aofex extends Exchange { return this.parseOrder (order); } + async fetchOrderTrades (id, symbol = undefined, since = undefined, limit = undefined, params = {}) { + const response = await this.fetchClosedOrder (id, symbol, params); + return this.safeValue (response, 'trades', []); + } + async fetchOrdersWithMethod (method, symbol = undefined, since = undefined, limit = undefined, params = {}) { await this.loadMarkets (); const request = { // 'from': 'BM7442641584965237751ZMAKJ5', // query start order_sn - // 'direct': 'prev', // next + 'direct': 'prev', // next }; let market = undefined; if (symbol !== undefined) { @@ -4561,7 +3309,7 @@ module.exports = class aofex extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10,"./base/functions/number":16}],8:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9,"./base/functions/number":15}],7:[function(require,module,exports){ (function (Buffer){ "use strict"; @@ -4853,8 +3601,9 @@ module.exports = class Exchange { const config = deepExtend (this.describe (), userConfig) // merge to this - for (const [property, value] of Object.entries (config)) + for (const [property, value] of Object.entries (config)) { this[property] = deepExtend (this[property], value) + } if (!this.httpAgent) { this.httpAgent = defaultFetch.http ? new defaultFetch.http.Agent ({ 'keepAlive': true }) : undefined @@ -4869,13 +3618,15 @@ module.exports = class Exchange { this['has' + capitalize (k)] = !!this.has[k] // converts 'emulated' to true } - if (this.api) + if (this.api) { this.defineRestApi (this.api, 'request') + } this.initRestRateLimiter () - if (this.markets) + if (this.markets) { this.setMarkets (this.markets) + } } defaults () { @@ -4907,20 +3658,23 @@ module.exports = class Exchange { checkAddress (address) { - if (address === undefined) + if (address === undefined) { throw new InvalidAddress (this.id + ' address is undefined') + } // check the address is not the same letter like 'aaaaa' nor too short nor has a space - if ((unique (address).length === 1) || address.length < this.minFundingAddressLength || address.includes (' ')) + if ((unique (address).length === 1) || address.length < this.minFundingAddressLength || address.includes (' ')) { throw new InvalidAddress (this.id + ' address is invalid or has less than ' + this.minFundingAddressLength.toString () + ' characters: "' + this.json (address) + '"') + } return address } initRestRateLimiter () { - if (this.rateLimit === undefined) + if (this.rateLimit === undefined) { throw new Error (this.id + '.rateLimit property is not configured') + } this.tokenBucket = this.extend ({ delay: 1, @@ -4951,15 +3705,17 @@ module.exports = class Exchange { const promise = fetchImplementation (url, this.extend (params, this.fetchOptions)) .catch ((e) => { - if (isNode) + if (isNode) { throw new ExchangeNotAvailable ([ this.id, method, url, e.type, e.message ].join (' ')) + } throw e // rethrow all unknown errors }) - .then (response => this.handleRestResponse (response, url, method, headers, body)) + .then ((response) => this.handleRestResponse (response, url, method, headers, body)) return timeout (this.timeout, promise).catch ((e) => { - if (e instanceof TimedOut) + if (e instanceof TimedOut) { throw new RequestTimeout (this.id + ' ' + method + ' ' + url + ' request timed out (' + this.timeout + ' ms)') + } throw e }) } @@ -5007,16 +3763,20 @@ module.exports = class Exchange { let underscore = type + '_' + lowercaseMethod + '_' + underscoreSuffix if ('suffixes' in options) { - if ('camelcase' in options['suffixes']) + if ('camelcase' in options['suffixes']) { camelcase += options['suffixes']['camelcase'] - if ('underscore' in options.suffixes) + } + if ('underscore' in options.suffixes) { underscore += options['suffixes']['underscore'] + } } - if ('underscore_suffix' in options) + if ('underscore_suffix' in options) { underscore += options.underscoreSuffix; - if ('camelcase_suffix' in options) + } + if ('camelcase_suffix' in options) { camelcase += options.camelcaseSuffix; + } let partial = async params => this[methodName] (path, type, uppercaseMethod, params || {}) @@ -5159,7 +3919,7 @@ module.exports = class Exchange { getResponseHeaders (response) { const result = {} response.headers.forEach ((value, key) => { - key = key.split ('-').map (word => capitalize (word)).join ('-') + key = key.split ('-').map ((word) => capitalize (word)).join ('-') result[key] = value }) return result @@ -5197,7 +3957,7 @@ module.exports = class Exchange { } setMarkets (markets, currencies = undefined) { - const values = Object.values (markets).map (market => deepExtend ({ + const values = Object.values (markets).map ((market) => deepExtend ({ 'limits': this.limits, 'precision': this.precision, }, this.fees['trading'], market)) @@ -5368,6 +4128,22 @@ module.exports = class Exchange { throw new NotSupported (this.id + ' fetchOrder not supported yet'); } + fetchUnifiedOrder (order, params = {}) { + return this.fetchOrder (this.safeValue (order, 'id'), this.safeValue (order, 'symbol'), params); + } + + createOrder (symbol, type, side, amount, price = undefined, params = {}) { + throw new NotSupported (this.id + ' createOrder not supported yet'); + } + + cancelOrder (id, symbol = undefined, params = {}) { + throw new NotSupported (this.id + ' cancelOrder not supported yet'); + } + + cancelUnifiedOrder (order, params = {}) { + return this.cancelOrder (this.safeValue (order, 'id'), this.safeValue (order, 'symbol'), params); + } + fetchOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) { throw new NotSupported (this.id + ' fetchOrders not supported yet'); } @@ -6021,7 +4797,7 @@ module.exports = class Exchange { }).call(this,require("buffer").Buffer) -},{"../static_dependencies/BN/bn":120,"./errors":10,"./functions":11,"buffer":179}],9:[function(require,module,exports){ +},{"../static_dependencies/BN/bn":119,"./errors":9,"./functions":10,"buffer":178}],8:[function(require,module,exports){ 'use strict'; const errorHierarchy = { @@ -6067,7 +4843,7 @@ const errorHierarchy = { module.exports = errorHierarchy; -},{}],10:[function(require,module,exports){ +},{}],9:[function(require,module,exports){ 'use strict'; const errorHierarchy = require ('./errorHierarchy.js') @@ -6120,7 +4896,7 @@ module.exports = subclass ( errorHierarchy ) -},{"./errorHierarchy.js":9}],11:[function(require,module,exports){ +},{"./errorHierarchy.js":8}],10:[function(require,module,exports){ 'use strict'; /* ------------------------------------------------------------------------ */ @@ -6150,7 +4926,7 @@ module.exports = unCamelCasePropertyNames (Object.assign ({} /* ------------------------------------------------------------------------ */ -},{"./functions/crypto":12,"./functions/encode":13,"./functions/generic":14,"./functions/misc":15,"./functions/number":16,"./functions/platform":17,"./functions/string":18,"./functions/throttle":19,"./functions/time":20,"./functions/type":21}],12:[function(require,module,exports){ +},{"./functions/crypto":11,"./functions/encode":12,"./functions/generic":13,"./functions/misc":14,"./functions/number":15,"./functions/platform":16,"./functions/string":17,"./functions/throttle":18,"./functions/time":19,"./functions/type":20}],11:[function(require,module,exports){ 'use strict' /* ------------------------------------------------------------------------ */ @@ -6299,7 +5075,7 @@ module.exports = { /* ------------------------------------------------------------------------ */ -},{"../../static_dependencies/BN/bn.js":120,"../../static_dependencies/crypto-js/crypto-js":121,"./../../static_dependencies/elliptic/lib/elliptic":122,"./../../static_dependencies/node-rsa/NodeRSA":137,"./../errors":10,"./encode":13,"./string":18}],13:[function(require,module,exports){ +},{"../../static_dependencies/BN/bn.js":119,"../../static_dependencies/crypto-js/crypto-js":120,"./../../static_dependencies/elliptic/lib/elliptic":121,"./../../static_dependencies/node-rsa/NodeRSA":136,"./../errors":9,"./encode":12,"./string":17}],12:[function(require,module,exports){ "use strict"; /* ------------------------------------------------------------------------ */ @@ -6372,7 +5148,7 @@ module.exports['byteArrayToWordArray'] = byteArrayToWordArray /* ------------------------------------------------------------------------ */ -},{"../../static_dependencies/BN/bn":120,"../../static_dependencies/crypto-js/crypto-js":121,"../../static_dependencies/qs/index":153}],14:[function(require,module,exports){ +},{"../../static_dependencies/BN/bn":119,"../../static_dependencies/crypto-js/crypto-js":120,"../../static_dependencies/qs/index":152}],13:[function(require,module,exports){ "use strict"; /* ------------------------------------------------------------------------ */ @@ -6613,7 +5389,7 @@ module.exports = } -},{"./type":21}],15:[function(require,module,exports){ +},{"./type":20}],14:[function(require,module,exports){ 'use strict'; const { ROUND_UP, ROUND_DOWN } = require ('./number') @@ -6746,7 +5522,7 @@ module.exports = { /* ------------------------------------------------------------------------ */ -},{"./../errors":10,"./number":16}],16:[function(require,module,exports){ +},{"./../errors":9,"./number":15}],15:[function(require,module,exports){ 'use strict' /* ------------------------------------------------------------------------ @@ -6794,23 +5570,27 @@ function numberToString (x) { // avoids scientific notation for too large and to if (typeof x === 'string') return x + const s = x.toString () if (Math.abs (x) < 1.0) { - const s = x.toString () const e = parseInt (s.split ('e-')[1]) const neg = (s[0] === '-') if (e) { x *= Math.pow (10, e - 1) x = (neg ? '-' : '') + '0.' + (new Array (e)).join ('0') + x.toString ().substring (neg ? 3 : 2) + return x } } else { - let e = parseInt (x.toString ().split ('+')[1]) - if (e > 20) { - e -= 20 - x /= Math.pow (10, e) - x += (new Array (e + 1)).join ('0') + const parts = s.split ('e') + if (parts[1]) { + let e = parseInt (parts[1]) + const m = parts[0].split ('.') + if (m[1]) { + e -= m[1].length + } + return m[0] + m[1] + (new Array (e + 1)).join ('0') } } - return x.toString () + return s; } //----------------------------------------------------------------------------- @@ -7079,7 +5859,7 @@ module.exports = { /* ------------------------------------------------------------------------ */ -},{}],17:[function(require,module,exports){ +},{}],16:[function(require,module,exports){ (function (process){ "use strict"; @@ -7120,7 +5900,7 @@ module.exports = { defaultFetch, } }).call(this,require('_process')) -},{"../../static_dependencies/fetch-ponyfill/fetch-node":135,"_process":201}],18:[function(require,module,exports){ +},{"../../static_dependencies/fetch-ponyfill/fetch-node":134,"_process":200}],17:[function(require,module,exports){ "use strict"; /* ------------------------------------------------------------------------ */ @@ -7143,7 +5923,7 @@ module.exports = /* ------------------------------------------------------------------------ */ -},{}],19:[function(require,module,exports){ +},{}],18:[function(require,module,exports){ "use strict"; /* ------------------------------------------------------------------------ */ @@ -7209,7 +5989,7 @@ module.exports = { /* ------------------------------------------------------------------------ */ -},{"./time":20}],20:[function(require,module,exports){ +},{"./time":19}],19:[function(require,module,exports){ 'use strict'; /* ------------------------------------------------------------------------ */ @@ -7396,7 +6176,7 @@ module.exports = /* ------------------------------------------------------------------------ */ -},{}],21:[function(require,module,exports){ +},{}],20:[function(require,module,exports){ "use strict"; /* ------------------------------------------------------------------------ */ @@ -7463,7 +6243,7 @@ module.exports = { /* ------------------------------------------------------------------------ */ -},{}],22:[function(require,module,exports){ +},{}],21:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -8144,7 +6924,7 @@ module.exports = class bcex extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10}],23:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9}],22:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -8178,7 +6958,7 @@ module.exports = class bequant extends hitbtc { } }; -},{"./hitbtc":90}],24:[function(require,module,exports){ +},{"./hitbtc":90}],23:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -9148,7 +7928,7 @@ module.exports = class bibox extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10}],25:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9}],24:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -10406,13 +9186,13 @@ module.exports = class bigone extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10}],26:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9}],25:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- const Exchange = require ('./base/Exchange'); -const { ExchangeError, ArgumentsRequired, ExchangeNotAvailable, InsufficientFunds, OrderNotFound, InvalidOrder, DDoSProtection, InvalidNonce, AuthenticationError, InvalidAddress, RateLimitExceeded, PermissionDenied } = require ('./base/errors'); +const { ExchangeError, ArgumentsRequired, ExchangeNotAvailable, InsufficientFunds, OrderNotFound, InvalidOrder, DDoSProtection, InvalidNonce, AuthenticationError, InvalidAddress, RateLimitExceeded, PermissionDenied, NotSupported } = require ('./base/errors'); const { ROUND, TRUNCATE } = require ('./base/functions/number'); // --------------------------------------------------------------------------- @@ -10446,6 +9226,7 @@ module.exports = class binance extends Exchange { 'fetchTransactions': false, 'fetchTradingFee': true, 'fetchTradingFees': true, + 'cancelAllOrders': true, }, 'timeframes': { '1m': '1m', @@ -10466,6 +9247,10 @@ module.exports = class binance extends Exchange { }, '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', + }, 'api': { 'web': 'https://www.binance.com', 'wapi': 'https://api.binance.com/wapi/v3', @@ -10539,6 +9324,8 @@ module.exports = class binance extends Exchange { 'lending/union/purchaseRecord', 'lending/union/redemptionRecord', 'lending/union/interestHistory', + 'lending/project/list', + 'lending/project/position/list', ], 'post': [ 'asset/dust', @@ -10555,6 +9342,7 @@ module.exports = class binance extends Exchange { 'userDataStream', 'futures/transfer', // lending + 'lending/customizedFixed/purchase', 'lending/daily/purchase', 'lending/daily/redeem', ], @@ -10620,6 +9408,8 @@ module.exports = class binance extends Exchange { 'income', ], 'post': [ + 'batchOrders', + 'positionSide/dual', 'positionMargin', 'marginType', 'order', @@ -10630,6 +9420,7 @@ module.exports = class binance extends Exchange { 'listenKey', ], 'delete': [ + 'batchOrders', 'order', 'allOpenOrders', 'listenKey', @@ -10676,6 +9467,7 @@ module.exports = class binance extends Exchange { 'order/test', ], 'delete': [ + 'openOrders', // added on 2020-04-25 for canceling all open orders per symbol 'orderList', // oco 'order', ], @@ -10698,7 +9490,6 @@ module.exports = class binance extends Exchange { 'fetchTradesMethod': 'publicGetAggTrades', // publicGetTrades, publicGetHistoricalTrades 'fetchTickersMethod': 'publicGetTicker24hr', 'defaultTimeInForce': 'GTC', // 'GTC' = Good To Cancel (default), 'IOC' = Immediate Or Cancel - 'defaultLimitOrderType': 'limit', // or 'limit_maker' 'defaultType': 'spot', // 'spot', 'future' 'hasAlreadyAuthenticatedSuccessfully': false, 'warnOnFetchOpenOrdersWithoutSymbol': true, @@ -10735,6 +9526,32 @@ module.exports = class binance extends Exchange { }); } + setSandboxMode (enabled) { + if (enabled) { // eslint-disable-line no-extra-boolean-cast + if ('test' in this.urls) { + const type = this.safeString (this.options, 'defaultType', 'spot'); + if (type !== 'future') { + throw new NotSupported (this.id + ' does not have a sandbox URL for ' + type + " markets, set exchange.options['defaultType'] = 'future' or don't use the sandbox for " + this.id); + } + if (typeof this.urls['api'] === 'string') { + this.urls['api_backup'] = this.urls['api']; + this.urls['api'] = this.urls['test']; + } else { + this.urls['api_backup'] = this.extend ({}, this.urls['api']); + this.urls['api'] = this.extend ({}, this.urls['test']); + } + } else { + throw new NotSupported (this.id + ' does not have a sandbox URL'); + } + } else if ('api_backup' in this.urls) { + if (typeof this.urls['api'] === 'string') { + this.urls['api'] = this.urls['api_backup']; + } else { + this.urls['api'] = this.extend ({}, this.urls['api_backup']); + } + } + } + nonce () { return this.milliseconds () - this.options['timeDifference']; } @@ -10885,7 +9702,7 @@ module.exports = class binance extends Exchange { 'max': undefined, }, 'cost': { - 'min': -1 * Math.log10 (precision['amount']), + 'min': undefined, 'max': undefined, }, }, @@ -11129,7 +9946,7 @@ module.exports = class binance extends Exchange { async fetchBidsAsks (symbols = undefined, params = {}) { await this.loadMarkets (); - const defaultType = this.safeString2 (this.options, 'fetchOpenOrders', 'defaultType', 'spot'); + 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'; @@ -11146,12 +9963,12 @@ module.exports = class binance extends Exchange { parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) { return [ - ohlcv[0], - parseFloat (ohlcv[1]), - parseFloat (ohlcv[2]), - parseFloat (ohlcv[3]), - parseFloat (ohlcv[4]), - parseFloat (ohlcv[5]), + this.safeInteger (ohlcv, 0), + this.safeFloat (ohlcv, 1), + this.safeFloat (ohlcv, 2), + this.safeFloat (ohlcv, 3), + this.safeFloat (ohlcv, 4), + this.safeFloat (ohlcv, 5), ]; } @@ -11279,6 +10096,10 @@ module.exports = class binance extends Exchange { if (market !== undefined) { symbol = market['symbol']; } + let cost = undefined; + if ((price !== undefined) && (amount !== undefined)) { + cost = price * amount; + } return { 'info': trade, 'timestamp': timestamp, @@ -11287,11 +10108,11 @@ module.exports = class binance extends Exchange { 'id': id, 'order': orderId, 'type': undefined, - 'takerOrMaker': takerOrMaker, 'side': side, + 'takerOrMaker': takerOrMaker, 'price': price, 'amount': amount, - 'cost': price * amount, + 'cost': cost, 'fee': fee, }; } @@ -11589,6 +10410,8 @@ module.exports = class binance extends Exchange { } else if (uppercaseType === 'STOP') { stopPriceIsRequired = true; priceIsRequired = true; + } else if (uppercaseType === 'STOP_MARKET') { + stopPriceIsRequired = true; } if (priceIsRequired) { if (price === undefined) { @@ -11748,6 +10571,27 @@ module.exports = class binance extends Exchange { return this.parseOrder (response); } + async cancelAllOrders (symbol = undefined, params = {}) { + if (symbol === undefined) { + throw new ArgumentsRequired (this.id + ' cancelAllOrders requires a symbol argument'); + } + await this.loadMarkets (); + const market = this.market (symbol); + const request = { + 'symbol': market['id'], + }; + const defaultType = this.safeString2 (this.options, 'cancelAllOrders', 'defaultType', 'spot'); + const type = this.safeString (params, 'type', defaultType); + const query = this.omit (params, 'type'); + const method = (type === 'spot') ? 'privateDeleteOpenOrders' : 'fapiPrivateDeleteAllOpenOrders'; + const response = await this[method] (this.extend (request, query)); + if (Array.isArray (response)) { + return this.parseOrders (response, market); + } else { + return response; + } + } + async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) { if (symbol === undefined) { throw new ArgumentsRequired (this.id + ' fetchMyTrades requires a symbol argument'); @@ -11980,10 +10824,7 @@ module.exports = class binance extends Exchange { } parseTransactionStatusByType (status, type = undefined) { - if (type === undefined) { - return status; - } - const statuses = { + const statusesByType = { 'deposit': { '0': 'pending', '1': 'ok', @@ -11998,32 +10839,38 @@ module.exports = class binance extends Exchange { '6': 'ok', // Completed }, }; - return (status in statuses[type]) ? statuses[type][status] : status; + const statuses = this.safeValue (statusesByType, type, {}); + return this.safeString (statuses, status, status); } parseTransaction (transaction, currency = undefined) { // // fetchDeposits - // { insertTime: 1517425007000, - // amount: 0.3, - // address: "0x0123456789abcdef", - // addressTag: "", - // txId: "0x0123456789abcdef", - // asset: "ETH", - // status: 1 } + // + // { + // insertTime: 1517425007000, + // amount: 0.3, + // address: "0x0123456789abcdef", + // addressTag: "", + // txId: "0x0123456789abcdef", + // asset: "ETH", + // status: 1 + // } // // fetchWithdrawals // - // { amount: 14, - // address: "0x0123456789abcdef...", + // { + // amount: 14, + // address: "0x0123456789abcdef...", // successTime: 1514489710000, - // transactionFee: 0.01, - // addressTag: "", - // txId: "0x0123456789abcdef...", - // id: "0123456789abcdef...", - // asset: "ETH", - // applyTime: 1514488724000, - // status: 6 } + // transactionFee: 0.01, + // addressTag: "", + // txId: "0x0123456789abcdef...", + // id: "0123456789abcdef...", + // asset: "ETH", + // applyTime: 1514488724000, + // status: 6 + // } // const id = this.safeString (transaction, 'id'); const address = this.safeString (transaction, 'address'); @@ -12033,7 +10880,7 @@ module.exports = class binance extends Exchange { tag = undefined; } } - const txid = this.safeValue (transaction, 'txId'); + const txid = this.safeString (transaction, 'txId'); const currencyId = this.safeString (transaction, 'asset'); const code = this.safeCurrencyCode (currencyId, currency); let timestamp = undefined; @@ -12263,6 +11110,11 @@ module.exports = class binance extends Exchange { 'timestamp': this.nonce (), 'recvWindow': this.options['recvWindow'], }, params)); + } else if (path === 'batchOrders') { + query = this.rawencode (this.extend ({ + 'timestamp': this.nonce (), + 'recvWindow': this.options['recvWindow'], + }, params)); } else { query = this.urlencode (this.extend ({ 'timestamp': this.nonce (), @@ -12369,7 +11221,7 @@ module.exports = class binance extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10,"./base/functions/number":16}],27:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9,"./base/functions/number":15}],26:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -12424,7 +11276,7 @@ module.exports = class binanceje extends binance { }; -},{"./binance.js":26}],28:[function(require,module,exports){ +},{"./binance.js":25}],27:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -12458,10 +11310,10 @@ module.exports = class binanceus extends binance { }, 'fees': { 'trading': { - 'tierBased': false, + 'tierBased': true, 'percentage': true, - 'taker': 0.0, // 0.1% trading fee, zero fees for all trading pairs before November 1 - 'maker': 0.0, // 0.1% trading fee, zero fees for all trading pairs before November 1 + 'taker': 0.001, // 0.1% trading fee, zero fees for all trading pairs before November 1 + 'maker': 0.001, // 0.1% trading fee, zero fees for all trading pairs before November 1 }, }, }); @@ -12469,7 +11321,7 @@ module.exports = class binanceus extends binance { }; -},{"./binance.js":26}],29:[function(require,module,exports){ +},{"./binance.js":25}],28:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -12891,7 +11743,7 @@ module.exports = class bit2c extends Exchange { }; -},{"./base/Exchange":8,"./base/errors":10}],30:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9}],29:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -13460,13 +12312,13 @@ module.exports = class bitbank extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10}],31:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9}],30:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- const Exchange = require ('./base/Exchange'); -const { InvalidNonce, InsufficientFunds, AuthenticationError, InvalidOrder, ExchangeError, OrderNotFound, AccountSuspended, BadSymbol, OrderImmediatelyFillable, RateLimitExceeded } = require ('./base/errors'); +const { InvalidNonce, InsufficientFunds, AuthenticationError, InvalidOrder, ExchangeError, OrderNotFound, AccountSuspended, BadSymbol, OrderImmediatelyFillable, RateLimitExceeded, OnMaintenance } = require ('./base/errors'); // --------------------------------------------------------------------------- @@ -13516,6 +12368,7 @@ module.exports = class bitbay extends Exchange { 'https://github.com/BitBayNet/API', 'https://docs.bitbay.net/v1.0.1-en/reference', ], + 'support': 'https://support.bitbay.net', 'fees': 'https://bitbay.net/en/fees', }, 'api': { @@ -13580,8 +12433,60 @@ module.exports = class bitbay extends Exchange { }, 'fees': { 'trading': { + 'maker': 0.0, + 'taker': 0.1 / 100, + 'percentage': true, + 'tierBased': false, + }, + 'fiat': { 'maker': 0.30 / 100, 'taker': 0.43 / 100, + 'percentage': true, + 'tierBased': true, + 'tiers': { + 'taker': [ + [ 0.0043, 0 ], + [ 0.0042, 1250 ], + [ 0.0041, 3750 ], + [ 0.0040, 7500 ], + [ 0.0039, 10000 ], + [ 0.0038, 15000 ], + [ 0.0037, 20000 ], + [ 0.0036, 25000 ], + [ 0.0035, 37500 ], + [ 0.0034, 50000 ], + [ 0.0033, 75000 ], + [ 0.0032, 100000 ], + [ 0.0031, 150000 ], + [ 0.0030, 200000 ], + [ 0.0029, 250000 ], + [ 0.0028, 375000 ], + [ 0.0027, 500000 ], + [ 0.0026, 625000 ], + [ 0.0025, 875000 ], + ], + 'maker': [ + [ 0.0030, 0 ], + [ 0.0029, 1250 ], + [ 0.0028, 3750 ], + [ 0.0028, 7500 ], + [ 0.0027, 10000 ], + [ 0.0026, 15000 ], + [ 0.0025, 20000 ], + [ 0.0025, 25000 ], + [ 0.0024, 37500 ], + [ 0.0023, 50000 ], + [ 0.0023, 75000 ], + [ 0.0022, 100000 ], + [ 0.0021, 150000 ], + [ 0.0021, 200000 ], + [ 0.0020, 250000 ], + [ 0.0019, 375000 ], + [ 0.0018, 500000 ], + [ 0.0018, 625000 ], + [ 0.0017, 875000 ], + ], + }, }, 'funding': { 'withdraw': { @@ -13598,6 +12503,9 @@ module.exports = class bitbay extends Exchange { }, }, }, + 'options': { + 'fiatCurrencies': [ 'EUR', 'USD', 'GBP', 'PLN' ], + }, 'exceptions': { '400': ExchangeError, // At least one parameter wasn't set '401': InvalidOrder, // Invalid order type @@ -13622,12 +12530,14 @@ module.exports = class bitbay extends Exchange { 'OFFER_NOT_FOUND': OrderNotFound, 'OFFER_WOULD_HAVE_BEEN_PARTIALLY_FILLED': OrderImmediatelyFillable, 'ACTION_LIMIT_EXCEEDED': RateLimitExceeded, + 'UNDER_MAINTENANCE': OnMaintenance, }, }); } async fetchMarkets (params = {}) { const response = await this.v1_01PublicGetTradingTicker (params); + const fiatCurrencies = this.safeValue (this.options, 'fiatCurrencies', []); // // { // status: 'Ok', @@ -13666,6 +12576,12 @@ module.exports = class bitbay extends Exchange { 'amount': this.safeInteger (first, 'scale'), 'price': this.safeInteger (second, 'scale'), }; + let fees = this.safeValue (this.fees, 'trading', {}); + if (this.inArray (base, fiatCurrencies) || this.inArray (quote, fiatCurrencies)) { + fees = this.safeValue (this.fees, 'fiat', {}); + } + const maker = this.safeFloat (fees, 'maker'); + const taker = this.safeFloat (fees, 'taker'); // todo: check that the limits have ben interpreted correctly // todo: parse the fees page result.push ({ @@ -13677,7 +12593,8 @@ module.exports = class bitbay extends Exchange { 'quoteId': quoteId, 'precision': precision, 'active': undefined, - 'fee': undefined, + 'maker': maker, + 'taker': taker, 'limits': { 'amount': { 'min': this.safeFloat (first, 'minOffer'), @@ -14676,7 +13593,7 @@ module.exports = class bitbay extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10}],32:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9}],31:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -15584,12 +14501,12 @@ module.exports = class bitfinex extends Exchange { parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) { return [ - ohlcv[0], - ohlcv[1], - ohlcv[3], - ohlcv[4], - ohlcv[2], - ohlcv[5], + this.safeInteger (ohlcv, 0), + this.safeFloat (ohlcv, 1), + this.safeFloat (ohlcv, 3), + this.safeFloat (ohlcv, 4), + this.safeFloat (ohlcv, 2), + this.safeFloat (ohlcv, 5), ]; } @@ -15861,7 +14778,7 @@ module.exports = class bitfinex extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10,"./base/functions/number":16}],33:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9,"./base/functions/number":15}],32:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -16563,6 +15480,7 @@ module.exports = class bitfinex2 extends bitfinex { 'PARTIALLY FILLED': 'open', 'EXECUTED': 'closed', 'CANCELED': 'canceled', + 'CANCELED was: PARTIALLY FILLED': 'canceled', 'INSUFFICIENT MARGIN': 'canceled', 'INSUFFICIENT BALANCE (G1) was: PARTIALLY FILLED': 'canceled', 'RSN_DUST': 'rejected', @@ -17055,7 +15973,7 @@ module.exports = class bitfinex2 extends bitfinex { } }; -},{"./base/errors":10,"./bitfinex.js":32}],34:[function(require,module,exports){ +},{"./base/errors":9,"./bitfinex.js":31}],33:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -17547,7 +16465,7 @@ module.exports = class bitflyer extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10}],35:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9}],34:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -18149,13 +17067,13 @@ module.exports = class bitforex extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10}],36:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9}],35:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- const Exchange = require ('./base/Exchange'); -const { ExchangeError, ExchangeNotAvailable, AuthenticationError, BadRequest, PermissionDenied, InvalidAddress } = require ('./base/errors'); +const { ExchangeError, ExchangeNotAvailable, AuthenticationError, BadRequest, PermissionDenied, InvalidAddress, ArgumentsRequired, InvalidOrder } = require ('./base/errors'); // --------------------------------------------------------------------------- @@ -18168,7 +17086,12 @@ module.exports = class bithumb extends Exchange { 'rateLimit': 500, 'has': { 'CORS': true, + 'createOrder': true, + 'cancelOrder': true, + 'createMarketOrder': true, 'fetchTickers': true, + 'fetchOpenOrders': true, + 'fetchOrder': true, 'withdraw': true, }, 'urls': { @@ -18200,8 +17123,8 @@ module.exports = class bithumb extends Exchange { 'info/ticker', 'info/orders', 'info/user_transactions', - 'trade/place', 'info/order_detail', + 'trade/place', 'trade/cancel', 'trade/btc_withdrawal', 'trade/krw_deposit', @@ -18317,15 +17240,53 @@ module.exports = class bithumb extends Exchange { 'currency': market['base'], }; if (limit !== undefined) { - request['count'] = limit; // max = 50 + request['count'] = limit; // default 30, max 30 } const response = await this.publicGetOrderbookCurrency (this.extend (request, params)); - const orderbook = this.safeValue (response, 'data'); - const timestamp = this.safeInteger (orderbook, 'timestamp'); - return this.parseOrderBook (orderbook, timestamp, 'bids', 'asks', 'price', 'quantity'); + // + // { + // "status":"0000", + // "data":{ + // "timestamp":"1587621553942", + // "payment_currency":"KRW", + // "order_currency":"BTC", + // "bids":[ + // {"price":"8652000","quantity":"0.0043"}, + // {"price":"8651000","quantity":"0.0049"}, + // {"price":"8650000","quantity":"8.4791"}, + // ], + // "asks":[ + // {"price":"8654000","quantity":"0.119"}, + // {"price":"8655000","quantity":"0.254"}, + // {"price":"8658000","quantity":"0.119"}, + // ] + // } + // } + // + const data = this.safeValue (response, 'data', {}); + const timestamp = this.safeInteger (data, 'timestamp'); + return this.parseOrderBook (data, timestamp, 'bids', 'asks', 'price', 'quantity'); } parseTicker (ticker, market = undefined) { + // + // fetchTicker, fetchTickers + // + // { + // "opening_price":"227100", + // "closing_price":"228400", + // "min_price":"222300", + // "max_price":"230000", + // "units_traded":"82618.56075337", + // "acc_trade_value":"18767376138.6031", + // "prev_closing_price":"227100", + // "units_traded_24H":"151871.13484676", + // "acc_trade_value_24H":"34247610416.8974", + // "fluctate_24H":"8700", + // "fluctate_rate_24H":"3.96", + // "date":"1587710327264", // fetchTickers inject this + // } + // const timestamp = this.safeInteger (ticker, 'date'); let symbol = undefined; if (market !== undefined) { @@ -18376,9 +17337,31 @@ module.exports = class bithumb extends Exchange { async fetchTickers (symbols = undefined, params = {}) { await this.loadMarkets (); const response = await this.publicGetTickerAll (params); + // + // { + // "status":"0000", + // "data":{ + // "BTC":{ + // "opening_price":"9045000", + // "closing_price":"9132000", + // "min_price":"8938000", + // "max_price":"9168000", + // "units_traded":"4619.79967497", + // "acc_trade_value":"42021363832.5187", + // "prev_closing_price":"9041000", + // "units_traded_24H":"8793.5045804", + // "acc_trade_value_24H":"78933458515.4962", + // "fluctate_24H":"530000", + // "fluctate_rate_24H":"6.16" + // }, + // "date":"1587710878669" + // } + // } + // const result = {}; - const timestamp = this.safeInteger (response['data'], 'date'); - const tickers = this.omit (response['data'], 'date'); + const data = this.safeValue (response, 'data', {}); + const timestamp = this.safeInteger (data, 'date'); + const tickers = this.omit (data, 'date'); const ids = Object.keys (tickers); for (let i = 0; i < ids.length; i++) { const id = ids[i]; @@ -18405,19 +17388,72 @@ module.exports = class bithumb extends Exchange { 'currency': market['base'], }; const response = await this.publicGetTickerCurrency (this.extend (request, params)); - return this.parseTicker (response['data'], market); + // + // { + // "status":"0000", + // "data":{ + // "opening_price":"227100", + // "closing_price":"228400", + // "min_price":"222300", + // "max_price":"230000", + // "units_traded":"82618.56075337", + // "acc_trade_value":"18767376138.6031", + // "prev_closing_price":"227100", + // "units_traded_24H":"151871.13484676", + // "acc_trade_value_24H":"34247610416.8974", + // "fluctate_24H":"8700", + // "fluctate_rate_24H":"3.96", + // "date":"1587710327264" + // } + // } + // + const data = this.safeValue (response, 'data', {}); + return this.parseTicker (data, market); } parseTrade (trade, market = undefined) { + // + // fetchTrades (public) + // + // { + // "transaction_date":"2020-04-23 22:21:46", + // "type":"ask", + // "units_traded":"0.0125", + // "price":"8667000", + // "total":"108337" + // } + // + // fetchOrder (private) + // + // { + // "transaction_date": "1572497603902030", + // "price": "8601000", + // "units": "0.005", + // "fee_currency": "KRW", + // "fee": "107.51", + // "total": "43005" + // } + // // a workaround for their bug in date format, hours are not 0-padded - const parts = trade['transaction_date'].split (' '); - const transaction_date = parts[0]; - let transaction_time = parts[1]; - if (transaction_time.length < 8) { - transaction_time = '0' + transaction_time; + let timestamp = undefined; + const transactionDatetime = this.safeString (trade, 'transaction_date'); + if (transactionDatetime !== undefined) { + const parts = transactionDatetime.split (' '); + const numParts = parts.length; + if (numParts > 1) { + const transactionDate = parts[0]; + let transactionTime = parts[1]; + if (transactionTime.length < 8) { + transactionTime = '0' + transactionTime; + } + timestamp = this.parse8601 (transactionDate + ' ' + transactionTime); + } else { + timestamp = this.safeIntegerProduct (trade, 'transaction_date', 0.001); + } + } + if (timestamp !== undefined) { + timestamp -= 9 * 3600000; // they report UTC + 9 hours, server in Korean timezone } - let timestamp = this.parse8601 (transaction_date + ' ' + transaction_time); - timestamp -= 9 * 3600000; // they report UTC + 9 hours (server in Korean timezone) const type = undefined; let side = this.safeString (trade, 'type'); side = (side === 'ask') ? 'sell' : 'buy'; @@ -18428,12 +17464,24 @@ module.exports = class bithumb extends Exchange { } const price = this.safeFloat (trade, 'price'); const amount = this.safeFloat (trade, 'units_traded'); - let cost = undefined; - if (amount !== undefined) { - if (price !== undefined) { - cost = price * amount; + let cost = this.safeFloat (trade, 'total'); + if (cost === undefined) { + if (amount !== undefined) { + if (price !== undefined) { + cost = price * amount; + } } } + let fee = undefined; + const feeCost = this.safeFloat (trade, 'fee'); + if (feeCost !== undefined) { + const feeCurrencyId = this.safeString (trade, 'fee_currency'); + const feeCurrencyCode = this.commonCurrencyCode (feeCurrencyId); + fee = { + 'cost': feeCost, + 'currency': feeCurrencyCode, + }; + } return { 'id': id, 'info': trade, @@ -18447,7 +17495,7 @@ module.exports = class bithumb extends Exchange { 'price': price, 'amount': amount, 'cost': cost, - 'fee': undefined, + 'fee': fee, }; } @@ -18461,57 +17509,276 @@ module.exports = class bithumb extends Exchange { request['count'] = limit; // default 20, max 100 } const response = await this.publicGetTransactionHistoryCurrency (this.extend (request, params)); - return this.parseTrades (response['data'], market, since, limit); + // + // { + // "status":"0000", + // "data":[ + // { + // "transaction_date":"2020-04-23 22:21:46", + // "type":"ask", + // "units_traded":"0.0125", + // "price":"8667000", + // "total":"108337" + // }, + // ] + // } + // + const data = this.safeValue (response, 'data', []); + return this.parseTrades (data, market, since, limit); } async createOrder (symbol, type, side, amount, price = undefined, params = {}) { await this.loadMarkets (); const market = this.market (symbol); - let request = undefined; - let method = 'privatePostTrade'; + const request = { + 'order_currency': market['id'], + 'Payment_currency': market['quote'], + 'units': amount, + }; + let method = 'privatePostTradePlace'; if (type === 'limit') { - request = { - 'order_currency': market['id'], - 'Payment_currency': market['quote'], - 'units': amount, - 'price': price, - 'type': (side === 'buy') ? 'bid' : 'ask', - }; - method += 'Place'; - } else if (type === 'market') { - request = { - 'currency': market['id'], - 'units': amount, - }; - method += 'Market' + this.capitalize (side); + request['price'] = price; + request['type'] = (side === 'buy') ? 'bid' : 'ask'; + } else { + method = 'privatePostTradeMarket' + this.capitalize (side); } const response = await this[method] (this.extend (request, params)); const id = this.safeString (response, 'order_id'); + if (id === undefined) { + throw new InvalidOrder (this.id + ' createOrder did not return an order id'); + } return { 'info': response, + 'symbol': symbol, + 'type': type, + 'side': side, 'id': id, }; } + async fetchOrder (id, symbol = undefined, params = {}) { + if (symbol === undefined) { + throw new ArgumentsRequired (this.id + ' fetchOrder requires a symbol argument'); + } + await this.loadMarkets (); + const market = this.market (symbol); + const request = { + 'order_id': id, + 'count': 1, + 'order_currency': market['base'], + 'payment_currency': market['quote'], + }; + const response = await this.privatePostInfoOrderDetail (this.extend (request, params)); + // + // { + // "status": "0000", + // "data": { + // "transaction_date": "1572497603668315", + // "type": "bid", + // "order_status": "Completed", + // "order_currency": "BTC", + // "payment_currency": "KRW", + // "order_price": "8601000", + // "order_qty": "0.007", + // "cancel_date": "", + // "cancel_type": "", + // "contract": [ + // { + // "transaction_date": "1572497603902030", + // "price": "8601000", + // "units": "0.005", + // "fee_currency": "KRW", + // "fee": "107.51", + // "total": "43005" + // }, + // ] + // } + // } + // + const data = this.safeValue (response, 'data'); + return this.parseOrder (this.extend (data, { 'order_id': id }), market); + } + + parseOrderStatus (status) { + const statuses = { + 'Pending': 'open', + 'Completed': 'closed', + 'Cancel': 'canceled', + }; + return this.safeString (statuses, status, status); + } + + parseOrder (order, market = undefined) { + // + // fetchOrder + // + // { + // "transaction_date": "1572497603668315", + // "type": "bid", + // "order_status": "Completed", + // "order_currency": "BTC", + // "payment_currency": "KRW", + // "order_price": "8601000", + // "order_qty": "0.007", + // "cancel_date": "", + // "cancel_type": "", + // "contract": [ + // { + // "transaction_date": "1572497603902030", + // "price": "8601000", + // "units": "0.005", + // "fee_currency": "KRW", + // "fee": "107.51", + // "total": "43005" + // }, + // ] + // } + // + // fetchOpenOrders + // + // { + // "order_currency": "BTC", + // "payment_currency": "KRW", + // "order_id": "C0101000007408440032", + // "order_date": "1571728739360570", + // "type": "bid", + // "units": "5.0", + // "units_remaining": "5.0", + // "price": "501000", + // } + // + const timestamp = this.safeIntegerProduct (order, 'order_date', 0.001); + const sideProperty = this.safeValue2 (order, 'type', 'side'); + const side = (sideProperty === 'bid') ? 'buy' : 'sell'; + const status = this.parseOrderStatus (this.safeString (order, 'order_status')); + let price = this.safeFloat2 (order, 'order_price', 'price'); + let type = 'limit'; + if (price === 0) { + price = undefined; + type = 'market'; + } + const amount = this.safeFloat2 (order, 'order_qty', 'units'); + let remaining = this.safeFloat (order, 'units_remaining'); + if (remaining === undefined) { + if (status === 'closed') { + remaining = 0; + } else { + remaining = amount; + } + } + let filled = undefined; + if ((amount !== undefined) && (remaining !== undefined)) { + filled = amount - remaining; + } + let symbol = undefined; + const baseId = this.safeString (order, 'order_currency'); + const quoteId = this.safeString (order, 'payment_currency'); + const base = this.safeCurrencyCode (baseId); + const quote = this.safeCurrencyCode (quoteId); + if ((base !== undefined) && (quote !== undefined)) { + symbol = base + '/' + quote; + } + if ((symbol === undefined) && (market !== undefined)) { + symbol = market['symbol']; + } + const rawTrades = this.safeValue (order, 'contract'); + let trades = undefined; + const id = this.safeString (order, 'order_id'); + if (rawTrades !== undefined) { + trades = this.parseTrades (rawTrades, market, undefined, undefined, { + 'side': side, + 'symbol': symbol, + 'order': id, + }); + } + return { + 'info': order, + 'id': id, + 'timestamp': timestamp, + 'datetime': this.iso8601 (timestamp), + 'lastTradeTimestamp': undefined, + 'symbol': symbol, + 'type': type, + 'side': side, + 'price': price, + 'amount': amount, + 'cost': undefined, + 'average': undefined, + 'filled': filled, + 'remaining': remaining, + 'status': status, + 'fee': undefined, + 'trades': trades, + }; + } + + async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) { + if (symbol === undefined) { + throw new ArgumentsRequired (this.id + ' fetchOpenOrders requires a symbol argument'); + } + await this.loadMarkets (); + const market = this.market (symbol); + if (limit === undefined) { + limit = 100; + } + const request = { + 'count': limit, + 'order_currency': market['base'], + 'payment_currency': market['quote'], + }; + if (since !== undefined) { + request['after'] = since; + } + const response = await this.privatePostInfoOrders (this.extend (request, params)); + // + // { + // "status": "0000", + // "data": [ + // { + // "order_currency": "BTC", + // "payment_currency": "KRW", + // "order_id": "C0101000007408440032", + // "order_date": "1571728739360570", + // "type": "bid", + // "units": "5.0", + // "units_remaining": "5.0", + // "price": "501000", + // } + // ] + // } + // + const data = this.safeValue (response, 'data', []); + return this.parseOrders (data, market, since, limit); + } + async cancelOrder (id, symbol = undefined, params = {}) { const side_in_params = ('side' in params); if (!side_in_params) { - throw new ExchangeError (this.id + ' cancelOrder requires a `side` parameter (sell or buy) and a `currency` parameter'); + throw new ArgumentsRequired (this.id + ' cancelOrder requires a `symbol` argument and a `side` parameter (sell or buy)'); } - const currency = this.safeString (params, 'currency'); - if (currency === undefined) { - throw new ExchangeError (this.id + ' cancelOrder requires a `currency` parameter (a currency id)'); + if (symbol === undefined) { + throw new ArgumentsRequired (this.id + ' cancelOrder requires a `symbol` argument and a `side` parameter (sell or buy)'); } + const market = this.market (symbol); const side = (params['side'] === 'buy') ? 'bid' : 'ask'; params = this.omit (params, [ 'side', 'currency' ]); + // https://github.com/ccxt/ccxt/issues/6771 const request = { 'order_id': id, 'type': side, - 'currency': currency, + 'order_currency': market['base'], + 'payment_currency': market['quote'], }; return await this.privatePostTradeCancel (this.extend (request, params)); } + cancelUnifiedOrder (order, params = {}) { + const request = { + 'side': order['side'], + }; + return this.cancelOrder (order['id'], order['symbol'], this.extend (request, params)); + } + async withdraw (code, amount, address, tag = undefined, params = {}) { this.checkAddress (address); await this.loadMarkets (); @@ -18524,7 +17791,7 @@ module.exports = class bithumb extends Exchange { if (currency === 'XRP' || currency === 'XMR') { const destination = this.safeString (params, 'destination'); if ((tag === undefined) && (destination === undefined)) { - throw new ExchangeError (this.id + ' ' + code + ' withdraw() requires a tag argument or an extra destination param'); + throw new ArgumentsRequired (this.id + ' ' + code + ' withdraw() requires a tag argument or an extra destination param'); } else if (tag !== undefined) { request['destination'] = tag; } @@ -18602,7 +17869,7 @@ module.exports = class bithumb extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10}],37:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9}],36:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -18630,7 +17897,7 @@ module.exports = class bitkk extends zb { } }; -},{"./zb.js":173}],38:[function(require,module,exports){ +},{"./zb.js":172}],37:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -18668,6 +17935,7 @@ module.exports = class bitmart extends Exchange { 'fetchClosedOrders': true, 'fetchCanceledOrders': true, 'fetchOrder': true, + 'signIn': true, }, 'urls': { 'logo': 'https://user-images.githubusercontent.com/1294454/61835713-a2662f80-ae85-11e9-9d00-6442919701fd.jpg', @@ -18675,6 +17943,7 @@ module.exports = class bitmart extends Exchange { 'www': 'https://www.bitmart.com/', 'doc': 'https://github.com/bitmartexchange/bitmart-official-api-docs', 'referral': 'http://www.bitmart.com/?r=rQCFLh', + 'fees': 'https://www.bitmart.com/fee/en', }, 'requiredCredentials': { 'apiKey': true, @@ -19558,7 +18827,7 @@ module.exports = class bitmart extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10}],39:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9}],38:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -20748,7 +20017,7 @@ module.exports = class bitmax extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10,"./base/functions/number":16}],40:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9,"./base/functions/number":15}],39:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -22079,7 +21348,7 @@ module.exports = class bitmex extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10,"./base/functions/number":16}],41:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9,"./base/functions/number":15}],40:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -22648,7 +21917,7 @@ module.exports = class bitso extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10}],42:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9}],41:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -23785,11 +23054,19 @@ module.exports = class bitstamp extends Exchange { body = this.urlencode (query); contentType = 'application/x-www-form-urlencoded'; headers['Content-Type'] = contentType; + } else { + // sending an empty POST request will trigger + // an API0020 error returned by the exchange + // therefore for empty requests we send a dummy object + // https://github.com/ccxt/ccxt/issues/6846 + body = this.urlencode ({ 'foo': 'bar' }); + contentType = 'application/x-www-form-urlencoded'; + headers['Content-Type'] = contentType; } } const authBody = body ? body : ''; const auth = xAuth + method + url.replace ('https://', '') + contentType + xAuthNonce + xAuthTimestamp + xAuthVersion + authBody; - const signature = this.encode (this.hmac (this.encode (auth), this.encode (this.secret))); + const signature = this.hmac (this.encode (auth), this.encode (this.secret)); headers['X-Auth-Signature'] = signature; } } @@ -23846,7 +23123,7 @@ module.exports = class bitstamp extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10}],43:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9}],42:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -24139,7 +23416,7 @@ module.exports = class bitstamp1 extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10}],44:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9}],43:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -25681,7 +24958,7 @@ module.exports = class bittrex extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10,"./base/functions/number":16}],45:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9,"./base/functions/number":15}],44:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -26334,7 +25611,7 @@ module.exports = class bitz extends Exchange { } } else { if (since !== undefined) { - throw new ExchangeError (this.id + ' fetchOHLCV requires a limit argument if the since argument is specified'); + throw new ArgumentsRequired (this.id + ' fetchOHLCV requires a limit argument if the since argument is specified'); } } const response = await this.marketGetKline (this.extend (request, params)); @@ -26897,7 +26174,7 @@ module.exports = class bitz extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10}],46:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9}],45:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -27132,7 +26409,7 @@ module.exports = class bl3p extends Exchange { } }; -},{"./base/Exchange":8}],47:[function(require,module,exports){ +},{"./base/Exchange":7}],46:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -27208,6 +26485,9 @@ module.exports = class bleutrade extends Exchange { ], }, 'v3Private': { + 'get': [ + 'statement', + ], 'post': [ 'getbalance', 'getbalances', @@ -27324,8 +26604,8 @@ module.exports = class bleutrade extends Exchange { // MarketCurrencyLong: 'Litecoin', // BaseCurrencyLong: 'Tether' } const id = this.safeString (market, 'MarketName'); - const baseId = this.safeString (market, 'MarketCurrency'); - const quoteId = this.safeString (market, 'BaseCurrency'); + const baseId = this.safeString (market, 'MarketAsset'); + const quoteId = this.safeString (market, 'BaseAsset'); const base = this.safeCurrencyCode (baseId); const quote = this.safeCurrencyCode (quoteId); const symbol = base + '/' + quote; @@ -27970,7 +27250,7 @@ module.exports = class bleutrade extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10}],48:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9}],47:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -28590,7 +27870,7 @@ module.exports = class braziliex extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10}],49:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9}],48:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -29068,7 +28348,7 @@ module.exports = class btcalpha extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10}],50:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9}],49:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -29487,7 +28767,7 @@ module.exports = class btcbox extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10}],51:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9}],50:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -30247,7 +29527,7 @@ module.exports = class btcmarkets extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10,"./base/functions/number":16}],52:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9,"./base/functions/number":15}],51:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -30320,7 +29600,7 @@ module.exports = class btctradeim extends coinegg { } }; -},{"./base/errors":10,"./coinegg.js":65}],53:[function(require,module,exports){ +},{"./base/errors":9,"./coinegg.js":64}],52:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -30341,6 +29621,7 @@ module.exports = class btctradeua extends Exchange { 'CORS': false, 'createMarketOrder': false, 'fetchOpenOrders': true, + 'signIn': true, }, 'urls': { 'referral': 'https://btc-trade.com.ua/registration/22689', @@ -30706,7 +29987,7 @@ module.exports = class btctradeua extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10}],54:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9}],53:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -31029,13 +30310,13 @@ module.exports = class btcturk extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10}],55:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9}],54:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- const Exchange = require ('./base/Exchange'); -const { AddressPending, AuthenticationError, ExchangeError, NotSupported, PermissionDenied } = require ('./base/errors'); +const { AddressPending, AuthenticationError, ExchangeError, NotSupported, PermissionDenied, ArgumentsRequired } = require ('./base/errors'); // --------------------------------------------------------------------------- @@ -31724,7 +31005,7 @@ module.exports = class buda extends Exchange { async fetchDeposits (code = undefined, since = undefined, limit = undefined, params = {}) { await this.loadMarkets (); if (code === undefined) { - throw new ExchangeError (this.id + ': fetchDeposits() requires a currency code argument'); + throw new ArgumentsRequired (this.id + ': fetchDeposits() requires a currency code argument'); } const currency = this.currency (code); const request = { @@ -31739,7 +31020,7 @@ module.exports = class buda extends Exchange { async fetchWithdrawals (code = undefined, since = undefined, limit = undefined, params = {}) { await this.loadMarkets (); if (code === undefined) { - throw new ExchangeError (this.id + ': fetchDeposits() requires a currency code argument'); + throw new ArgumentsRequired (this.id + ': fetchDeposits() requires a currency code argument'); } const currency = this.currency (code); const request = { @@ -31819,7 +31100,7 @@ module.exports = class buda extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10}],56:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9}],55:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -33006,14 +32287,14 @@ module.exports = class bw extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10}],57:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9}],56:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- const Exchange = require ('./base/Exchange'); const { TICK_SIZE } = require ('./base/functions/number'); -const { AuthenticationError, ExchangeError, ArgumentsRequired, PermissionDenied, InvalidOrder, OrderNotFound, InsufficientFunds, BadRequest, RateLimitExceeded, InvalidNonce } = require ('./base/errors'); +const { AuthenticationError, ExchangeError, ArgumentsRequired, PermissionDenied, InvalidOrder, OrderNotFound, InsufficientFunds, BadRequest, RateLimitExceeded, InvalidNonce, NotSupported } = require ('./base/errors'); // --------------------------------------------------------------------------- @@ -33057,7 +32338,7 @@ module.exports = class bybit extends Exchange { '30m': '30', '1h': '60', '2h': '120', - '3h': '180', + '4h': '240', '6h': '360', '12h': '720', '1d': 'D', @@ -33072,6 +32353,7 @@ module.exports = class bybit extends Exchange { 'www': 'https://www.bybit.com/', 'doc': [ 'https://bybit-exchange.github.io/docs/inverse/', + 'https://bybit-exchange.github.io/docs/linear/', 'https://github.com/bybit-exchange', ], 'fees': 'https://help.bybit.com/hc/en-us/articles/360039261154', @@ -33125,6 +32407,41 @@ module.exports = class bybit extends Exchange { 'position/trading-stop', ], }, + 'publicLinear': { + 'get': [ + 'kline', + 'recent-trading-records', + 'funding/prev-funding-rate', + 'mark-price-kline', + ], + }, + 'privateLinear': { + 'get': [ + 'order/list', + 'order/search', + 'stop-order/list', + 'stop-order/search', + 'position/list', + 'position/set-auto-add-margin', + 'position/set-leverage', + 'position/switch-isolated', + 'position/trading-stop', + 'position/add-margin', + 'trade/execution/list', + 'trade/closed-pnl/list', + 'risk-limit', + 'funding/prev-funding', + 'funding/predicted-funding', + ], + 'post': [ + 'order/create', + 'order/cancel', + 'order/cancelAll', + 'stop-order/create', + 'stop-order/cancel', + 'stop-order/cancelAll', + ], + }, 'position': { 'post': [ 'change-position-margin', @@ -33236,6 +32553,9 @@ module.exports = class bybit extends Exchange { }, 'precisionMode': TICK_SIZE, 'options': { + 'marketTypes': { + 'BTC/USDT': 'linear', + }, 'code': 'BTC', 'fetchBalance': { 'code': 'BTC', @@ -33318,6 +32638,8 @@ module.exports = class bybit extends Exchange { // } // const markets = this.safeValue (response, 'result', []); + const options = this.safeValue (this.options, 'fetchMarkets', {}); + const linearQuoteCurrencies = this.safeValue (options, 'linear', { 'USDT': true }); const result = []; for (let i = 0; i < markets.length; i++) { const market = markets[i]; @@ -33326,6 +32648,8 @@ module.exports = class bybit extends Exchange { const quoteId = this.safeString (market, 'quote_currency'); const base = this.safeCurrencyCode (baseId); const quote = this.safeCurrencyCode (quoteId); + const linear = (quote in linearQuoteCurrencies); + const inverse = !linear; const symbol = base + '/' + quote; const lotSizeFilter = this.safeValue (market, 'lot_size_filter', {}); const priceFilter = this.safeValue (market, 'price_filter', {}); @@ -33342,6 +32666,12 @@ module.exports = class bybit extends Exchange { 'precision': precision, 'taker': this.safeFloat (market, 'taker_fee'), 'maker': this.safeFloat (market, 'maker_fee'), + 'type': 'future', + 'spot': false, + 'future': true, + 'option': false, + 'linear': linear, + 'inverse': inverse, 'limits': { 'amount': { 'min': this.safeFloat (lotSizeFilter, 'min_trading_qty'), @@ -33356,10 +32686,6 @@ module.exports = class bybit extends Exchange { 'max': undefined, }, }, - 'type': 'future', - 'spot': false, - 'future': true, - 'option': false, 'info': market, }); } @@ -33619,13 +32945,25 @@ module.exports = class bybit extends Exchange { // turnover: '162.32773718999994' // }, // + // { + // "id":143536, + // "symbol":"BTCUSDT", + // "period":"15", + // "start_at":1587883500, + // "volume":1.035, + // "open":7540.5, + // "high":7541, + // "low":7540.5, + // "close":7541 + // } + // return [ - this.safeTimestamp (ohlcv, 'open_time'), + this.safeTimestamp2 (ohlcv, 'open_time', 'start_at'), this.safeFloat (ohlcv, 'open'), this.safeFloat (ohlcv, 'high'), this.safeFloat (ohlcv, 'low'), this.safeFloat (ohlcv, 'close'), - this.safeFloat (ohlcv, 'turnover'), + this.safeFloat2 (ohlcv, 'turnover', 'volume'), ]; } @@ -33650,7 +32988,13 @@ module.exports = class bybit extends Exchange { if (limit !== undefined) { request['limit'] = limit; // max 200, default 200 } - const response = await this.publicGetKlineList (this.extend (request, params)); + const marketTypes = this.safeValue (this.options, 'marketTypes', {}); + const marketType = this.safeString (marketTypes, symbol); + const method = (marketType === 'linear') ? 'publicLinearGetKline' : 'publicGetKlineList'; + const response = await this[method] (this.extend (request, params)); + // + // inverse perpetual BTC/USD + // // { // ret_code: 0, // ret_msg: 'OK', @@ -33671,6 +33015,30 @@ module.exports = class bybit extends Exchange { // ], // time_now: '1583953082.397330' // } + // + // linear perpetual BTC/USDT + // + // { + // "ret_code":0, + // "ret_msg":"OK", + // "ext_code":"", + // "ext_info":"", + // "result":[ + // { + // "id":143536, + // "symbol":"BTCUSDT", + // "period":"15", + // "start_at":1587883500, + // "volume":1.035, + // "open":7540.5, + // "high":7541, + // "low":7540.5, + // "close":7541 + // } + // ], + // "time_now":"1587884120.168077" + // } + // const result = this.safeValue (response, 'result', {}); return this.parseOHLCVs (result, market, timeframe, since, limit); } @@ -33697,6 +33065,8 @@ module.exports = class bybit extends Exchange { // "exec_id": "256e5ef8-abfe-5772-971b-f944e15e0d68", // "exec_price": "8178.5", // "exec_qty": 1, + // // the docs say the exec_time field is "abandoned" now + // // the user should use "trade_time_ms" // "exec_time": "1571676941.70682", // "exec_type": "Trade", //Exec Type Enum // "exec_value": "0.00012227", @@ -33711,30 +33081,35 @@ module.exports = class bybit extends Exchange { // "order_type": "Market", //Order Type Enum // "side": "Buy", //Side Enum // "symbol": "BTCUSD", //Symbol Enum - // "user_id": 1 + // "user_id": 1, + // "trade_time_ms": 1577480599000 // } // const id = this.safeString2 (trade, 'id', 'exec_id'); let symbol = undefined; let base = undefined; const marketId = this.safeString (trade, 'symbol'); + let amount = this.safeFloat2 (trade, 'qty', 'exec_qty'); + let cost = this.safeFloat (trade, 'exec_value'); + const price = this.safeFloat2 (trade, 'price', 'exec_price'); if (marketId in this.markets_by_id) { market = this.markets_by_id[marketId]; symbol = market['symbol']; base = market['base']; } - if ((symbol === undefined) && (market !== undefined)) { - symbol = market['symbol']; - base = market['base']; + if (market !== undefined) { + if (symbol === undefined) { + symbol = market['symbol']; + base = market['base']; + } + // if private trade + if ('exec_fee' in trade) { + if (market['inverse']) { + amount = this.safeFloat (trade, 'exec_value'); + cost = this.safeFloat (trade, 'exec_qty'); + } + } } - let timestamp = this.parse8601 (this.safeString (trade, 'time')); - if (timestamp === undefined) { - timestamp = this.safeTimestamp (trade, 'exec_time'); - } - const side = this.safeStringLower (trade, 'side'); - const price = this.safeFloat2 (trade, 'price', 'exec_price'); - const amount = this.safeFloat2 (trade, 'qty', 'exec_qty'); - let cost = this.safeFloat (trade, 'exec_value'); if (cost === undefined) { if (amount !== undefined) { if (price !== undefined) { @@ -33742,6 +33117,11 @@ module.exports = class bybit extends Exchange { } } } + let timestamp = this.parse8601 (this.safeString (trade, 'time')); + if (timestamp === undefined) { + timestamp = this.safeInteger (trade, 'trade_time_ms'); + } + const side = this.safeStringLower (trade, 'side'); const lastLiquidityInd = this.safeString (trade, 'last_liquidity_ind'); const takerOrMaker = (lastLiquidityInd === 'AddedLiquidity') ? 'maker' : 'taker'; const feeCost = this.safeFloat (trade, 'exec_fee'); @@ -33780,7 +33160,10 @@ module.exports = class bybit extends Exchange { if (limit !== undefined) { request['count'] = limit; // default 500, max 1000 } - const response = await this.publicGetTradingRecords (this.extend (request, params)); + const marketTypes = this.safeValue (this.options, 'marketTypes', {}); + const marketType = this.safeString (marketTypes, symbol); + const method = (marketType === 'linear') ? 'publicLinearGetRecentTradingRecords' : 'publicGetTradingRecords'; + const response = await this[method] (this.extend (request, params)); // // { // ret_code: 0, @@ -33894,8 +33277,8 @@ module.exports = class bybit extends Exchange { // "last_exec_time": 0, // "last_exec_price": 0, // "leaves_qty": 1, - // "cum_exec_qty": 0, - // "cum_exec_value": 0, + // "cum_exec_qty": 0, // in contracts, where 1 contract = 1 quote currency unit (USD for inverse contracts) + // "cum_exec_value": 0, // in contract's underlying currency (BTC for inverse contracts) // "cum_exec_fee": 0, // "reject_reason": "", // "order_link_id": "", @@ -33903,18 +33286,69 @@ module.exports = class bybit extends Exchange { // "updated_at": "2019-11-30T11:03:43.455Z" // } // + // fetchOrder + // + // { + // "user_id" : 599946, + // "symbol" : "BTCUSD", + // "side" : "Buy", + // "order_type" : "Limit", + // "price" : "7948", + // "qty" : 10, + // "time_in_force" : "GoodTillCancel", + // "order_status" : "Filled", + // "ext_fields" : { + // "o_req_num" : -1600687220498, + // "xreq_type" : "x_create" + // }, + // "last_exec_time" : "1588150113.968422", + // "last_exec_price" : "7948", + // "leaves_qty" : 0, + // "leaves_value" : "0", + // "cum_exec_qty" : 10, + // "cum_exec_value" : "0.00125817", + // "cum_exec_fee" : "-0.00000031", + // "reject_reason" : "", + // "cancel_type" : "", + // "order_link_id" : "", + // "created_at" : "2020-04-29T08:45:24.399146Z", + // "updated_at" : "2020-04-29T08:48:33.968422Z", + // "order_id" : "dd2504b9-0157-406a-99e1-efa522373944" + // } + // + const marketId = this.safeString (order, 'symbol'); + let symbol = undefined; + let base = undefined; + if (marketId in this.markets_by_id) { + market = this.markets_by_id[marketId]; + } const timestamp = this.parse8601 (this.safeString (order, 'created_at')); const id = this.safeString (order, 'order_id'); const price = this.safeFloat (order, 'price'); const average = this.safeFloat (order, 'average_price'); - const amount = this.safeFloat (order, 'qty'); - let filled = this.safeFloat (order, 'cum_exec_qty'); - let remaining = this.safeFloat (order, 'leaves_qty'); + let amount = undefined; + let cost = undefined; + let filled = undefined; + let remaining = undefined; + if (market !== undefined) { + symbol = market['symbol']; + base = market['base']; + if (market['inverse']) { + cost = this.safeFloat (order, 'cum_exec_qty'); + filled = this.safeFloat (order, 'cum_exec_value'); + remaining = this.safeFloat (order, 'leaves_value'); + amount = this.sum (filled, remaining); + } else { + amount = this.safeFloat (order, 'qty'); + cost = this.safeFloat (order, 'cum_exec_value'); + filled = this.safeFloat (order, 'cum_exec_qty'); + remaining = this.safeFloat (order, 'leaves_qty'); + } + } let lastTradeTimestamp = this.safeTimestamp (order, 'last_exec_time'); if (lastTradeTimestamp === 0) { lastTradeTimestamp = undefined; } - let cost = this.safeFloat (order, 'cum_exec_value'); if ((filled === undefined) && (amount !== undefined) && (remaining !== undefined)) { filled = amount - remaining; } @@ -33929,22 +33363,6 @@ module.exports = class bybit extends Exchange { } } const status = this.parseOrderStatus (this.safeString (order, 'order_status')); - const marketId = this.safeString (order, 'symbol'); - let symbol = undefined; - let base = undefined; - if (marketId in this.markets_by_id) { - market = this.markets_by_id[marketId]; - symbol = market['symbol']; - base = market['base']; - } - if (market !== undefined) { - if (symbol === undefined) { - symbol = market['symbol']; - } - if (base === undefined) { - base = market['base']; - } - } const side = this.safeStringLower (order, 'side'); let feeCost = this.safeFloat (order, 'cum_exec_fee'); let fee = undefined; @@ -33996,7 +33414,9 @@ module.exports = class bybit extends Exchange { // conditional orders --------------------------------------------- // 'stop_order_id': id, // one of stop_order_id or order_link_id is required for conditional orders }; - let method = 'privateGetOrder'; + const marketTypes = this.safeValue (this.options, 'marketTypes', {}); + const marketType = this.safeString (marketTypes, symbol); + let method = (marketType === 'linear') ? 'privateLinearGetOrderSearch' : 'privateGetOrder'; const stopOrderId = this.safeString (params, 'stop_order_id'); if (stopOrderId === undefined) { const orderLinkId = this.safeString (params, 'order_link_id'); @@ -34004,7 +33424,7 @@ module.exports = class bybit extends Exchange { request['order_id'] = id; } } else { - method = 'privateGetStopOrder'; + method = (marketType === 'linear') ? 'privateLinearGetStopOrderSearch' : 'privateGetStopOrder'; } const response = await this[method] (this.extend (request, params)); // @@ -34116,12 +33536,14 @@ module.exports = class bybit extends Exchange { } const stopPx = this.safeValue (params, 'stop_px'); const basePrice = this.safeValue (params, 'base_price'); - let method = 'privatePostOrderCreate'; + const marketTypes = this.safeValue (this.options, 'marketTypes', {}); + const marketType = this.safeString (marketTypes, symbol); + let method = (marketType === 'linear') ? 'privateLinearPostOrderCreate' : 'privatePostOrderCreate'; if (stopPx !== undefined) { if (basePrice === undefined) { throw new ArgumentsRequired (this.id + ' createOrder requires both the stop_px and base_price params for a conditional ' + type + ' order'); } else { - method = 'openapiPostStopOrderCreate'; + method = (marketType === 'linear') ? 'privateLinearPostStopOrderCreate' : 'openapiPostStopOrderCreate'; request['stop_px'] = this.priceToPrecision (symbol, stopPx); request['base_price'] = this.priceToPrecision (symbol, basePrice); params = this.omit (params, [ 'stop_px', 'base_price' ]); @@ -34215,6 +33637,11 @@ module.exports = class bybit extends Exchange { if (symbol === undefined) { throw new ArgumentsRequired (this.id + ' editOrder requires an symbol argument'); } + const marketTypes = this.safeValue (this.options, 'marketTypes', {}); + const marketType = this.safeString (marketTypes, symbol); + if (marketType === 'linear') { + throw new NotSupported (this.id + ' does not support editOrder for ' + marketType + ' ' + symbol + ' market type'); + } await this.loadMarkets (); const market = this.market (symbol); const request = { @@ -34292,7 +33719,9 @@ module.exports = class bybit extends Exchange { // conditional orders --------------------------------------------- // 'stop_order_id': id, // one of stop_order_id or order_link_id is required for conditional orders }; - let method = 'privatePostOrderCancel'; + const marketTypes = this.safeValue (this.options, 'marketTypes', {}); + const marketType = this.safeValue (marketTypes, symbol); + let method = (marketType === 'linear') ? 'privateLinearPostOrderCancel' : 'privatePostOrderCancel'; const stopOrderId = this.safeString (params, 'stop_order_id'); if (stopOrderId === undefined) { const orderLinkId = this.safeString (params, 'order_link_id'); @@ -34300,7 +33729,7 @@ module.exports = class bybit extends Exchange { request['order_id'] = id; } } else { - method = 'openapiPostStopOrderCancel'; + method = (marketType === 'linear') ? 'privateLinearPostStopOrderCancel' : 'openapiPostStopOrderCancel'; } const response = await this[method] (this.extend (request, params)); const result = this.safeValue (response, 'result', {}); @@ -34317,7 +33746,10 @@ module.exports = class bybit extends Exchange { 'symbol': market['id'], }; const options = this.safeValue (this.options, 'cancelAllOrders'); - const method = this.safeString (options, 'method', 'privatePostOrderCancelAll'); + const marketTypes = this.safeValue (this.options, 'marketTypes', {}); + const marketType = this.safeString (marketTypes, symbol); + const defaultMethod = (marketType === 'linear') ? 'privateLinearPostOrderCancelAll' : 'privatePostOrderCancelAll'; + const method = this.safeString (options, 'method', defaultMethod); const response = await this[method] (this.extend (request, params)); const result = this.safeValue (response, 'result', []); return this.parseOrders (result, market); @@ -34346,7 +33778,9 @@ module.exports = class bybit extends Exchange { request['limit'] = limit; } const options = this.safeValue (this.options, 'fetchOrders', {}); - let defaultMethod = 'openapiGetOrderList'; + const marketTypes = this.safeValue (this.options, 'marketTypes', {}); + const marketType = this.safeString (marketTypes, symbol); + let defaultMethod = (marketType === 'linear') ? 'privateLinearGetOrderList' : 'openapiGetOrderList'; let query = params; if (('stop_order_id' in params) || ('stop_order_status' in params)) { let stopOrderStatus = this.safeValue (params, 'stopOrderStatus'); @@ -34357,7 +33791,7 @@ module.exports = class bybit extends Exchange { request['stop_order_status'] = stopOrderStatus; query = this.omit (params, 'stop_order_status'); } - defaultMethod = 'openapiGetStopOrderList'; + defaultMethod = (marketType === 'linear') ? 'privateLinearGetStopOrderList' : 'openapiGetStopOrderList'; } const method = this.safeString (options, 'method', defaultMethod); const response = await this[method] (this.extend (request, query)); @@ -34533,12 +33967,15 @@ module.exports = class bybit extends Exchange { request['symbol'] = market['id']; } if (since !== undefined) { - request['start_time'] = parseInt (since / 1000); + request['start_time'] = since; } if (limit !== undefined) { request['limit'] = limit; // default 20, max 50 } - const response = await this.privateGetExecutionList (this.extend (request, params)); + const marketTypes = this.safeValue (this.options, 'marketTypes', {}); + const marketType = this.safeString (marketTypes, symbol); + const method = (marketType === 'linear') ? 'privateLinearGetTradeExecutionList' : 'privateGetExecutionList'; + const response = await this[method] (this.extend (request, params)); // // { // "ret_code": 0, @@ -34873,6 +34310,11 @@ module.exports = class bybit extends Exchange { if (Object.keys (params).length) { request += '?' + this.rawencode (params); } + } else if (api === 'publicLinear') { + request = '/public/linear/' + request; + if (Object.keys (params).length) { + request += '?' + this.rawencode (params); + } } else { this.checkRequiredCredentials (); if (api === 'openapi') { @@ -34880,14 +34322,16 @@ module.exports = class bybit extends Exchange { } else if (api === 'private') { // private v2 request = '/' + this.version + '/' + api + '/' + request; + } else if (api === 'privateLinear') { + request = '/private/linear/' + request; } else { // position, user - request += '/' + api + '/' + request; + request = '/' + api + '/' + request; } const timestamp = this.nonce (); const query = this.extend (params, { 'api_key': this.apiKey, - 'recvWindow': this.options['recvWindow'], + 'recv_window': this.options['recvWindow'], 'timestamp': timestamp, }); const auth = this.rawencode (this.keysort (query)); @@ -34933,7 +34377,7 @@ module.exports = class bybit extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10,"./base/functions/number":16}],58:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9,"./base/functions/number":15}],57:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -34983,9 +34427,15 @@ module.exports = class bytetrade extends Exchange { '1M': '1M', }, 'urls': { - 'test': 'https://api-v2-test.byte-trade.com', + 'test': { + 'market': 'https://api-v2-test.byte-trade.com', + 'public': 'https://api-v2-test.byte-trade.com', + }, 'logo': 'https://user-images.githubusercontent.com/1294454/67288762-2f04a600-f4e6-11e9-9fd6-c60641919491.jpg', - 'api': 'https://api-v2.byte-trade.com', + 'api': { + 'market': 'https://api-v2.bytetrade.com', + 'public': 'https://api-v2.bytetrade.com', + }, 'www': 'https://www.byte-trade.com', 'doc': 'https://github.com/Bytetrade/bytetrade-official-api-docs/wiki', }, @@ -36158,7 +35608,7 @@ module.exports = class bytetrade extends Exchange { this.numberToLE (address.length, 1), this.stringToBinary (this.encode (address)), this.numberToLE (parseInt (coinId), 4), - this.numberToLE (Math.floor (parseInt (parseFloat (this.integerDivide (amountChain, eightBytes)))), 8), + this.numberToLE (this.integerDivide (amountChain, eightBytes), 8), this.numberToLE (this.integerModulo (amountChain, eightBytes), 8), this.numberToLE (1, 1), this.numberToLE (this.integerDivide (assetFee, eightBytes), 8), @@ -36191,7 +35641,7 @@ module.exports = class bytetrade extends Exchange { this.numberToLE (middleAddress.length, 1), this.stringToBinary (this.encode (middleAddress)), this.numberToLE (parseInt (coinId), 4), - this.numberToLE (Math.floor (parseInt (parseFloat (this.integerDivide (amountChain, eightBytes)))), 8), + this.numberToLE (this.integerDivide (amountChain, eightBytes), 8), this.numberToLE (this.integerModulo (amountChain, eightBytes), 8), this.numberToLE (0, 1), this.numberToLE (1, 1), @@ -36294,7 +35744,7 @@ module.exports = class bytetrade extends Exchange { } sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) { - let url = this.urls['api']; + let url = this.urls['api'][api]; url += '/' + path; if (Object.keys (params).length) { url += '?' + this.urlencode (params); @@ -36321,7 +35771,7 @@ module.exports = class bytetrade extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10,"./base/functions/number":16}],59:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9,"./base/functions/number":15}],58:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -36888,9 +36338,45 @@ module.exports = class cex extends Exchange { request['order_type'] = type; } const response = await this.privatePostPlaceOrderPair (this.extend (request, params)); + // + // { + // "id": "12978363524", + // "time": 1586610022259, + // "type": "buy", + // "price": "0.033934", + // "amount": "0.10722802", + // "pending": "0.10722802", + // "complete": false + // } + // + const placedAmount = this.safeFloat (response, 'amount'); + const remaining = this.safeFloat (response, 'pending'); + const timestamp = this.safeValue (response, 'time'); + const complete = this.safeValue (response, 'complete'); + const status = complete ? 'closed' : 'open'; + let filled = undefined; + if ((placedAmount !== undefined) && (remaining !== undefined)) { + filled = Math.max (placedAmount - remaining, 0); + } return { + 'id': this.safeString (response, 'id'), 'info': response, - 'id': response['id'], + 'clientOrderId': undefined, + 'timestamp': timestamp, + 'datetime': this.iso8601 (timestamp), + 'lastTradeTimestamp': undefined, + 'type': type, + 'side': this.safeString (response, 'type'), + 'symbol': symbol, + 'status': status, + 'price': this.safeFloat (response, 'price'), + 'amount': placedAmount, + 'cost': undefined, + 'average': undefined, + 'remaining': remaining, + 'filled': filled, + 'fee': undefined, + 'trades': undefined, }; } @@ -37506,7 +36992,7 @@ module.exports = class cex extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10}],60:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9}],59:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -37540,7 +37026,7 @@ module.exports = class chilebit extends foxbit { } }; -},{"./foxbit.js":85}],61:[function(require,module,exports){ +},{"./foxbit.js":84}],60:[function(require,module,exports){ 'use strict'; // ---------------------------------------------------------------------------- @@ -38727,7 +38213,7 @@ module.exports = class coinbase extends Exchange { }; -},{"./base/Exchange":8,"./base/errors":10}],62:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9}],61:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -38760,7 +38246,7 @@ module.exports = class coinbaseprime extends coinbasepro { } }; -},{"./coinbasepro.js":63}],63:[function(require,module,exports){ +},{"./coinbasepro.js":62}],62:[function(require,module,exports){ 'use strict'; // ---------------------------------------------------------------------------- @@ -39723,7 +39209,7 @@ module.exports = class coinbasepro extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10}],64:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9}],63:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -40158,7 +39644,7 @@ module.exports = class coincheck extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10}],65:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9}],64:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -40665,7 +40151,7 @@ module.exports = class coinegg extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10}],66:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9}],65:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -41580,7 +41066,7 @@ module.exports = class coinex extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10}],67:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9}],66:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -42031,7 +41517,7 @@ module.exports = class coinfalcon extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10}],68:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9}],67:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -42554,7 +42040,7 @@ module.exports = class coinfloor extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10}],69:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9}],68:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -42903,7 +42389,7 @@ module.exports = class coingi extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10}],70:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9}],69:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -43237,7 +42723,7 @@ module.exports = class coinmarketcap extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10}],71:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9}],70:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -43801,6 +43287,7 @@ module.exports = class coinmate extends Exchange { const statuses = { 'FILLED': 'closed', 'CANCELLED': 'canceled', + 'PARTIALLY_FILLED': 'open', 'OPEN': 'open', }; return this.safeString (statuses, status, status); @@ -43863,12 +43350,15 @@ module.exports = class coinmate extends Exchange { const price = this.safeFloat (order, 'price'); const amount = this.safeFloat2 (order, 'originalAmount', 'amount'); const remaining = this.safeFloat (order, 'remainingAmount', amount); - const status = this.parseOrderStatus (this.safeString (order, 'status')); + let status = this.parseOrderStatus (this.safeString (order, 'status')); const type = this.parseOrderType (this.safeString (order, 'orderTradeType')); let filled = undefined; let cost = undefined; if ((amount !== undefined) && (remaining !== undefined)) { - filled = amount - remaining; + filled = Math.min (amount - remaining, 0); + if (remaining === 0) { + status = 'closed'; + } if (price !== undefined) { cost = filled * price; } @@ -44014,7 +43504,7 @@ module.exports = class coinmate extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10}],72:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9}],71:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -44541,7 +44031,7 @@ module.exports = class coinone extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10}],73:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9}],72:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -44714,7 +44204,7 @@ module.exports = class coinspot extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10}],74:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9}],73:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -44786,7 +44276,7 @@ module.exports = class coolcoin extends coinegg { } }; -},{"./coinegg.js":65}],75:[function(require,module,exports){ +},{"./coinegg.js":64}],74:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -45731,7 +45221,7 @@ module.exports = class coss extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10}],76:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9}],75:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -45863,7 +45353,6 @@ module.exports = class crex24 extends Exchange { 'fetchClosedOrdersMethod': 'tradingGetOrderHistory', // or 'tradingGetActiveOrders' 'fetchTickersMethod': 'publicGetTicker24hr', 'defaultTimeInForce': 'GTC', // 'GTC' = Good To Cancel (default), 'IOC' = Immediate Or Cancel - 'defaultLimitOrderType': 'limit', // or 'limit_maker' 'hasAlreadyAuthenticatedSuccessfully': false, 'warnOnFetchOpenOrdersWithoutSymbol': true, 'parseOrderToPrecision': false, // force amounts and costs in parseOrder to precision @@ -47035,7 +46524,7 @@ module.exports = class crex24 extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10}],77:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9}],76:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -47563,11 +47052,13 @@ module.exports = class deribit extends Exchange { 'info': response, }; const balance = this.safeValue (response, 'result', {}); + const currencyId = this.safeString (balance, 'currency'); + const currencyCode = this.safeCurrencyCode (currencyId); const account = this.account (); account['free'] = this.safeFloat (balance, 'availableFunds'); account['used'] = this.safeFloat (balance, 'maintenanceMargin'); account['total'] = this.safeFloat (balance, 'equity'); - result[code] = account; + result[currencyCode] = account; return this.parseBalance (result); } @@ -47921,7 +47412,7 @@ module.exports = class deribit extends Exchange { // M = maker, T = taker, MT = both takerOrMaker = (liquidity === 'M') ? 'maker' : 'taker'; } - const feeCost = this.safeFloat (trade, 'feeCost'); + const feeCost = this.safeFloat (trade, 'fee'); let fee = undefined; if (feeCost !== undefined) { const feeCurrencyId = this.safeString (trade, 'fee_currency'); @@ -48749,7 +48240,7 @@ module.exports = class deribit extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10,"./base/functions/number":16}],78:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9,"./base/functions/number":15}],77:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -49928,7 +49419,7 @@ module.exports = class digifinex extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10}],79:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9}],78:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -51200,13 +50691,13 @@ module.exports = class dsx extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10}],80:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9}],79:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- const Exchange = require ('./base/Exchange'); -const { ArgumentsRequired, ExchangeError, OrderNotFound, AuthenticationError, InsufficientFunds, InvalidOrder, InvalidNonce, NotSupported, OnMaintenance, RateLimitExceeded } = require ('./base/errors'); +const { ArgumentsRequired, ExchangeError, OrderNotFound, AuthenticationError, InsufficientFunds, InvalidOrder, InvalidNonce, NotSupported, OnMaintenance, RateLimitExceeded, BadRequest, PermissionDenied } = require ('./base/errors'); // --------------------------------------------------------------------------- @@ -51217,7 +50708,7 @@ module.exports = class exmo extends Exchange { 'name': 'EXMO', 'countries': [ 'ES', 'RU' ], // Spain, Russia 'rateLimit': 350, // once every 350 ms ≈ 180 requests per minute ≈ 3 requests per second - 'version': 'v1', + 'version': 'v1.1', 'has': { 'CORS': false, 'fetchClosedOrders': 'emulated', @@ -51235,6 +50726,21 @@ module.exports = class exmo extends Exchange { 'fetchFundingFees': true, 'fetchCurrencies': true, 'fetchTransactions': true, + 'fetchOHLCV': true, + }, + 'timeframes': { + '1m': '1', + '5m': '5', + '15m': '15', + '30m': '30', + '45m': '45', + '1h': '60', + '2h': '120', + '3h': '180', + '4h': '240', + '1d': 'D', + '1w': 'W', + '1M': 'M', }, 'urls': { 'logo': 'https://user-images.githubusercontent.com/1294454/27766491-1b0ea956-5eda-11e7-9225-40d67b481b8d.jpg', @@ -51265,6 +50771,7 @@ module.exports = class exmo extends Exchange { 'pair_settings', 'ticker', 'trades', + 'candles_history', ], }, 'private': { @@ -51272,6 +50779,8 @@ module.exports = class exmo extends Exchange { 'user_info', 'order_create', 'order_cancel', + 'stop_market_order_create', + 'stop_market_order_cancel', 'user_open_orders', 'user_trades', 'user_cancelled_orders', @@ -51306,86 +50815,90 @@ module.exports = class exmo extends Exchange { 'error': '', 'data': { 'limits': [ - { 'pair': 'EXM/USDT', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '100000' }, - { 'pair': 'EXM/ETH', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '5000' }, + { 'pair': 'ALGO/EXM', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.001', 'max_p': '10000', 'min_a': '1', 'max_a': '50000000' }, + { 'pair': 'ALGO/BTC', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.000001', 'max_a': '50' }, + { 'pair': 'ATOM/EXM', 'min_q': '1', 'max_q': '500000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '200', 'max_a': '50000000' }, + { 'pair': 'ATOM/BTC', 'min_q': '1', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, { 'pair': 'BTC/USD', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '1', 'max_p': '30000', 'min_a': '1', 'max_a': '500000' }, - { 'pair': 'BTC/KZT', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '1000', 'max_p': '12000000', 'min_a': '1000', 'max_a': '100000000' }, - { 'pair': 'ETH/KZT', 'min_q': '0.001', 'max_q': '5000', 'min_p': '4', 'max_p': '40000000', 'min_a': '3', 'max_a': '500000' }, - { 'pair': 'USDT/KZT', 'min_q': '1', 'max_q': '500000', 'min_p': '200', 'max_p': '4000', 'min_a': '0.1', 'max_a': '500000' }, - { 'pair': 'ONT/EXM', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '200', 'max_a': '15000000' }, - { 'pair': 'ONT/BTC', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.00001', 'max_a': '10' }, - { 'pair': 'ONT/RUB', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '100', 'max_a': '6000000' }, - { 'pair': 'ONT/UAH', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '200', 'max_a': '250000' }, - { 'pair': 'ONG/EXM', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '100', 'max_a': '15000000' }, - { 'pair': 'ONG/BTC', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.00001', 'max_a': '10' }, - { 'pair': 'ONG/RUB', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '100', 'max_a': '250000' }, - { 'pair': 'ONG/UAH', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '50', 'max_a': '6000000' }, - { 'pair': 'CRON/BTC', 'min_q': '1', 'max_q': '100000', 'min_p': '0.0000001', 'max_p': '1', 'min_a': '0.00001', 'max_a': '100' }, - { 'pair': 'CRON/ETH', 'min_q': '1', 'max_q': '100000', 'min_p': '0.0000001', 'max_p': '10', 'min_a': '0.00001', 'max_a': '5000' }, - { 'pair': 'CRON/USDT', 'min_q': '1', 'max_q': '100000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.001', 'max_a': '500000' }, - { 'pair': 'CRON/EXM', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '100000' }, { 'pair': 'BTC/RUB', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '1', 'max_p': '2000000', 'min_a': '10', 'max_a': '50000000' }, { 'pair': 'BTC/EUR', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '1', 'max_p': '30000', 'min_a': '1', 'max_a': '500000' }, { 'pair': 'BTC/UAH', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '1', 'max_p': '15000000', 'min_a': '10', 'max_a': '15000000' }, + { 'pair': 'BTC/GBP', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '1', 'max_p': '30000', 'min_a': '1', 'max_a': '500000' }, + { 'pair': 'ETH/GBP', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '3', 'max_a': '500000' }, + { 'pair': 'XRP/GBP', 'min_q': '1', 'max_q': '5000000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.001', 'max_a': '500000' }, + { 'pair': 'USDT/GBP', 'min_q': '1', 'max_q': '500000', 'min_p': '0.5', 'max_p': '10', 'min_a': '0.1', 'max_a': '500000' }, { 'pair': 'BTC/PLN', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '1', 'max_p': '20000000', 'min_a': '50', 'max_a': '2000000' }, { 'pair': 'BTC/TRY', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '1', 'max_p': '800000', 'min_a': '40', 'max_a': '6000000' }, + { 'pair': 'BTC/KZT', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '1000', 'max_p': '12000000', 'min_a': '1000', 'max_a': '100000000' }, { 'pair': 'BTC/USDT', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '0.01', 'max_p': '30000', 'min_a': '3', 'max_a': '500000' }, { 'pair': 'ETH/BTC', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.001', 'max_a': '100' }, { 'pair': 'ETH/USD', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '3', 'max_a': '500000' }, { 'pair': 'ETH/RUB', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '150', 'max_a': '50000000' }, - { 'pair': 'XRP/BTC', 'min_q': '1', 'max_q': '100000', 'min_p': '0.0000001', 'max_p': '1', 'min_a': '0.00001', 'max_a': '100' }, - { 'pair': 'XRP/USD', 'min_q': '1', 'max_q': '100000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.001', 'max_a': '500000' }, - { 'pair': 'XRP/RUB', 'min_q': '1', 'max_q': '100000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '50000000' }, + { 'pair': 'XRP/BTC', 'min_q': '1', 'max_q': '5000000', 'min_p': '0.0000001', 'max_p': '1', 'min_a': '0.00001', 'max_a': '100' }, + { 'pair': 'XRP/USD', 'min_q': '1', 'max_q': '5000000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.001', 'max_a': '500000' }, + { 'pair': 'XRP/RUB', 'min_q': '1', 'max_q': '5000000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '50000000' }, { 'pair': 'ADA/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, { 'pair': 'ADA/ETH', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.001', 'max_a': '5000' }, { 'pair': 'ADA/USD', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '500000' }, - { 'pair': 'BCH/USD', 'min_q': '0.003', 'max_q': '10000', 'min_p': '0.00000001', 'max_p': '30000', 'min_a': '0.0001', 'max_a': '500000' }, - { 'pair': 'BCH/RUB', 'min_q': '0.003', 'max_q': '10000', 'min_p': '0.00000001', 'max_p': '2000000', 'min_a': '0.0001', 'max_a': '50000000' }, - { 'pair': 'BCH/EUR', 'min_q': '0.003', 'max_q': '100000', 'min_p': '0.01', 'max_p': '300000', 'min_a': '3', 'max_a': '500000' }, - { 'pair': 'BCH/UAH', 'min_q': '0.003', 'max_q': '100000', 'min_p': '0.1', 'max_p': '30000', 'min_a': '10', 'max_a': '15000000' }, - { 'pair': 'BCH/BTC', 'min_q': '0.003', 'max_q': '10000', 'min_p': '0.00000001', 'max_p': '5', 'min_a': '0.0001', 'max_a': '100' }, - { 'pair': 'BCH/ETH', 'min_q': '0.003', 'max_q': '10000', 'min_p': '0.0000001', 'max_p': '200', 'min_a': '0.0001', 'max_a': '5000' }, - { 'pair': 'BCH/USDT', 'min_q': '0.003', 'max_q': '100000', 'min_p': '0.01', 'max_p': '5000', 'min_a': '3', 'max_a': '500000' }, + { 'pair': 'ALGO/USDT', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '1', 'max_a': '500000' }, + { 'pair': 'ALGO/RUB', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.000001', 'max_p': '10000', 'min_a': '1', 'max_a': '50000000' }, + { 'pair': 'ALGO/EUR', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '1', 'max_a': '500000' }, + { 'pair': 'ATOM/USD', 'min_q': '1', 'max_q': '500000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.5', 'max_a': '500000' }, + { 'pair': 'ATOM/EUR', 'min_q': '1', 'max_q': '500000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.5', 'max_a': '500000' }, + { 'pair': 'BCH/USD', 'min_q': '0.003', 'max_q': '5000', 'min_p': '0.00000001', 'max_p': '30000', 'min_a': '0.0001', 'max_a': '500000' }, + { 'pair': 'BCH/RUB', 'min_q': '0.003', 'max_q': '5000', 'min_p': '0.00000001', 'max_p': '2000000', 'min_a': '0.0001', 'max_a': '50000000' }, + { 'pair': 'BCH/EUR', 'min_q': '0.003', 'max_q': '5000', 'min_p': '0.01', 'max_p': '300000', 'min_a': '3', 'max_a': '500000' }, + { 'pair': 'BCH/UAH', 'min_q': '0.003', 'max_q': '5000', 'min_p': '0.1', 'max_p': '30000', 'min_a': '10', 'max_a': '15000000' }, + { 'pair': 'BCH/BTC', 'min_q': '0.003', 'max_q': '5000', 'min_p': '0.00000001', 'max_p': '5', 'min_a': '0.0001', 'max_a': '100' }, + { 'pair': 'BCH/ETH', 'min_q': '0.003', 'max_q': '5000', 'min_p': '0.0000001', 'max_p': '200', 'min_a': '0.0001', 'max_a': '5000' }, + { 'pair': 'BCH/USDT', 'min_q': '0.003', 'max_q': '5000', 'min_p': '0.01', 'max_p': '5000', 'min_a': '3', 'max_a': '500000' }, { 'pair': 'BTCZ/BTC', 'min_q': '100', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, - { 'pair': 'BTG/USD', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '3', 'max_a': '500000' }, - { 'pair': 'BTG/BTC', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, - { 'pair': 'BTG/ETH', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.0001', 'max_p': '100', 'min_a': '0.01', 'max_a': '5000' }, - { 'pair': 'BTT/RUB', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '0.000001', 'max_a': '100' }, - { 'pair': 'BTT/UAH', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '0.000001', 'max_a': '100' }, - { 'pair': 'BTT/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '0.1', 'min_a': '0.00001', 'max_a': '100' }, + { 'pair': 'BTG/USD', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '3', 'max_a': '500000' }, + { 'pair': 'BTG/BTC', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, + { 'pair': 'BTG/ETH', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.0001', 'max_p': '100', 'min_a': '0.01', 'max_a': '5000' }, + { 'pair': 'BTT/RUB', 'min_q': '1', 'max_q': '500000000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '0.000001', 'max_a': '100' }, + { 'pair': 'BTT/UAH', 'min_q': '1', 'max_q': '500000000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '0.000001', 'max_a': '100' }, + { 'pair': 'BTT/BTC', 'min_q': '1', 'max_q': '500000000', 'min_p': '0.00000001', 'max_p': '0.1', 'min_a': '0.00001', 'max_a': '100' }, + { 'pair': 'CRON/BTC', 'min_q': '1', 'max_q': '100000', 'min_p': '0.0000001', 'max_p': '1', 'min_a': '0.00001', 'max_a': '100' }, + { 'pair': 'CRON/ETH', 'min_q': '1', 'max_q': '100000', 'min_p': '0.0000001', 'max_p': '10', 'min_a': '0.00001', 'max_a': '5000' }, + { 'pair': 'CRON/USDT', 'min_q': '1', 'max_q': '100000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.001', 'max_a': '500000' }, + { 'pair': 'CRON/EXM', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '100000' }, { 'pair': 'DAI/USD', 'min_q': '1', 'max_q': '500000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000' }, { 'pair': 'DAI/RUB', 'min_q': '1', 'max_q': '500000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '0.5', 'max_a': '30000000' }, { 'pair': 'DAI/BTC', 'min_q': '1', 'max_q': '500000', 'min_p': '0.0000001', 'max_p': '0.1', 'min_a': '0.00001', 'max_a': '100' }, { 'pair': 'DAI/ETH', 'min_q': '1', 'max_q': '500000', 'min_p': '0.000001', 'max_p': '10', 'min_a': '0.0001', 'max_a': '5000' }, - { 'pair': 'DASH/USD', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '3', 'max_a': '500000' }, - { 'pair': 'DASH/RUB', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '150', 'max_a': '50000000' }, - { 'pair': 'DASH/UAH', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.01', 'max_p': '200000', 'min_a': '10', 'max_a': '15000000' }, - { 'pair': 'DASH/BTC', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.0001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, - { 'pair': 'DASH/USDT', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.01', 'max_p': '5000', 'min_a': '3', 'max_a': '500000' }, + { 'pair': 'DASH/USD', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '3', 'max_a': '500000' }, + { 'pair': 'DASH/RUB', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '150', 'max_a': '50000000' }, + { 'pair': 'DASH/UAH', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.01', 'max_p': '200000', 'min_a': '10', 'max_a': '15000000' }, + { 'pair': 'DASH/BTC', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.0001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, + { 'pair': 'DASH/USDT', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.01', 'max_p': '5000', 'min_a': '3', 'max_a': '500000' }, { 'pair': 'DCR/RUB', 'min_q': '0.01', 'max_q': '50000', 'min_p': '0.00001', 'max_p': '100000', 'min_a': '0.5', 'max_a': '3000000' }, { 'pair': 'DCR/UAH', 'min_q': '0.01', 'max_q': '50000', 'min_p': '0.00001', 'max_p': '100000', 'min_a': '0.25', 'max_a': '1000000' }, { 'pair': 'DCR/BTC', 'min_q': '0.01', 'max_q': '50000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, - { 'pair': 'DOGE/USD', 'min_q': '100', 'max_q': '1000000000', 'min_p': '0.0000001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '500000' }, - { 'pair': 'DOGE/BTC', 'min_q': '100', 'max_q': '100000000', 'min_p': '0.0000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '100' }, - { 'pair': 'DXT/USD', 'min_q': '100', 'max_q': '10000000', 'min_p': '0.00001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000' }, - { 'pair': 'DXT/BTC', 'min_q': '100', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '100' }, - { 'pair': 'EOS/USD', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.01', 'max_p': '1000', 'min_a': '0.5', 'max_a': '500000' }, - { 'pair': 'EOS/EUR', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.5', 'max_a': '500000' }, - { 'pair': 'EOS/BTC', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, - { 'pair': 'ETC/USD', 'min_q': '0.2', 'max_q': '1000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '0.01', 'max_a': '500000' }, - { 'pair': 'ETC/RUB', 'min_q': '0.2', 'max_q': '1000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '0.01', 'max_a': '50000000' }, - { 'pair': 'ETC/BTC', 'min_q': '0.2', 'max_q': '1000', 'min_p': '0.0001', 'max_p': '0.5', 'min_a': '0.001', 'max_a': '100' }, + { 'pair': 'DOGE/USD', 'min_q': '100', 'max_q': '500000000', 'min_p': '0.0000001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '500000' }, + { 'pair': 'DOGE/BTC', 'min_q': '100', 'max_q': '500000000', 'min_p': '0.0000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '100' }, + { 'pair': 'DXT/USD', 'min_q': '100', 'max_q': '50000000', 'min_p': '0.00001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000' }, + { 'pair': 'DXT/BTC', 'min_q': '100', 'max_q': '50000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '100' }, + { 'pair': 'EOS/USD', 'min_q': '0.01', 'max_q': '500000', 'min_p': '0.01', 'max_p': '1000', 'min_a': '0.5', 'max_a': '500000' }, + { 'pair': 'EOS/EUR', 'min_q': '0.01', 'max_q': '500000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.5', 'max_a': '500000' }, + { 'pair': 'EOS/BTC', 'min_q': '0.01', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, + { 'pair': 'ETC/USD', 'min_q': '0.2', 'max_q': '100000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '0.01', 'max_a': '500000' }, + { 'pair': 'ETC/RUB', 'min_q': '0.2', 'max_q': '100000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '0.01', 'max_a': '50000000' }, + { 'pair': 'ETC/BTC', 'min_q': '0.2', 'max_q': '100000', 'min_p': '0.0001', 'max_p': '0.5', 'min_a': '0.001', 'max_a': '100' }, { 'pair': 'ETH/EUR', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '3', 'max_a': '500000' }, { 'pair': 'ETH/UAH', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.01', 'max_p': '1000000', 'min_a': '90', 'max_a': '15000000' }, { 'pair': 'ETH/PLN', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '50', 'max_a': '2000000' }, { 'pair': 'ETH/TRY', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.1', 'max_p': '80000', 'min_a': '10', 'max_a': '6000000' }, + { 'pair': 'ETH/KZT', 'min_q': '0.001', 'max_q': '5000', 'min_p': '4', 'max_p': '40000000', 'min_a': '3', 'max_a': '500000' }, { 'pair': 'ETH/USDT', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '3', 'max_a': '500000' }, { 'pair': 'ETH/LTC', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.00000001', 'max_p': '100000', 'min_a': '0.05', 'max_a': '100000' }, - { 'pair': 'ETZ/BTC', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '10' }, - { 'pair': 'ETZ/ETH', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.00000001', 'max_p': '100', 'min_a': '0.001', 'max_a': '100' }, - { 'pair': 'ETZ/USDT', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '1000' }, - { 'pair': 'GAS/USD', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.01', 'max_p': '50000', 'min_a': '0.1', 'max_a': '500000' }, - { 'pair': 'GAS/BTC', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, + { 'pair': 'ETZ/BTC', 'min_q': '1', 'max_q': '50000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '10' }, + { 'pair': 'ETZ/ETH', 'min_q': '1', 'max_q': '50000000', 'min_p': '0.00000001', 'max_p': '100', 'min_a': '0.001', 'max_a': '100' }, + { 'pair': 'ETZ/USDT', 'min_q': '1', 'max_q': '50000000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '1000' }, + { 'pair': 'EXM/USDT', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '100000' }, + { 'pair': 'EXM/ETH', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '5000' }, + { 'pair': 'GAS/USD', 'min_q': '0.01', 'max_q': '500000', 'min_p': '0.01', 'max_p': '50000', 'min_a': '0.1', 'max_a': '500000' }, + { 'pair': 'GAS/BTC', 'min_q': '0.01', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, { 'pair': 'GNT/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, { 'pair': 'GNT/ETH', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.01', 'max_a': '5000' }, { 'pair': 'GUSD/USD', 'min_q': '1', 'max_q': '500000', 'min_p': '0.1', 'max_p': '10', 'min_a': '0.1', 'max_a': '500000' }, @@ -51400,84 +50913,94 @@ module.exports = class exmo extends Exchange { { 'pair': 'KICK/USDT', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '100000' }, { 'pair': 'KICK/BTC', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '0.1', 'min_a': '0.00001', 'max_a': '100' }, { 'pair': 'KICK/ETH', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '5000' }, - { 'pair': 'LSK/USD', 'min_q': '0.1', 'max_q': '200000', 'min_p': '0.1', 'max_p': '1000', 'min_a': '1', 'max_a': '500000' }, - { 'pair': 'LSK/RUB', 'min_q': '0.1', 'max_q': '200000', 'min_p': '0.001', 'max_p': '100000', 'min_a': '0.5', 'max_a': '50000000' }, - { 'pair': 'LSK/BTC', 'min_q': '1', 'max_q': '200000', 'min_p': '0.0000001', 'max_p': '1', 'min_a': '0.0015', 'max_a': '100' }, - { 'pair': 'LTC/USD', 'min_q': '0.05', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '3', 'max_a': '500000' }, - { 'pair': 'LTC/RUB', 'min_q': '0.05', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '150', 'max_a': '50000000' }, - { 'pair': 'LTC/EUR', 'min_q': '0.05', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '3', 'max_a': '500000' }, - { 'pair': 'LTC/UAH', 'min_q': '0.05', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '300000', 'min_a': '5', 'max_a': '18000000' }, - { 'pair': 'LTC/BTC', 'min_q': '0.05', 'max_q': '1000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, + { 'pair': 'LSK/USD', 'min_q': '0.1', 'max_q': '500000', 'min_p': '0.1', 'max_p': '1000', 'min_a': '1', 'max_a': '500000' }, + { 'pair': 'LSK/RUB', 'min_q': '0.1', 'max_q': '500000', 'min_p': '0.001', 'max_p': '100000', 'min_a': '0.5', 'max_a': '50000000' }, + { 'pair': 'LSK/BTC', 'min_q': '1', 'max_q': '500000', 'min_p': '0.0000001', 'max_p': '1', 'min_a': '0.0015', 'max_a': '100' }, + { 'pair': 'LTC/USD', 'min_q': '0.05', 'max_q': '10000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '3', 'max_a': '500000' }, + { 'pair': 'LTC/RUB', 'min_q': '0.05', 'max_q': '10000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '150', 'max_a': '50000000' }, + { 'pair': 'LTC/EUR', 'min_q': '0.05', 'max_q': '10000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '3', 'max_a': '500000' }, + { 'pair': 'LTC/UAH', 'min_q': '0.05', 'max_q': '10000', 'min_p': '0.01', 'max_p': '300000', 'min_a': '5', 'max_a': '18000000' }, + { 'pair': 'LTC/BTC', 'min_q': '0.05', 'max_q': '10000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, { 'pair': 'MKR/BTC', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '0.0001', 'max_p': '100', 'min_a': '0.000001', 'max_a': '100' }, { 'pair': 'MKR/DAI', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '0.5', 'max_p': '500000', 'min_a': '0.005', 'max_a': '500000' }, - { 'pair': 'MNC/USD', 'min_q': '10', 'max_q': '100000000', 'min_p': '0.000001', 'max_p': '10000', 'min_a': '0.01', 'max_a': '100000' }, - { 'pair': 'MNC/BTC', 'min_q': '10', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.000001', 'max_a': '100' }, - { 'pair': 'MNC/ETH', 'min_q': '10', 'max_q': '100000000', 'min_p': '0.0000001', 'max_p': '10', 'min_a': '0.00001', 'max_a': '1000' }, + { 'pair': 'MNC/USD', 'min_q': '10', 'max_q': '500000000', 'min_p': '0.000001', 'max_p': '10000', 'min_a': '0.01', 'max_a': '100000' }, + { 'pair': 'MNC/BTC', 'min_q': '10', 'max_q': '500000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.000001', 'max_a': '100' }, + { 'pair': 'MNC/ETH', 'min_q': '10', 'max_q': '500000000', 'min_p': '0.0000001', 'max_p': '10', 'min_a': '0.00001', 'max_a': '1000' }, { 'pair': 'MNX/USD', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.5', 'max_a': '500000' }, { 'pair': 'MNX/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, { 'pair': 'MNX/ETH', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.01', 'max_a': '5000' }, - { 'pair': 'NEO/USD', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.01', 'max_p': '50000', 'min_a': '0.1', 'max_a': '500000' }, - { 'pair': 'NEO/RUB', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.001', 'max_p': '1500000', 'min_a': '50', 'max_a': '50000000' }, - { 'pair': 'NEO/BTC', 'min_q': '0.1', 'max_q': '200000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, - { 'pair': 'OMG/USD', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.01', 'max_p': '1000', 'min_a': '0.5', 'max_a': '500000' }, - { 'pair': 'OMG/BTC', 'min_q': '1', 'max_q': '100000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, - { 'pair': 'OMG/ETH', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.01', 'max_a': '5000' }, - { 'pair': 'PTI/RUB', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '600000', 'min_a': '10', 'max_a': '600000' }, - { 'pair': 'PTI/BTC', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.000001', 'max_a': '10' }, - { 'pair': 'PTI/EOS', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.0000001', 'max_p': '5000', 'min_a': '0.01', 'max_a': '20000' }, - { 'pair': 'PTI/USDT', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.000001', 'max_p': '10000', 'min_a': '0.01', 'max_a': '100000' }, - { 'pair': 'QTUM/USD', 'min_q': '0.1', 'max_q': '200000', 'min_p': '0.00000001', 'max_p': '10000', 'min_a': '0.1', 'max_a': '500000' }, - { 'pair': 'QTUM/BTC', 'min_q': '0.1', 'max_q': '200000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '100' }, - { 'pair': 'QTUM/ETH', 'min_q': '0.1', 'max_q': '200000', 'min_p': '0.00000001', 'max_p': '100', 'min_a': '0.001', 'max_a': '5000' }, + { 'pair': 'NEO/USD', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.01', 'max_p': '50000', 'min_a': '0.1', 'max_a': '500000' }, + { 'pair': 'NEO/RUB', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.001', 'max_p': '1500000', 'min_a': '50', 'max_a': '50000000' }, + { 'pair': 'NEO/BTC', 'min_q': '0.1', 'max_q': '100000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, + { 'pair': 'OMG/USD', 'min_q': '0.01', 'max_q': '500000', 'min_p': '0.01', 'max_p': '1000', 'min_a': '0.5', 'max_a': '500000' }, + { 'pair': 'OMG/BTC', 'min_q': '1', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, + { 'pair': 'OMG/ETH', 'min_q': '0.01', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.01', 'max_a': '5000' }, + { 'pair': 'ONG/EXM', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '100', 'max_a': '15000000' }, + { 'pair': 'ONG/BTC', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.00001', 'max_a': '10' }, + { 'pair': 'ONG/RUB', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '100', 'max_a': '250000' }, + { 'pair': 'ONG/UAH', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '50', 'max_a': '6000000' }, + { 'pair': 'ONT/EXM', 'min_q': '1', 'max_q': '500000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '200', 'max_a': '15000000' }, + { 'pair': 'ONT/BTC', 'min_q': '1', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.00001', 'max_a': '10' }, + { 'pair': 'ONT/RUB', 'min_q': '1', 'max_q': '500000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '100', 'max_a': '6000000' }, + { 'pair': 'ONT/UAH', 'min_q': '1', 'max_q': '500000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '200', 'max_a': '250000' }, + { 'pair': 'PTI/RUB', 'min_q': '1', 'max_q': '50000000', 'min_p': '0.00000001', 'max_p': '600000', 'min_a': '10', 'max_a': '600000' }, + { 'pair': 'PTI/BTC', 'min_q': '1', 'max_q': '50000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.000001', 'max_a': '10' }, + { 'pair': 'PTI/EOS', 'min_q': '1', 'max_q': '50000000', 'min_p': '0.0000001', 'max_p': '5000', 'min_a': '0.01', 'max_a': '20000' }, + { 'pair': 'PTI/USDT', 'min_q': '1', 'max_q': '50000000', 'min_p': '0.000001', 'max_p': '10000', 'min_a': '0.01', 'max_a': '100000' }, + { 'pair': 'QTUM/USD', 'min_q': '0.1', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '10000', 'min_a': '0.1', 'max_a': '500000' }, + { 'pair': 'QTUM/BTC', 'min_q': '0.1', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '100' }, + { 'pair': 'QTUM/ETH', 'min_q': '0.1', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '100', 'min_a': '0.001', 'max_a': '5000' }, { 'pair': 'ROOBEE/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '0.1', 'min_a': '0.00001', 'max_a': '100' }, - { 'pair': 'SMART/USD', 'min_q': '10', 'max_q': '10000000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '1', 'max_a': '500000' }, - { 'pair': 'SMART/RUB', 'min_q': '10', 'max_q': '10000000', 'min_p': '0.0001', 'max_p': '100000', 'min_a': '10', 'max_a': '50000000' }, - { 'pair': 'SMART/EUR', 'min_q': '10', 'max_q': '10000000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '1', 'max_a': '500000' }, - { 'pair': 'SMART/BTC', 'min_q': '10', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.00001', 'max_a': '100' }, - { 'pair': 'TRX/USD', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '500000' }, - { 'pair': 'TRX/RUB', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.000001', 'max_p': '100000', 'min_a': '0.1', 'max_a': '50000000' }, - { 'pair': 'TRX/UAH', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.000001', 'max_p': '100000', 'min_a': '0.1', 'max_a': '50000000' }, - { 'pair': 'TRX/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, + { 'pair': 'SMART/USD', 'min_q': '10', 'max_q': '100000000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '1', 'max_a': '500000' }, + { 'pair': 'SMART/RUB', 'min_q': '10', 'max_q': '100000000', 'min_p': '0.0001', 'max_p': '100000', 'min_a': '10', 'max_a': '50000000' }, + { 'pair': 'SMART/EUR', 'min_q': '10', 'max_q': '100000000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '1', 'max_a': '500000' }, + { 'pair': 'SMART/BTC', 'min_q': '10', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.00001', 'max_a': '100' }, + { 'pair': 'TRX/USD', 'min_q': '1', 'max_q': '50000000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '500000' }, + { 'pair': 'TRX/EUR', 'min_q': '0.01', 'max_q': '50000000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '500000' }, + { 'pair': 'TRX/RUB', 'min_q': '1', 'max_q': '50000000', 'min_p': '0.000001', 'max_p': '100000', 'min_a': '0.1', 'max_a': '50000000' }, + { 'pair': 'TRX/UAH', 'min_q': '1', 'max_q': '50000000', 'min_p': '0.000001', 'max_p': '100000', 'min_a': '0.1', 'max_a': '50000000' }, + { 'pair': 'TRX/BTC', 'min_q': '1', 'max_q': '50000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, { 'pair': 'USDC/USD', 'min_q': '1', 'max_q': '500000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '3', 'max_a': '500000' }, { 'pair': 'USDC/BTC', 'min_q': '1', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '100' }, { 'pair': 'USDC/ETH', 'min_q': '1', 'max_q': '500000', 'min_p': '0.0000001', 'max_p': '100', 'min_a': '0.001', 'max_a': '1000' }, { 'pair': 'USDC/USDT', 'min_q': '1', 'max_q': '500000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '3', 'max_a': '500000' }, { 'pair': 'USDT/USD', 'min_q': '1', 'max_q': '500000', 'min_p': '0.5', 'max_p': '10', 'min_a': '0.1', 'max_a': '500000' }, { 'pair': 'USDT/RUB', 'min_q': '1', 'max_q': '500000', 'min_p': '0.01', 'max_p': '1000', 'min_a': '10', 'max_a': '50000000' }, - { 'pair': 'USDT/EUR', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.1', 'max_p': '10', 'min_a': '0.1', 'max_a': '500000' }, - { 'pair': 'USDT/UAH', 'min_q': '0.01', 'max_q': '100000', 'min_p': '1', 'max_p': '3000', 'min_a': '2', 'max_a': '15000000' }, + { 'pair': 'USDT/EUR', 'min_q': '0.01', 'max_q': '500000', 'min_p': '0.1', 'max_p': '10', 'min_a': '0.1', 'max_a': '500000' }, + { 'pair': 'USDT/UAH', 'min_q': '0.01', 'max_q': '500000', 'min_p': '1', 'max_p': '3000', 'min_a': '2', 'max_a': '15000000' }, + { 'pair': 'USDT/KZT', 'min_q': '1', 'max_q': '500000', 'min_p': '200', 'max_p': '4000', 'min_a': '0.1', 'max_a': '500000' }, { 'pair': 'VLX/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '0.1', 'min_a': '0.00001', 'max_a': '100' }, - { 'pair': 'WAVES/USD', 'min_q': '0.5', 'max_q': '10000', 'min_p': '0.001', 'max_p': '3500', 'min_a': '0.5', 'max_a': '500000' }, - { 'pair': 'WAVES/RUB', 'min_q': '0.5', 'max_q': '10000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '1', 'max_a': '50000000' }, - { 'pair': 'WAVES/BTC', 'min_q': '0.5', 'max_q': '10000', 'min_p': '0.000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '100' }, - { 'pair': 'WAVES/ETH', 'min_q': '0.5', 'max_q': '10000', 'min_p': '0.00001', 'max_p': '30', 'min_a': '0.0035', 'max_a': '3500' }, - { 'pair': 'XEM/USD', 'min_q': '10', 'max_q': '5000000', 'min_p': '0.00001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000' }, - { 'pair': 'XEM/EUR', 'min_q': '10', 'max_q': '5000000', 'min_p': '0.00001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000' }, - { 'pair': 'XEM/UAH', 'min_q': '1', 'max_q': '5000000', 'min_p': '0.0001', 'max_p': '30000', 'min_a': '10', 'max_a': '15000000' }, - { 'pair': 'XEM/BTC', 'min_q': '10', 'max_q': '5000000', 'min_p': '0.0000001', 'max_p': '1', 'min_a': '0.00015', 'max_a': '100' }, - { 'pair': 'XLM/USD', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '500000' }, - { 'pair': 'XLM/RUB', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.00001', 'max_p': '100000', 'min_a': '0.1', 'max_a': '50000000' }, - { 'pair': 'XLM/TRY', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.00001', 'max_p': '100000', 'min_a': '0.1', 'max_a': '6000000' }, - { 'pair': 'XLM/BTC', 'min_q': '1', 'max_q': '200000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, - { 'pair': 'XMR/USD', 'min_q': '0.01', 'max_q': '1000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000' }, - { 'pair': 'XMR/RUB', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.001', 'max_p': '600000', 'min_a': '10', 'max_a': '16000000' }, - { 'pair': 'XMR/EUR', 'min_q': '0.01', 'max_q': '1000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000' }, - { 'pair': 'XMR/UAH', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.001', 'max_p': '300000', 'min_a': '5', 'max_a': '16000000' }, - { 'pair': 'XMR/BTC', 'min_q': '0.01', 'max_q': '1000', 'min_p': '0.0001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, - { 'pair': 'XMR/ETH', 'min_q': '0.01', 'max_q': '1000', 'min_p': '0.00000001', 'max_p': '100', 'min_a': '0.001', 'max_a': '5000' }, - { 'pair': 'XRP/EUR', 'min_q': '1', 'max_q': '100000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.001', 'max_a': '500000' }, - { 'pair': 'XRP/TRY', 'min_q': '1', 'max_q': '100000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '6000000' }, - { 'pair': 'XRP/UAH', 'min_q': '1', 'max_q': '100000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '15000000' }, - { 'pair': 'XRP/USDT', 'min_q': '1', 'max_q': '100000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.001', 'max_a': '500000' }, - { 'pair': 'XRP/ETH', 'min_q': '1', 'max_q': '100000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.00001', 'max_a': '5000' }, + { 'pair': 'WAVES/USD', 'min_q': '0.5', 'max_q': '500000', 'min_p': '0.001', 'max_p': '3500', 'min_a': '0.5', 'max_a': '500000' }, + { 'pair': 'WAVES/RUB', 'min_q': '0.5', 'max_q': '500000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '1', 'max_a': '50000000' }, + { 'pair': 'WAVES/BTC', 'min_q': '0.5', 'max_q': '500000', 'min_p': '0.000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '100' }, + { 'pair': 'WAVES/ETH', 'min_q': '0.5', 'max_q': '500000', 'min_p': '0.00001', 'max_p': '30', 'min_a': '0.0035', 'max_a': '3500' }, + { 'pair': 'XEM/USD', 'min_q': '10', 'max_q': '10000000', 'min_p': '0.00001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000' }, + { 'pair': 'XEM/EUR', 'min_q': '10', 'max_q': '10000000', 'min_p': '0.00001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000' }, + { 'pair': 'XEM/UAH', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.0001', 'max_p': '30000', 'min_a': '10', 'max_a': '15000000' }, + { 'pair': 'XEM/BTC', 'min_q': '10', 'max_q': '10000000', 'min_p': '0.0000001', 'max_p': '1', 'min_a': '0.00015', 'max_a': '100' }, + { 'pair': 'XLM/USD', 'min_q': '0.01', 'max_q': '5000000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '500000' }, + { 'pair': 'XLM/RUB', 'min_q': '0.01', 'max_q': '5000000', 'min_p': '0.00001', 'max_p': '100000', 'min_a': '0.1', 'max_a': '50000000' }, + { 'pair': 'XLM/TRY', 'min_q': '0.01', 'max_q': '5000000', 'min_p': '0.00001', 'max_p': '100000', 'min_a': '0.1', 'max_a': '6000000' }, + { 'pair': 'XLM/BTC', 'min_q': '1', 'max_q': '5000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, + { 'pair': 'XMR/USD', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000' }, + { 'pair': 'XMR/RUB', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.001', 'max_p': '600000', 'min_a': '10', 'max_a': '16000000' }, + { 'pair': 'XMR/EUR', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000' }, + { 'pair': 'XMR/UAH', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.001', 'max_p': '300000', 'min_a': '5', 'max_a': '16000000' }, + { 'pair': 'XMR/BTC', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.0001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, + { 'pair': 'XMR/ETH', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.00000001', 'max_p': '100', 'min_a': '0.001', 'max_a': '5000' }, + { 'pair': 'XRP/EUR', 'min_q': '1', 'max_q': '5000000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.001', 'max_a': '500000' }, + { 'pair': 'XRP/TRY', 'min_q': '1', 'max_q': '5000000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '6000000' }, + { 'pair': 'XRP/UAH', 'min_q': '1', 'max_q': '5000000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '15000000' }, + { 'pair': 'XRP/USDT', 'min_q': '1', 'max_q': '5000000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.001', 'max_a': '500000' }, + { 'pair': 'XRP/ETH', 'min_q': '1', 'max_q': '5000000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.00001', 'max_a': '5000' }, { 'pair': 'XTZ/USD', 'min_q': '0.1', 'max_q': '100000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '100000' }, { 'pair': 'XTZ/RUB', 'min_q': '0.1', 'max_q': '100000', 'min_p': '0.00001', 'max_p': '100000', 'min_a': '0.5', 'max_a': '500000' }, { 'pair': 'XTZ/BTC', 'min_q': '0.1', 'max_q': '100000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.00001', 'max_a': '10' }, { 'pair': 'XTZ/ETH', 'min_q': '0.1', 'max_q': '100000', 'min_p': '0.0000001', 'max_p': '10', 'min_a': '0.0001', 'max_a': '1000' }, - { 'pair': 'ZEC/USD', 'min_q': '0.01', 'max_q': '1000', 'min_p': '0.001', 'max_p': '5000', 'min_a': '0.1', 'max_a': '500000' }, - { 'pair': 'ZEC/RUB', 'min_q': '0.01', 'max_q': '1000', 'min_p': '0.001', 'max_p': '100000', 'min_a': '0.1', 'max_a': '50000000' }, - { 'pair': 'ZEC/EUR', 'min_q': '0.01', 'max_q': '1000', 'min_p': '0.001', 'max_p': '5000', 'min_a': '0.1', 'max_a': '500000' }, - { 'pair': 'ZEC/BTC', 'min_q': '0.01', 'max_q': '1000', 'min_p': '0.00001', 'max_p': '10', 'min_a': '0.001', 'max_a': '100' }, + { 'pair': 'ZEC/USD', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.001', 'max_p': '5000', 'min_a': '0.1', 'max_a': '500000' }, + { 'pair': 'ZEC/RUB', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.001', 'max_p': '100000', 'min_a': '0.1', 'max_a': '50000000' }, + { 'pair': 'ZEC/EUR', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.001', 'max_p': '5000', 'min_a': '0.1', 'max_a': '500000' }, + { 'pair': 'ZEC/BTC', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.00001', 'max_p': '10', 'min_a': '0.001', 'max_a': '100' }, { 'pair': 'ZRX/USD', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000' }, { 'pair': 'ZRX/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, { 'pair': 'ZRX/ETH', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.01', 'max_a': '5000' }, @@ -51540,6 +51063,8 @@ module.exports = class exmo extends Exchange { { 'prov': 'CRON', 'dep': '0%', 'wd': '5 CRON' }, { 'prov': 'ONT', 'dep': '0%', 'wd': '1 ONT' }, { 'prov': 'ONG', 'dep': '0%', 'wd': '5 ONG' }, + { 'prov': 'ALGO', 'dep': '0%', 'wd': '0.01 ALGO' }, + { 'prov': 'ATOM', 'dep': '0%', 'wd': '' }, ], }, { @@ -51548,9 +51073,10 @@ module.exports = class exmo extends Exchange { 'items': [ { 'prov': 'EX-CODE', 'dep': '', 'wd': '0.2%' }, { 'prov': 'Payeer', 'dep': '3.95%', 'wd': '-' }, - { 'prov': 'AdvCash', 'dep': '0%', 'wd': '3.99%' }, + { 'prov': 'AdvCash', 'dep': '0%', 'wd': '3.49%' }, { 'prov': 'Visa/MasterCard (Simplex)', 'dep': '4.5% + 0.5 USD', 'wd': '-' }, { 'prov': 'Visa', 'dep': '3.45%', 'wd': '-' }, + { 'prov': 'Frick Bank', 'dep': '0 USD', 'wd': '-' }, ], }, { @@ -51558,22 +51084,24 @@ module.exports = class exmo extends Exchange { 'title': 'EUR', 'items': [ { 'prov': 'EX-CODE', 'dep': '', 'wd': '0.2%' }, - { 'prov': 'Visa/MasterCard (Simplex)', 'dep': '4.5% + 0.5 EUR', 'wd': '-' }, + { 'prov': 'Visa/MasterCard', 'dep': '4.5% + 0.5 EUR', 'wd': '-' }, { 'prov': 'Visa', 'dep': '2.95%', 'wd': '-' }, - { 'prov': 'SEPA', 'dep': '10 EUR', 'wd': '50 EUR' }, + { 'prov': 'Frick Internal Transfer', 'dep': '0 EUR', 'wd': '-' }, + { 'prov': 'SEPA Frick Bank', 'dep': '0 EUR', 'wd': '-' }, + { 'prov': 'WIRE Frick Bank', 'dep': '0%', 'wd': '-' }, + { 'prov': 'SEPA Weg Ag', 'dep': '-', 'wd': '1 EUR' }, ], }, { 'group': 'rub', 'title': 'RUB', 'items': [ - { 'prov': 'Payeer', 'dep': '2.49%', 'wd': '-' }, + { 'prov': 'Payeer', 'dep': '2.49%', 'wd': '3.99%' }, { 'prov': 'EX-CODE', 'dep': '', 'wd': '0.2%' }, - { 'prov': 'Qiwi', 'dep': '0.99%', 'wd': '2%' }, - { 'prov': 'Yandex Money', 'dep': '1.95%', 'wd': '-' }, - { 'prov': 'Enfins', 'dep': '0%', 'wd': '1.49%' }, - { 'prov': 'AdvCash', 'dep': '0%', 'wd': '2.49%' }, - { 'prov': 'Visa/MasterCard', 'dep': '1.99%', 'wd': '4.49% + 60 RUB' }, + { 'prov': 'Qiwi', 'dep': '1.49%', 'wd': '2.49%' }, + { 'prov': 'Yandex Money', 'dep': '1.49%', 'wd': '-' }, + { 'prov': 'AdvCash', 'dep': '0%', 'wd': '3.49%' }, + { 'prov': 'Visa/MasterCard', 'dep': '2.99%', 'wd': '3.99% + 60 RUB' }, ], }, { @@ -51581,7 +51109,6 @@ module.exports = class exmo extends Exchange { 'title': 'PLN', 'items': [ { 'prov': 'EX-CODE', 'dep': '', 'wd': '0.2%' }, - { 'prov': 'Visa/MasterCard (Simplex)', 'dep': '4.5% + 1 PLN', 'wd': '-' }, ], }, { @@ -51591,6 +51118,7 @@ module.exports = class exmo extends Exchange { { 'prov': 'EX-CODE', 'dep': '', 'wd': '0.2%' }, { 'prov': 'Visa', 'dep': '3.05%', 'wd': '-' }, { 'prov': 'Visa/MasterCard (Simplex)', 'dep': '4.5% + 2 TRY', 'wd': '-' }, + { 'prov': 'AdvCash', 'dep': '0%', 'wd': '-' }, ], }, { @@ -51599,17 +51127,18 @@ module.exports = class exmo extends Exchange { 'items': [ { 'prov': 'EX-CODE', 'dep': '', 'wd': '0.2%' }, { 'prov': 'Terminal', 'dep': '2.6%', 'wd': '-' }, - { 'prov': 'Enfins', 'dep': '0%', 'wd': '1.95%' }, - { 'prov': 'Visa/MasterCard', 'dep': '1% + 5 UAH', 'wd': '2.99%' }, + { 'prov': 'Visa/MasterCard', 'dep': '1% + 5 UAH', 'wd': '-' }, + { 'prov': 'Visa/MasterCard EasyTransfer', 'dep': '-', 'wd': '2.99%' }, ], }, { 'group': 'kzt', 'title': 'KZT', 'items': [ + { 'prov': 'EX-CODE', 'dep': '', 'wd': '0.2%' }, { 'prov': 'Visa/MasterCard RoyalPay', 'dep': '-', 'wd': '2.99% + 450 KZT' }, { 'prov': 'Visa/MasterCard', 'dep': '3.5%', 'wd': '-' }, - { 'prov': 'AdvCash', 'dep': '0%', 'wd': '1.49%' }, + { 'prov': 'AdvCash', 'dep': '0%', 'wd': '-' }, ], }, ], @@ -51623,6 +51152,7 @@ module.exports = class exmo extends Exchange { '40015': ExchangeError, // API function do not exist '40016': OnMaintenance, // {"result":false,"error":"Error 40016: Maintenance work in progress"} '40017': AuthenticationError, // Wrong API Key + '40032': PermissionDenied, // {"result":false,"error":"Error 40032: Access is denied for this API key"} '40034': RateLimitExceeded, // {"result":false,"error":"Error 40034: Access is denied, rate limit is exceeded"} '50052': InsufficientFunds, '50054': InsufficientFunds, @@ -51632,6 +51162,8 @@ module.exports = class exmo extends Exchange { '50321': InvalidOrder, // Price by order is more than permissible maximum for this pair }, 'broad': { + 'range period is too long': BadRequest, + 'invalid syntax': BadRequest, 'API rate limit exceeded': RateLimitExceeded, // {"result":false,"error":"API rate limit exceeded for 99.33.55.224. Retry after 60 sec.","history":[],"begin":1579392000,"end":1579478400} }, }, @@ -51793,8 +51325,21 @@ module.exports = class exmo extends Exchange { } async fetchMarkets (params = {}) { - const fees = await this.fetchTradingFees (); const response = await this.publicGetPairSettings (params); + // + // { + // "EXM_ETH": { + // "min_quantity": "1", + // "max_quantity": "1000", + // "min_price": "1", + // "max_price": "1000", + // "max_amount": "1000", + // "min_amount": "1", + // "commission_taker_percent": "0.2", + // "commission_maker_percent": "0.2" + // }, + // } + // const keys = Object.keys (response); const result = []; for (let i = 0; i < keys.length; i++) { @@ -51804,6 +51349,8 @@ module.exports = class exmo extends Exchange { const [ baseId, quoteId ] = symbol.split ('/'); const base = this.safeCurrencyCode (baseId); const quote = this.safeCurrencyCode (quoteId); + const taker = this.safeFloat (market, 'commission_taker_percent'); + const maker = this.safeFloat (market, 'commission_maker_percent'); result.push ({ 'id': id, 'symbol': symbol, @@ -51812,8 +51359,8 @@ module.exports = class exmo extends Exchange { 'baseId': baseId, 'quoteId': quoteId, 'active': true, - 'taker': fees['taker'], - 'maker': fees['maker'], + 'taker': taker / 100, + 'maker': maker / 100, 'limits': { 'amount': { 'min': this.safeFloat (market, 'min_quantity'), @@ -51838,6 +51385,74 @@ module.exports = class exmo extends Exchange { return result; } + async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) { + await this.loadMarkets (); + const market = this.market (symbol); + const request = { + 'symbol': market['id'], + 'resolution': this.timeframes[timeframe], + }; + const options = this.safeValue (this.options, 'fetchOHLCV'); + const maxLimit = this.safeInteger (options, 'maxLimit', 3000); + const duration = this.parseTimeframe (timeframe); + const now = this.milliseconds (); + if (since === undefined) { + if (limit === undefined) { + throw new ArgumentsRequired (this.id + ' fetchOHLCV requires a since argument or a limit argument'); + } else { + if (limit > maxLimit) { + throw new BadRequest (this.id + ' fetchOHLCV will serve ' + maxLimit.toString () + ' candles at most'); + } + request['from'] = parseInt (now / 1000) - limit * duration - 1; + request['to'] = parseInt (now / 1000); + } + } else { + request['from'] = parseInt (since / 1000) - 1; + if (limit === undefined) { + request['to'] = parseInt (now / 1000); + } else { + if (limit > maxLimit) { + throw new BadRequest (this.id + ' fetchOHLCV will serve ' + maxLimit.toString () + ' candles at most'); + } + const to = this.sum (since, limit * duration * 1000); + request['to'] = parseInt (to / 1000); + } + } + const response = await this.publicGetCandlesHistory (this.extend (request, params)); + // + // { + // "candles":[ + // {"t":1584057600000,"o":0.02235144,"c":0.02400233,"h":0.025171,"l":0.02221,"v":5988.34031761}, + // {"t":1584144000000,"o":0.0240373,"c":0.02367413,"h":0.024399,"l":0.0235,"v":2027.82522329}, + // {"t":1584230400000,"o":0.02363458,"c":0.02319242,"h":0.0237948,"l":0.02223196,"v":1707.96944997}, + // ] + // } + // + const candles = this.safeValue (response, 'candles', []); + return this.parseOHLCVs (candles, market, timeframe, since, limit); + } + + parseOHLCV (ohlcv, market = undefined, timeframe = '5m', since = undefined, limit = undefined) { + // + // { + // "t":1584057600000, + // "o":0.02235144, + // "c":0.02400233, + // "h":0.025171, + // "l":0.02221, + // "v":5988.34031761 + // } + // + return [ + this.safeInteger (ohlcv, 't'), + this.safeFloat (ohlcv, 'o'), + this.safeFloat (ohlcv, 'h'), + this.safeFloat (ohlcv, 'l'), + this.safeFloat (ohlcv, 'c'), + this.safeFloat (ohlcv, 'v'), + ]; + } + async fetchBalance (params = {}) { await this.loadMarkets (); const response = await this.privatePostUserInfo (params); @@ -51961,8 +51576,36 @@ module.exports = class exmo extends Exchange { } parseTrade (trade, market = undefined) { + // + // fetchTrades (public) + // + // { + // "trade_id":165087520, + // "date":1587470005, + // "type":"buy", + // "quantity":"1.004", + // "price":"0.02491461", + // "amount":"0.02501426" + // }, + // + // fetchMyTrades, fetchOrderTrades + // + // { + // "trade_id": 3, + // "date": 1435488248, + // "type": "buy", + // "pair": "BTC_USD", + // "order_id": 12345, + // "quantity": 1, + // "price": 100, + // "amount": 100, + // "exec_type": "taker", + // "commission_amount": "0.02", + // "commission_currency": "BTC", + // "commission_percent": "0.2" + // } + // const timestamp = this.safeTimestamp (trade, 'date'); - let fee = undefined; let symbol = undefined; const id = this.safeString (trade, 'trade_id'); const orderId = this.safeString (trade, 'order_id'); @@ -51971,24 +51614,35 @@ module.exports = class exmo extends Exchange { const cost = this.safeFloat (trade, 'amount'); const side = this.safeString (trade, 'type'); const type = undefined; - if (market !== undefined) { + const marketId = this.safeString (trade, 'pair'); + if (marketId !== undefined) { + if (marketId in this.markets_by_id) { + market = this.markets_by_id[marketId]; + } else { + const [ baseId, quoteId ] = marketId.split ('_'); + const base = this.safeCurrencyCode (baseId); + const quote = this.safeCurrencyCode (quoteId); + symbol = base + '/' + quote; + } + } + if ((symbol === undefined) && (market !== undefined)) { symbol = market['symbol']; - if (market['taker'] !== market['maker']) { - throw new ExchangeError (this.id + ' parseTrade can not deduce proper fee costs, taker and maker fees now differ'); - } - if ((side === 'buy') && (amount !== undefined)) { - fee = { - 'currency': market['base'], - 'cost': amount * market['taker'], - 'rate': market['taker'], - }; - } else if ((side === 'sell') && (cost !== undefined)) { - fee = { - 'currency': market['quote'], - 'cost': cost * market['taker'], - 'rate': market['taker'], - }; + } + const takerOrMaker = this.safeString (trade, 'exec_type'); + let fee = undefined; + const feeCost = this.safeFloat (trade, 'commission_amount'); + if (feeCost !== undefined) { + const feeCurrencyId = this.safeString (trade, 'commission_currency'); + const feeCurrencyCode = this.safeCurrencyCode (feeCurrencyId); + let feeRate = this.safeFloat (trade, 'commission_percent'); + if (feeRate !== undefined) { + feeRate /= 1000; } + fee = { + 'cost': feeCost, + 'currency': feeCurrencyCode, + 'rate': feeRate, + }; } return { 'id': id, @@ -51999,7 +51653,7 @@ module.exports = class exmo extends Exchange { 'order': orderId, 'type': type, 'side': side, - 'takerOrMaker': undefined, + 'takerOrMaker': takerOrMaker, 'price': price, 'amount': amount, 'cost': cost, @@ -52014,6 +51668,28 @@ module.exports = class exmo extends Exchange { 'pair': market['id'], }; const response = await this.publicGetTrades (this.extend (request, params)); + // + // { + // "ETH_BTC":[ + // { + // "trade_id":165087520, + // "date":1587470005, + // "type":"buy", + // "quantity":"1.004", + // "price":"0.02491461", + // "amount":"0.02501426" + // }, + // { + // "trade_id":165087369, + // "date":1587469938, + // "type":"buy", + // "quantity":"0.94", + // "price":"0.02492348", + // "amount":"0.02342807" + // } + // ] + // } + // const data = this.safeValue (response, market['id'], []); return this.parseTrades (data, market, since, limit); } @@ -52171,6 +51847,31 @@ module.exports = class exmo extends Exchange { 'order_id': id.toString (), }; const response = await this.privatePostOrderTrades (this.extend (request, params)); + // + // { + // "type": "buy", + // "in_currency": "BTC", + // "in_amount": "1", + // "out_currency": "USD", + // "out_amount": "100", + // "trades": [ + // { + // "trade_id": 3, + // "date": 1435488248, + // "type": "buy", + // "pair": "BTC_USD", + // "order_id": 12345, + // "quantity": 1, + // "price": 100, + // "amount": 100, + // "exec_type": "taker", + // "commission_amount": "0.02", + // "commission_currency": "BTC", + // "commission_percent": "0.2" + // } + // ] + // } + // const trades = this.safeValue (response, 'trades'); return this.parseTrades (trades, market, since, limit); } @@ -52618,9 +52319,10 @@ module.exports = class exmo extends Exchange { if (response === undefined) { return; // fallback to default error handler } - if ('result' in response) { + if (('result' in response) || ('errmsg' in response)) { // // {"result":false,"error":"Error 50052: Insufficient funds"} + // {"s":"error","errmsg":"strconv.ParseInt: parsing \"\": invalid syntax"} // let success = this.safeValue (response, 'result', false); if (typeof success === 'string') { @@ -52632,7 +52334,7 @@ module.exports = class exmo extends Exchange { } if (!success) { let code = undefined; - const message = this.safeString (response, 'error'); + const message = this.safeString2 (response, 'error', 'errmsg'); const errorParts = message.split (':'); const numParts = errorParts.length; if (numParts > 1) { @@ -52649,7 +52351,7 @@ module.exports = class exmo extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10}],81:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9}],80:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -53102,7 +52804,7 @@ module.exports = class exx extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10}],82:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9}],81:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -53836,7 +53538,7 @@ module.exports = class fcoin extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10}],83:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9}],82:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -53862,7 +53564,7 @@ module.exports = class fcoinjp extends fcoin { } }; -},{"./fcoin.js":82}],84:[function(require,module,exports){ +},{"./fcoin.js":81}],83:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -54141,7 +53843,7 @@ module.exports = class flowbtc extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10}],85:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9}],84:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -54400,7 +54102,7 @@ module.exports = class foxbit extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10}],86:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9}],85:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -54983,6 +54685,7 @@ module.exports = class ftx extends Exchange { // { // "fee": 20.1374935, // "feeRate": 0.0005, + // "feeCurrency": "USD", // "future": "EOS-0329", // "id": 11215, // "liquidity": "taker", @@ -55029,8 +54732,11 @@ module.exports = class ftx extends Exchange { let fee = undefined; const feeCost = this.safeFloat (trade, 'fee'); if (feeCost !== undefined) { + const feeCurrencyId = this.safeString (trade, 'feeCurrency'); + const feeCurrencyCode = this.safeCurrencyCode (feeCurrencyId); fee = { 'cost': feeCost, + 'currency': feeCurrencyCode, 'rate': this.safeFloat (trade, 'feeRate'), }; } @@ -55836,7 +55542,7 @@ module.exports = class ftx extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10,"./base/functions/number":16}],87:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9,"./base/functions/number":15}],86:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -56033,7 +55739,7 @@ module.exports = class fybse extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10}],88:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9}],87:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -56200,6 +55906,26 @@ module.exports = class gateio extends Exchange { async fetchMarkets (params = {}) { const response = await this.publicGetMarketinfo (params); + // + // { + // "result":"true", + // "pairs":[ + // { + // "usdt_cnyx":{ + // "decimal_places":3, + // "amount_decimal_places":3, + // "min_amount":1, + // "min_amount_a":1, + // "min_amount_b":3, + // "fee":0.02, + // "trade_disabled":0, + // "buy_disabled":0, + // "sell_disabled":0 + // } + // }, + // ] + // } + // const markets = this.safeValue (response, 'pairs'); if (!markets) { throw new ExchangeError (this.id + ' fetchMarkets got an unrecognized response'); @@ -56226,14 +55952,14 @@ module.exports = class gateio extends Exchange { const symbol = base + '/' + quote; const precision = { 'amount': 8, - 'price': details['decimal_places'], + 'price': this.safeInteger (details, 'decimal_places'), }; const amountLimits = { - 'min': details['min_amount'], + 'min': this.safeFloat (details, 'min_amount'), 'max': undefined, }; const priceLimits = { - 'min': Math.pow (10, -details['decimal_places']), + 'min': Math.pow (10, -precision['price']), 'max': undefined, }; const defaultCost = amountLimits['min'] * priceLimits['min']; @@ -56247,9 +55973,13 @@ module.exports = class gateio extends Exchange { 'price': priceLimits, 'cost': costLimits, }; - const active = true; + const disabled = this.safeValue (details, 'trade_disabled'); + const active = !disabled; + const uppercaseId = id.toUpperCase (); + const fee = this.safeFloat (details, 'fee'); result.push ({ 'id': id, + 'uppercaseId': uppercaseId, 'symbol': symbol, 'base': base, 'quote': quote, @@ -56257,8 +55987,8 @@ module.exports = class gateio extends Exchange { 'quoteId': quoteId, 'info': market, 'active': active, - 'maker': details['fee'] / 100, - 'taker': details['fee'] / 100, + 'maker': fee / 100, + 'taker': fee / 100, 'precision': precision, 'limits': limits, }); @@ -56520,22 +56250,64 @@ module.exports = class gateio extends Exchange { parseOrder (order, market = undefined) { // - // {'amount': '0.00000000', - // 'currencyPair': 'xlm_usdt', - // 'fee': '0.0113766632239302 USDT', - // 'feeCurrency': 'USDT', - // 'feePercentage': 0.18, - // 'feeValue': '0.0113766632239302', - // 'filledAmount': '30.14004987', - // 'filledRate': 0.2097, - // 'initialAmount': '30.14004987', - // 'initialRate': '0.2097', - // 'left': 0, - // 'orderNumber': '998307286', - // 'rate': '0.2097', - // 'status': 'closed', - // 'timestamp': 1531158583, - // 'type': 'sell'}, + // createOrder + // + // { + // "fee": "0 ZEC", + // "code": 0, + // "rate": "0.0055", + // "side": 2, + // "type": "buy", + // "ctime": 1586460839.138, + // "market": "ZEC_BTC", + // "result": "true", + // "status": "open", + // "iceberg": "0", + // "message": "Success", + // "feeValue": "0", + // "filledRate": "0.005500000", + // "leftAmount": "0.60607456", + // "feeCurrency": "ZEC", + // "orderNumber": 10755887009, + // "filledAmount": "0", + // "feePercentage": 0.002, + // "initialAmount": "0.60607456" + // } + // + // { + // 'amount': '0.00000000', + // 'currencyPair': 'xlm_usdt', + // 'fee': '0.0113766632239302 USDT', + // 'feeCurrency': 'USDT', + // 'feePercentage': 0.18, + // 'feeValue': '0.0113766632239302', + // 'filledAmount': '30.14004987', + // 'filledRate': 0.2097, + // 'initialAmount': '30.14004987', + // 'initialRate': '0.2097', + // 'left': 0, + // 'orderNumber': '998307286', + // 'rate': '0.2097', + // 'status': 'closed', + // 'timestamp': 1531158583, + // 'type': 'sell' + // } + // + // { + // "orderNumber": 10802237760, + // "orderType": 1, + // "type": "buy", + // "rate": "0.54250000", + // "amount": "45.55638518", + // "total": "24.71433896", + // "initialRate": "0.54250000", + // "initialAmount": "45.55638518", + // "filledRate": "0.54250000", + // "filledAmount": "0", + // "currencyPair": "nano_usdt", + // "timestamp": 1586556143, + // "status": "open" + // } // const id = this.safeString2 (order, 'orderNumber', 'id'); let symbol = undefined; @@ -56556,12 +56328,15 @@ module.exports = class gateio extends Exchange { } else if (side === '2') { side = 'buy'; } - const price = this.safeFloat2 (order, 'initialRate', 'price'); + const price = this.safeFloat2 (order, 'initialRate', 'rate'); const average = this.safeFloat (order, 'filledRate'); const amount = this.safeFloat2 (order, 'initialAmount', 'amount'); const filled = this.safeFloat (order, 'filledAmount'); // In the order status response, this field has a different name. - const remaining = this.safeFloat2 (order, 'leftAmount', 'left'); + let remaining = this.safeFloat2 (order, 'leftAmount', 'left'); + if (remaining === undefined) { + remaining = amount - filled; + } const feeCost = this.safeFloat (order, 'feeValue'); const feeCurrencyId = this.safeString (order, 'feeCurrency'); const feeCurrencyCode = this.safeCurrencyCode (feeCurrencyId); @@ -56687,7 +56462,7 @@ module.exports = class gateio extends Exchange { async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) { if (symbol === undefined) { - throw new ArgumentsRequired (this.id + ' fetchMyTrades requires symbol param'); + throw new ArgumentsRequired (this.id + ' fetchMyTrades requires symbol argument'); } await this.loadMarkets (); const market = this.market (symbol); @@ -56866,7 +56641,7 @@ module.exports = class gateio extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10}],89:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9}],88:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -57049,8 +56824,7 @@ module.exports = class gemini extends Exchange { if (numTables < 2) { throw new NotSupported (error); } - // tables[1] = tables[1].replace ("\n", ''); // eslint-disable-line quotes - const rows = tables[1].split ("\n"); // eslint-disable-line quotes + const rows = tables[1].split ("\n\n"); // eslint-disable-line quotes const numRows = rows.length; if (numRows < 2) { throw new NotSupported (error); @@ -57061,66 +56835,73 @@ module.exports = class gemini extends Exchange { const row = rows[i]; const cells = row.split ("\n"); // eslint-disable-line quotes const numCells = cells.length; - if (numCells < 7) { + if (numCells < 9) { throw new NotSupported (error); } - // // [ - // 'btcusd', - // 'USD', // quote - // 'BTC', // base - // '0.00001 BTC (1e-5)', // min amount - // '0.00000001 BTC (1e-8)', // amount min tick size - // '0.01 USD', // price min tick size - // '\n' + // 'BTC', // currency + // '0.00001 BTC (1e-5)', // min order size + // '0.00000001 BTC (1e-8)', // tick size + // '0.01 USD', // usd price increment + // 'N/A', // btc price increment + // '0.0001 ETH (1e-4)', // eth price increment + // '0.0001 BCH (1e-4)', // bch price increment + // '0.001 LTC (1e-3)', // ltc price increment + // '' // ] // - let id = cells[0].replace ('', ''); - id = id.replace ('', ''); - id = id.replace ('', ''); - let baseId = cells[2].replace ('', ''); - let quoteId = cells[1].replace ('', ''); - const minAmountAsString = cells[3].replace ('', ''); - const amountTickSizeAsString = cells[4].replace ('', ''); - const priceTickSizeAsString = cells[5].replace ('', ''); - const minAmount = minAmountAsString.split (' '); - const amountPrecision = amountTickSizeAsString.split (' '); - const pricePrecision = priceTickSizeAsString.split (' '); - baseId = baseId.toLowerCase (); - quoteId = quoteId.toLowerCase (); + const uppercaseBaseId = cells[0].replace ('', ''); + const baseId = uppercaseBaseId.toLowerCase (); const base = this.safeCurrencyCode (baseId); - const quote = this.safeCurrencyCode (quoteId); - const symbol = base + '/' + quote; - const precision = { - 'amount': this.precisionFromString (amountPrecision[0]), - 'price': this.precisionFromString (pricePrecision[0]), - }; - const active = undefined; - result.push ({ - 'id': id, - 'info': row, - 'symbol': symbol, - 'base': base, - 'quote': quote, - 'baseId': baseId, - 'quoteId': quoteId, - 'active': active, - 'precision': precision, - 'limits': { - 'amount': { - 'min': parseFloat (minAmount[0]), - 'max': undefined, + const quoteIds = [ 'usd', 'btc', 'eth', 'bch', 'ltc' ]; + const minAmountString = cells[1].replace ('', ''); + const minAmountParts = minAmountString.split (' '); + const minAmount = this.safeFloat (minAmountParts, 0); + const amountPrecisionString = cells[2].replace ('', ''); + const amountPrecisionParts = amountPrecisionString.split (' '); + const amountPrecision = this.precisionFromString (amountPrecisionParts[0]); + for (let j = 0; j < quoteIds.length; j++) { + const quoteId = quoteIds[j]; + const quote = this.safeCurrencyCode (quoteId); + const pricePrecisionIndex = this.sum (3, j); + const pricePrecisionString = cells[pricePrecisionIndex].replace ('', ''); + if (pricePrecisionString === 'N/A') { + continue; + } + const pricePrecisionParts = pricePrecisionString.split (' '); + const pricePrecision = this.precisionFromString (pricePrecisionParts[0]); + const symbol = base + '/' + quote; + const id = baseId + quoteId; + const active = undefined; + result.push ({ + 'id': id, + 'info': row, + 'symbol': symbol, + 'base': base, + 'quote': quote, + 'baseId': baseId, + 'quoteId': quoteId, + 'active': active, + 'precision': { + 'amount': amountPrecision, + 'price': pricePrecision, }, - 'price': { - 'min': undefined, - 'max': undefined, + 'limits': { + 'amount': { + 'min': minAmount, + 'max': undefined, + }, + 'price': { + 'min': undefined, + 'max': undefined, + }, + 'cost': { + 'min': undefined, + 'max': undefined, + }, }, - 'cost': { - 'min': undefined, - 'max': undefined, - }, - }, - }); + }); + } } return result; } @@ -57569,7 +57350,2028 @@ module.exports = class gemini extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10}],90:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9}],89:[function(require,module,exports){ +'use strict'; + +// --------------------------------------------------------------------------- + +const Exchange = require ('./base/Exchange'); +const { AuthenticationError, ExchangeError, OrderNotFound, ArgumentsRequired, BadSymbol, BadRequest, NullResponse, InvalidOrder, BadResponse, NotSupported, ExchangeNotAvailable, RequestTimeout, RateLimitExceeded, PermissionDenied, InsufficientFunds, InvalidAddress } = require ('./base/errors'); +const { TICK_SIZE, TRUNCATE } = require ('./base/functions/number'); + +// --------------------------------------------------------------------------- + +module.exports = class hbtc extends Exchange { + describe () { + return this.deepExtend (super.describe (), { + 'id': 'hbtc', + 'name': 'HBTC', + 'countries': [ 'CN' ], + 'rateLimit': 2000, + 'version': 'v1', + 'has': { + 'CORS': false, + 'fetchTime': true, + 'fetchBidAsk': true, + 'fetchBidsAsks': true, + 'fetchTickers': true, + 'fetchTicker': true, + 'fetchDepositAddress': false, + 'fetchOHLCV': true, + 'fetchOrder': true, + 'fetchOrders': false, + 'fetchOpenOrders': true, + 'fetchClosedOrders': true, + 'fetchTradingLimits': true, + 'fetchMarkets': true, + 'fetchMyTrades': true, + 'withdraw': true, + 'fetchCurrencies': false, + 'fetchDeposits': true, + 'fetchWithdrawals': true, + 'fetchAccounts': true, + 'fetchLedger': 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/51840849/80134449-70663300-85a7-11ea-8942-e204cdeaab5d.jpg', // 交易所LOGO + 'api': { + 'quote': 'https://api.hbtc.com/openapi/quote', // 市场API数据端点 + 'contract': 'https://api.hbtc.com/openapi/contract', // 合约API数据端点 + 'option': 'https://api.hbtc.com/openapi/option', // 合约API数据端点 + 'public': 'https://api.hbtc.com/openapi', // 公共API数据端点 + 'private': 'https://api.hbtc.com/openapi', // 私有API数据端点 + 'zendesk': 'https://hbtc.zendesk.com/hc/en-us', + }, + 'www': 'https://www.hbtc.com', // 公司主页 + 'referral': 'https://www.hbtc.com/register/O2S8NS', // 邀请链接 + 'doc': 'https://github.com/bhexopen/BHEX-OpenApi/tree/master/doc', // openapi文档地址 + 'fees': 'https://hbtc.zendesk.com/hc/zh-cn/articles/360009274694', // 费率介绍 + }, + 'api': { + 'public': { + 'get': [ + 'ping', + 'time', + 'brokerInfo', // 查询当前broker交易规则和symbol信息 + 'getOptions', + ], + }, + 'quote': { + 'get': [ + 'depth', // 获取深度 + 'depth/merged', + 'trades', // 获取当前最新成交 + 'klines', // 获取K线数据 + 'ticker/24hr', // 获取24小时价格变化数据 + 'ticker/price', + 'ticker/bookTicker', + 'contract/index', // 获取合约标的指数价格 + 'contract/depth', // 获取合约深度 + 'contract/depth/merged', + 'contract/trades', // 获取合约最近成交, + 'contract/klines', // 获取合约的K线数据 + 'contract/ticker/24hr', + 'option/index', + 'option/depth', + 'option/depth/merged', + 'option/trades', + 'option/klines', + 'option/ticker/24hr', + ], + }, + 'contract': { + 'get': [ + // public + 'insurance', + 'fundingRate', // 获取资金费率信息 + // private + 'openOrders', // 查询合约当前委托 + 'historyOrders', // 查询合约历史委托 + 'getOrder', // 查询合约订单详情 + 'myTrades', // 查询合约历史成交 + 'positions', // 查询合约当前持仓 + 'account', // 查询合约账户信息 + ], + 'post': [ + 'order', // 创建合约订单 + 'modifyMargin', // 修改保证金 + ], + 'delete': [ + 'order/cancel', // 取消合约订单 + 'order/batchCancel', + ], + }, + 'option': { + 'get': [ + 'openOrders', + 'positions', + 'historyOrders', + // 'getOrder', + 'myTrades', + 'settlements', + 'account', + ], + 'post': [ + 'order', + ], + 'delete': [ + 'order/cancel', + ], + }, + 'private': { + 'get': [ + 'order', // 查询订单 + 'openOrders', // 查询当前委托 + 'historyOrders', // 查询历史委托 + 'account', // 获取当前账户信息 + 'myTrades', // 查询历史成交 + 'depositOrders', + 'withdrawalOrders', + 'withdraw/detail', + 'balance_flow', + ], + 'post': [ + 'order', // 创建新订单 + 'order/test', + 'userDataStream', + 'subAccount/query', + 'transfer', + 'user/transfer', + 'withdraw', + ], + 'put': [ + 'userDataStream', + ], + 'delete': [ + 'order', // 取消订单 + 'userDataStream', + ], + }, + }, + 'precisionMode': TICK_SIZE, + 'fees': { + 'trading': { + 'tierBased': false, + 'percentage': true, + 'maker': 0.002, // MAKER费率 + 'taker': 0.002, // TAKER费率 + }, + }, + 'exceptions': { + 'exact': { + // general server or network errors + '-1000': ExchangeError, // An unknown error occured while processing the request + '-1001': ExchangeError, // Internal error, unable to process your request. Please try again + '-1002': AuthenticationError, // You are not authorized to execute this request. Request need API Key included in. We suggest that API Key be included in any request + '-1003': RateLimitExceeded, // Too many requests, please use the websocket for live updates + '-1004': BadRequest, + '-1005': PermissionDenied, + '-1006': BadResponse, // An unexpected response was received from the message bus. Execution status unknown. OPEN API server find some exception in execute request.Please report to Customer service + '-1007': RequestTimeout, // Timeout waiting for response from backend server. Send status unknown, execution status unknown + '-1014': InvalidOrder, // Unsupported order combination + '-1015': RateLimitExceeded, // Reach the rate limit.Please slow down your request speed + '-1016': ExchangeNotAvailable, // This service is no longer available + '-1020': NotSupported, // This operation is not supported + '-1021': BadRequest, // Timestamp for this request is outside of the recvWindow + '-1022': AuthenticationError, // Signature for this request is not valid + // request issues + '-1100': BadRequest, // Illegal characters found in a parameter + '-1101': BadRequest, // Too many parameters sent for this endpoint + '-1102': BadRequest, // A mandatory parameter was not sent, was empty/null, or malformed + '-1103': BadRequest, // An unknown parameter was sent + '-1104': BadRequest, // Not all sent parameters were read + '-1105': BadRequest, // A parameter was empty + '-1106': BadRequest, // A parameter was sent when not required + '-1111': BadRequest, // Precision is over the maximum defined for this asset + '-1112': NullResponse, // No orders on book for symbol + '-1114': InvalidOrder, // TimeInForce parameter sent when not required + '-1115': InvalidOrder, // Invalid timeInForce + '-1116': InvalidOrder, // Invalid orderType + '-1117': InvalidOrder, // Invalid side + '-1118': InvalidOrder, // New client order ID was empty + '-1119': InvalidOrder, // Original client order ID was empty + '-1120': BadRequest, // Invalid interval + '-1121': BadSymbol, // Invalid symbol + '-1125': AuthenticationError, // This listenKey does not exist + '-1127': BadRequest, // Lookup interval is too big + '-1128': BadRequest, // Combination of optional parameters invalid + '-1130': BadRequest, // Invalid data sent for a parameter + '-1131': InsufficientFunds, + '-1132': InvalidOrder, // Order price too high + '-1133': InvalidOrder, // Order price lower than the minimum,please check general broker info + '-1134': InvalidOrder, // Order price decimal too long,please check general broker info + '-1135': InvalidOrder, // Order quantity too large + '-1136': InvalidOrder, // Order quantity lower than the minimum + '-1137': InvalidOrder, // Order quantity decimal too long + '-1138': InvalidOrder, // Order price exceeds permissible range + '-1139': InvalidOrder, // Order has been filled + '-1140': InvalidOrder, // Transaction amount lower than the minimum + '-1141': InvalidOrder, // Duplicate clientOrderId + '-1142': InvalidOrder, // Order has been canceled + '-1143': OrderNotFound, // Cannot be found on order book + '-1144': InvalidOrder, // Order has been locked + '-1145': InvalidOrder, // This order type does not support cancellation + '-1146': RequestTimeout, // Order creation timeout + '-1147': RequestTimeout, // Order cancellation timeout + '-1149': InvalidOrder, // Create order failed + '-1187': InvalidAddress, // Withdrawal address not in whitelist + '-2010': InvalidOrder, // NEW_ORDER_REJECTED + '-2011': InvalidOrder, // CANCEL_REJECTED + '-2013': OrderNotFound, // Order does not exist + '-2014': AuthenticationError, // API-key format invalid + '-2015': AuthenticationError, // Invalid API-key, IP, or permissions for action + '-2016': ExchangeError, // No trading window could be found for the symbol. Try ticker/24hrs instead + }, + }, + // exchange-specific options + 'options': { + 'fetchTickers': { + 'method': 'quoteGetTicker24hr', + }, + }, + }); + } + + async fetchTime (params = {}) { + const response = await this.publicGetTime (params); + // + // { + // "serverTime": 1527777538000 + // } + // + return this.safeInteger (response, 'serverTime'); + } + + parseMarket (market, type = 'spot') { + const filters = this.safeValue (market, 'filters', []); + const id = this.safeString (market, 'symbol'); + let baseId = this.safeString (market, 'baseAsset'); + const quoteId = this.safeString (market, 'quoteAsset'); + let base = this.safeCurrencyCode (baseId); + const quote = this.safeCurrencyCode (quoteId); + let symbol = base + '/' + quote; + let spot = true; + let future = false; + let option = false; + let inverse = false; + if (type === 'future') { + symbol = id; + spot = false; + future = true; + inverse = this.safeValue (market, 'inverse', false); + baseId = this.safeString (market, 'underlying'); + base = this.safeCurrencyCode (baseId); + } else if (type === 'option') { + symbol = id; + spot = false; + option = true; + } + let amountMin = undefined; + let amountMax = undefined; + let priceMin = undefined; + let priceMax = undefined; + let costMin = undefined; + for (let j = 0; j < filters.length; j++) { + const filter = filters[j]; + const filterType = this.safeString (filter, 'filterType'); + if (filterType === 'LOT_SIZE') { + amountMin = this.safeFloat (filter, 'minQty'); + amountMax = this.safeFloat (filter, 'maxQty'); + } + if (filterType === 'PRICE_FILTER') { + priceMin = this.safeFloat (filter, 'minPrice'); + priceMax = this.safeFloat (filter, 'maxPrice'); + } + if (filterType === 'MIN_NOTIONAL') { + costMin = this.safeFloat (filter, 'minNotional'); + } + } + if ((costMin === undefined) && (amountMin !== undefined) && (priceMin !== undefined)) { + costMin = amountMin * priceMin; + } + const precision = { + 'price': this.safeFloat2 (market, 'quotePrecision', 'quoteAssetPrecision'), + 'amount': this.safeFloat (market, 'baseAssetPrecision'), + }; + const limits = { + 'amount': { + 'min': amountMin, + 'max': amountMax, + }, + 'price': { + 'min': priceMin, + 'max': priceMax, + }, + 'cost': { + 'min': costMin, + 'max': undefined, + }, + }; + return { + 'id': id, + 'symbol': symbol, + 'base': base, + 'quote': quote, + 'baseId': baseId, + 'quoteId': quoteId, + 'active': true, + 'type': type, + 'spot': spot, + 'future': future, + 'option': option, + 'inverse': inverse, + 'precision': precision, + 'limits': limits, + 'info': market, + }; + } + + async fetchMarkets (params = {}) { + const response = await this.publicGetBrokerInfo (params); + // + // { + // "timezone":"UTC", + // "serverTime":"1588015885118", + // "brokerFilters":[], + // "symbols":[ + // { + // "filters":[ + // {"minPrice":"0.01","maxPrice":"100000.00000000","tickSize":"0.01","filterType":"PRICE_FILTER"}, + // {"minQty":"0.0005","maxQty":"100000.00000000","stepSize":"0.000001","filterType":"LOT_SIZE"}, + // {"minNotional":"5","filterType":"MIN_NOTIONAL"} + // ], + // "exchangeId":"301", + // "symbol":"BTCUSDT", + // "symbolName":"BTCUSDT", + // "status":"TRADING", + // "baseAsset":"BTC", + // "baseAssetPrecision":"0.000001", + // "quoteAsset":"USDT", + // "quotePrecision":"0.01", + // "icebergAllowed":false + // }, + // ], + // "options":[ + // { + // "filters":[ + // {"minPrice":"0.01","maxPrice":"100000.00000000","tickSize":"0.01","filterType":"PRICE_FILTER"}, + // {"minQty":"0.01","maxQty":"100000.00000000","stepSize":"0.001","filterType":"LOT_SIZE"}, + // {"minNotional":"1","filterType":"MIN_NOTIONAL"} + // ], + // "exchangeId":"301", + // "symbol":"BTC0501CS8500", + // "symbolName":"BTC0501CS8500", + // "status":"TRADING", + // "baseAsset":"BTC0501CS8500", + // "baseAssetPrecision":"0.001", + // "quoteAsset":"BUSDT", + // "quotePrecision":"0.01", + // "icebergAllowed":false + // }, + // ], + // "contracts":[ + // { + // "filters":[ + // {"minPrice":"0.1","maxPrice":"100000.00000000","tickSize":"0.1","filterType":"PRICE_FILTER"}, + // {"minQty":"1","maxQty":"100000.00000000","stepSize":"1","filterType":"LOT_SIZE"}, + // {"minNotional":"0.000001","filterType":"MIN_NOTIONAL"} + // ], + // "exchangeId":"301", + // "symbol":"BTC-PERP-REV", + // "symbolName":"BTC-PERP-REV", + // "status":"TRADING", + // "baseAsset":"BTC-PERP-REV", + // "baseAssetPrecision":"1", + // "quoteAsset":"USDT", + // "quoteAssetPrecision":"0.1", + // "icebergAllowed":false, + // "inverse":true, + // "index":"BTCUSDT", + // "marginToken":"TBTC", + // "marginPrecision":"0.00000001", + // "contractMultiplier":"1.0", + // "underlying":"TBTC", + // "riskLimits":[ + // {"riskLimitId":"200000001","quantity":"1000000.0","initialMargin":"0.01","maintMargin":"0.005"}, + // {"riskLimitId":"200000002","quantity":"2000000.0","initialMargin":"0.02","maintMargin":"0.01"}, + // {"riskLimitId":"200000003","quantity":"3000000.0","initialMargin":"0.03","maintMargin":"0.015"}, + // {"riskLimitId":"200000004","quantity":"4000000.0","initialMargin":"0.04","maintMargin":"0.02"} + // ] + // }, + // { + // "filters":[ + // {"minPrice":"0.1","maxPrice":"100000.00000000","tickSize":"0.1","filterType":"PRICE_FILTER"}, + // {"minQty":"1","maxQty":"100000.00000000","stepSize":"1","filterType":"LOT_SIZE"}, + // {"minNotional":"0.000001","filterType":"MIN_NOTIONAL"} + // ], + // "exchangeId":"301", + // "symbol":"BTC-SWAP", + // "symbolName":"BTC-SWAP", + // "status":"TRADING", + // "baseAsset":"BTC-SWAP", + // "baseAssetPrecision":"1", + // "quoteAsset":"USDT", + // "quoteAssetPrecision":"0.1", + // "icebergAllowed":false, + // "inverse":true, + // "index":"BTCUSDT", + // "marginToken":"BTC", + // "marginPrecision":"0.00000001", + // "contractMultiplier":"1.0", + // "underlying":"BTC", + // "riskLimits":[ + // {"riskLimitId":"500000001","quantity":"1000000.0","initialMargin":"0.01","maintMargin":"0.005"}, + // {"riskLimitId":"500000002","quantity":"2000000.0","initialMargin":"0.02","maintMargin":"0.01"}, + // {"riskLimitId":"500000003","quantity":"3000000.0","initialMargin":"0.03","maintMargin":"0.015"}, + // {"riskLimitId":"500000004","quantity":"4000000.0","initialMargin":"0.04","maintMargin":"0.02"} + // ] + // }, + // { + // "filters":[ + // {"minPrice":"0.1","maxPrice":"100000.00000000","tickSize":"0.1","filterType":"PRICE_FILTER"}, + // {"minQty":"1","maxQty":"100000.00000000","stepSize":"1","filterType":"LOT_SIZE"}, + // {"minNotional":"0.000000001","filterType":"MIN_NOTIONAL"} + // ], + // "exchangeId":"301", + // "symbol":"BTC-PERP-BUSDT", + // "symbolName":"BTC-PERP-BUSDT", + // "status":"TRADING", + // "baseAsset":"BTC-PERP-BUSDT", + // "baseAssetPrecision":"1", + // "quoteAsset":"BUSDT", + // "quoteAssetPrecision":"0.1", + // "icebergAllowed":false, + // "inverse":false, + // "index":"BTCUSDT", + // "marginToken":"BUSDT", + // "marginPrecision":"0.0001", + // "contractMultiplier":"0.0001", + // "underlying":"TBTC", + // "riskLimits":[ + // {"riskLimitId":"600000132","quantity":"1000000.0","initialMargin":"0.01","maintMargin":"0.005"}, + // {"riskLimitId":"600000133","quantity":"2000000.0","initialMargin":"0.02","maintMargin":"0.01"}, + // {"riskLimitId":"600000134","quantity":"3000000.0","initialMargin":"0.03","maintMargin":"0.015"}, + // {"riskLimitId":"600000135","quantity":"4000000.0","initialMargin":"0.04","maintMargin":"0.02"} + // ] + // }, + // ] + // } + // + const result = []; + const symbols = this.safeValue (response, 'symbols', []); + for (let i = 0; i < symbols.length; i++) { + const market = this.parseMarket (symbols[i], 'spot'); + result.push (market); + } + const options = this.safeValue (response, 'options', []); + for (let i = 0; i < options.length; i++) { + const market = this.parseMarket (options[i], 'option'); + result.push (market); + } + const contracts = this.safeValue (response, 'contracts', []); + for (let i = 0; i < contracts.length; i++) { + const market = this.parseMarket (contracts[i], 'future'); + result.push (market); + } + return 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 40, max 40 + } + const response = await this.quoteGetDepth (this.extend (request, params)); + // + // { + // "time":1588068913453, + // "bids":[ + // ["0.025278","0.0202"], + // ["0.025277","16.1132"], + // ["0.025276","7.9056"], + // ] + // "asks":[ + // ["0.025302","5.9999"], + // ["0.025303","34.9151"], + // ["0.025304","92.391"], + // ] + // } + // + const timestamp = this.safeInteger (response, 'time'); + return this.parseOrderBook (response, timestamp); + } + + async fetchTicker (symbol, params = {}) { + await this.loadMarkets (); + const market = this.market (symbol); + const request = { + 'symbol': market['id'], + }; + const response = await this.quoteGetTicker24hr (this.extend (request, params)); + // + // { + // "time":1588069860794, + // "symbol":"BNB0501PS16", + // "bestBidPrice":"0.2129", + // "bestAskPrice":"0.3163", + // "volume":"33547", + // "quoteVolume":"10801.987", + // "lastPrice":"0.2625", + // "highPrice":"0.3918", + // "lowPrice":"0.2625", + // "openPrice":"0.362", + // } + // + 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 fetchBidAsk (symbol, params = {}) { + await this.loadMarkets (); + const market = this.market (symbol); + const request = { + 'symbol': market['id'], + }; + const response = await this.quoteGetTickerBookTicker (this.extend (request, params)); + // + // { + // "symbol": "LTCBTC", + // "bidPrice": "4.00000000", + // "bidQty": "431.00000000", + // "askPrice": "4.00000200", + // "askQty": "9.00000000" + // } + // + return this.parseTicker (response, market); + } + + async fetchBidsAsks (symbols = undefined, params = {}) { + await this.loadMarkets (); + const response = await this.quoteGetTickerBookTicker (params); + // + // [ + // { + // "symbol": "LTCBTC", + // "bidPrice": "4.00000000", + // "bidQty": "431.00000000", + // "askPrice": "4.00000200", + // "askQty": "9.00000000" + // }, + // { + // "symbol": "ETHBTC", + // "bidPrice": "0.07946700", + // "bidQty": "9.00000000", + // "askPrice": "100000.00000000", + // "askQty": "1000.00000000" + // }, + // ] + // + return this.parseTickers (response, symbols); + } + + async fetchTickers (symbols = undefined, params = {}) { + await this.loadMarkets (); + const options = this.safeValue (this.options, 'fetchTickers', {}); + const defaultMethod = this.safeString (options, 'method', 'quoteGetTicker24hr'); + const defaultType = this.safeString (options, 'type', 'spot'); + const type = this.safeString (params, 'type', defaultType); + const query = this.omit (params, 'type'); + let method = defaultMethod; + if (type === 'future') { + method = 'quoteGetContractTicker24hr'; + } else if (type === 'option') { + method = 'quoteGetOptionTicker24hr'; + } + const response = await this[method] (query); + // + // [ + // { + // "time": 1538725500422, + // "symbol": "ETHBTC", + // "lastPrice": "4.00000200", + // "openPrice": "99.00000000", + // "highPrice": "100.00000000", + // "lowPrice": "0.10000000", + // "volume": "8913.30000000" + // }, + // ] + // + return this.parseTickers (response, symbols); + } + + async fetchBalance (params = {}) { + await this.loadMarkets (); + const options = this.safeValue (this.options, 'fetchBalance', {}); + const defaultType = this.safeString (options, 'type', 'spot'); + const type = this.safeString (params, 'type', defaultType); + const query = this.omit (params, 'type'); + let method = 'privateGetAccount'; + if (type === 'future') { + method = 'contractGetAccount'; + } else if (type === 'option') { + method = 'optionGetAccount'; + } + const response = await this[method] (query); + // + // spot + // + // { + // 'balances': [ + // { + // 'asset': 'ALGO', + // 'free': '0', + // 'locked': '0' + // }, + // { + // 'asset': 'BHT', + // 'free': '0', + // 'locked': '0' + // } + // ] + // } + // + // contract + // + // { + // "BUSDT":{ + // "total":"1000", + // "availableMargin":"1000", + // "positionMargin":"0", + // "orderMargin":"0", + // "tokenId":"BUSDT" + // }, + // "TBTC":{ + // "total":"0.5", + // "availableMargin":"0.5", + // "positionMargin":"0", + // "orderMargin":"0", + // "tokenId":"TBTC" + // } + // } + // + // option + // + // { + // "optionAsset":"", + // "balances":[ + // { + // "tokenName":"USDT", + // "free":"0.0", + // "locked":"0.0", + // "margin":"0.0" + // }, + // { + // "tokenName":"BUSDT", + // "free":"0.0", + // "locked":"0.0", + // "margin":"0.0" + // } + // ] + // } + // + const balances = this.safeValue (response, 'balances'); + const result = { 'info': response }; + if (balances !== undefined) { + for (let i = 0; i < balances.length; i++) { + const balance = balances[i]; + const currencyId = this.safeString2 (balance, 'asset', 'tokenName'); + 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 { + const currencyIds = Object.keys (response); + for (let i = 0; i < currencyIds.length; i++) { + const currencyId = currencyIds[i]; + const code = this.safeCurrencyCode (currencyId); + const balance = response[currencyId]; + const account = this.account (); + account['free'] = this.safeFloat (balance, 'availableMargin'); + account['total'] = this.safeFloat (balance, 'total'); + result[code] = account; + } + } + return this.parseBalance (result); + } + + async fetchTrades (symbol, since = undefined, limit = 50, params = {}) { + await this.loadMarkets (); + const market = this.market (symbol); + const request = { + 'symbol': market['id'], + }; + if (limit !== undefined) { + request['limit'] = limit; // default 500, max 1000 + } + const response = await this.quoteGetTrades (this.extend (request, params)); + // + // [ + // {"price":"0.025344","time":1588084082060,"qty":"1","isBuyerMaker":false}, + // {"price":"0.02535","time":1588084086021,"qty":"0.553","isBuyerMaker":true}, + // {"price":"0.025348","time":1588084097037,"qty":"1","isBuyerMaker":false}, + // ] + // + return this.parseTrades (response, market, since, limit); + } + + parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) { + // + // [ + // 1587906000000, // open time + // "0.1761", // open + // "0.1761", // high + // "0.1761", // low + // "0.1761", // close + // "0", // base volume + // 0, // close time + // "0", // quote volume + // 0, // number of trades + // "0", // taker buy base asset volume + // "0" // taker buy quote asset volume + // ] + // + 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 500, max 500 + } + const response = await this.quoteGetKlines (this.extend (request, params)); + // + // [ + // [1587906000000,"0.1761","0.1761","0.1761","0.1761","0",0,"0",0,"0","0"], + // [1587906180000,"0.1761","0.1761","0.1761","0.1761","0",0,"0",0,"0","0"], + // [1587906360000,"0.1761","0.1848","0.1761","0.1848","53",0,"9.7944",1,"0","0"], + // ] + // + return this.parseOHLCVs (response, market, timeframe, since, limit); + } + + async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) { + await this.loadMarkets (); + let market = undefined; + const request = { + // if only fromId is set,it will get orders < that fromId in descending order + // if only toId is set, it will get orders > that toId in ascending order + // if fromId is set and toId is set, it will get orders < that fromId and > that toId in descending order + // if fromId is not set and toId it not set, most recent order are returned in descending order + // 'fromId': '43287482374', + // 'toId': '43287482374', + // 'endTime': this.milliseconds (), // optional, spot only + }; + const defaultType = this.safeString (this.options, 'type', 'spot'); + const options = this.safeValue (this.options, 'fetchMyTrades', {}); + const fetchMyTradesType = this.safeString (options, 'type', defaultType); + let type = this.safeString (params, 'type', fetchMyTradesType); + if (symbol !== undefined) { + market = this.market (symbol); + request['symbol'] = market['id']; + type = market['type']; + } + const query = this.omit (params, 'type'); + if (limit !== undefined) { + // spot default 500, max 1000 + // futures and options default 20, max 1000 + request['limit'] = limit; + } + let method = 'privateGetMyTrades'; + if (type === 'future') { + method = 'contractGetMyTrades'; + } else { + if (type === 'option') { + method = 'optionGetMyTrades'; + } else { + if (symbol === undefined) { + throw new ArgumentsRequired (this.id + ' fetchMyTrades requires a `symbol` argument for ' + type + ' markets'); + } + const market = this.market (symbol); + request['symbol'] = market['id']; + // spot only? + if (since !== undefined) { + request['startTime'] = since; + } + } + } + if (since !== undefined) { + request['startTime'] = since; + } + const response = await this[method] (this.extend (request, query)); + // + // spot + // + // [ + // { + // "id":"616384027512920576", + // "symbol":"TBTCBUSDT", + // "orderId":"616384027202542080", + // "matchOrderId":"605124954767266560", + // "price":"6826.06", + // "qty":"0.1", + // "commission":"0.682606", + // "commissionAsset":"BUSDT", + // "time":"1588214701982", + // "isBuyer":false, + // "isMaker":false, + // "fee":{ + // "feeTokenId":"BUSDT", + // "feeTokenName":"BUSDT", + // "fee":"0.682606" + // } + // } + // ] + // + return this.parseTrades (response, market, since, limit); + } + + async createOrder (symbol, type, side, amount, price = undefined, params = {}) { + await this.loadMarkets (); + const market = this.market (symbol); + const orderSide = side.toUpperCase (); + const orderType = type.toUpperCase (); + const request = { + 'symbol': market['id'], + // BUY or SELL for spot and options + 'side': orderSide, + // GTC, FOK, IOC for spot and options + // GTC, FOK, IOC, LIMIT_MAKER for futures + // 'timeInForce': 'GTC', + }; + let query = params; + let method = 'privatePostOrder'; + if (market['type'] === 'future') { + if ((orderSide !== 'BUY_OPEN') && (orderSide !== 'SELL_OPEN') && (orderSide !== 'BUY_CLOSE') && (orderSide !== 'SELL_CLOSE')) { + throw new NotSupported (this.id + ' createOrder() does not support order side ' + side + ' for ' + market['type'] + ' markets, only BUY_OPEN, SELL_OPEN, BUY_CLOSE and SELL_CLOSE are supported'); + } + if ((orderType !== 'LIMIT') && (orderType !== 'STOP')) { + throw new NotSupported (this.id + ' createOrder() does not support order type ' + type + ' for ' + market['type'] + ' markets, only LIMIT and STOP are supported'); + } + const clientOrderId = this.safeValue (params, 'clientOrderId'); + if (clientOrderId === undefined) { + throw new ArgumentsRequired (this.id + ' createOrder() requires a clientOrderId parameter for ' + market['type'] + ' markets, supply clientOrderId in the params argument'); + } + const leverage = this.safeValue (params, 'leverage'); + if (leverage === undefined && (orderSide === 'BUY_OPEN' || orderSide === 'SELL_OPEN')) { + throw new NotSupported (this.id + ' createOrder() requires a leverage parameter for ' + market['type'] + ' markets if orderSide is BUY_OPEN or SELL_OPEN'); + } + method = 'contractPostOrder'; + const priceType = this.safeString (params, 'priceType'); + if (priceType === undefined) { + request['price'] = this.priceToPrecision (symbol, price); + } else { + request['priceType'] = priceType; + if (priceType === 'INPUT') { + request['price'] = this.priceToPrecision (symbol, price); + } + } + request['orderType'] = type.toUpperCase (); // LIMIT, STOP + request['quantity'] = this.amountToPrecision (symbol, amount); + // request['leverage'] = 1; // not required for closing orders + request['leverage'] = leverage; + request['clientOrderId'] = clientOrderId; + // optional + // request['priceType'] = 'INPUT', // INPUT, OPPONENT, QUEUE, OVER, MARKET + // request['triggerPrice'] = 123.45; + } else { + if (market['type'] === 'option') { + method = 'optionPostOrder'; + } + const newClientOrderId = this.safeValue2 (params, 'clientOrderId', 'newClientOrderId'); + if (newClientOrderId !== undefined) { + request['newClientOrderId'] = newClientOrderId; + } + request['type'] = orderType; + if (type === 'limit') { + request['price'] = this.priceToPrecision (symbol, price); + request['quantity'] = this.amountToPrecision (symbol, amount); + } else if (type === 'market') { + // for market buy it requires the amount of quote currency to spend + if (side === 'buy') { + const createMarketBuyOrderRequiresPrice = this.safeValue (this.options, 'createMarketBuyOrderRequiresPrice', true); + if (createMarketBuyOrderRequiresPrice) { + if (price !== undefined) { + amount = amount * price; + } else { + throw new InvalidOrder (this.id + " createOrder() requires the price argument with market buy orders to calculate total order cost (amount to spend), where cost = amount * price. Supply a price argument to createOrder() call if you want the cost to be calculated for you from price and amount, or, alternatively, add .options['createMarketBuyOrderRequiresPrice'] = false and supply the total cost value in the 'amount' argument (the exchange-specific behaviour)"); + } + } + const precision = market['precision']['price']; + request['quantity'] = this.decimalToPrecision (amount, TRUNCATE, precision, this.precisionMode); + } else { + request['quantity'] = this.amountToPrecision (symbol, amount); + } + } + } + query = this.omit (query, [ 'clientOrderId', 'newClientOrderId' ]); + const response = await this[method] (this.extend (request, query)); + // + // spot + // + // { + // "symbol":"TBTCBUSDT", + // "orderId":"616376654496877056", + // "clientOrderId":"158821382304516955", + // "transactTime":"1588213823080", + // "price":"0", + // "origQty":"1000", + // "executedQty":"0", + // "status":"NEW", + // "timeInForce":"GTC", + // "type":"MARKET", + // "side":"BUY" + // } + // + // contract + // + // { + // 'time': '1570759718825', + // 'updateTime': '0', + // 'orderId': '469961015902208000', + // 'clientOrderId': '6423344174', + // 'symbol': 'BTC-PERP-REV', + // 'price': '8200', + // 'leverage': '12.08', + // 'origQty': '5', + // 'executedQty': '0', + // 'avgPrice': '0', + // 'marginLocked': '0.00005047', + // 'orderType': 'LIMIT', + // 'side': 'BUY_OPEN', + // 'fees': [], + // 'timeInForce': 'GTC', + // 'status': 'NEW', + // 'priceType': 'INPUT' + // } + // + return this.parseOrder (response, market); + } + + async cancelOrder (id, symbol = undefined, params = {}) { + await this.loadMarkets (); + const clientOrderId = this.safeValue2 (params, 'origClientOrderId', 'clientOrderId'); + const request = {}; + const defaultType = this.safeString (this.options, 'type', 'spot'); + const options = this.safeValue (this.options, 'cancelOrder', {}); + const cancelOrderType = this.safeString (options, 'type', defaultType); + let type = this.safeString (params, 'type', cancelOrderType); + let query = this.omit (params, 'type'); + if (clientOrderId !== undefined) { + request['origClientOrderId'] = clientOrderId; + query = this.omit (query, [ 'origClientOrderId', 'clientOrderId' ]); + } else { + request['orderId'] = id; + } + let method = 'privateDeleteOrder'; + const orderType = this.safeString (query, 'orderType'); + if (orderType !== undefined) { + type = 'future'; + } + if (type === 'future') { + method = 'contractDeleteOrderCancel'; + if (orderType === undefined) { + throw new ArgumentsRequired (this.id + " cancelOrder() requires an orderType parameter, pass the { 'orderType': 'LIMIT' } or { 'orderType': 'STOP' } in params argument"); + } + request['orderType'] = orderType; + } else { + if (type === 'option') { + method = 'optionDeleteOrderCancel'; + } + } + const response = await this[method] (this.extend (request, query)); + // + // spot + // + // { + // 'exchangeId': '301', + // 'symbol': 'BHTUSDT', + // 'clientOrderId': '0', + // 'orderId': '499890200602846976', + // 'status': 'CANCELED' + // } + // + // futures + // + // { + // "time":"1588353669383", + // "updateTime":"0", + // "orderId":"617549770304599296", + // "clientOrderId":"test-001", + // "symbol":"BTC-PERP-REV", + // "price":"10000", + // "leverage":"1", + // "origQty":"100", + // "executedQty":"0", + // "avgPrice":"0", + // "marginLocked":"0", + // "orderType":"LIMIT", + // "side":"SELL_OPEN", + // "fees":[], + // "timeInForce":"GTC", + // "status":"CANCELED", + // "priceType":"INPUT", + // } + // + return this.parseOrder (response); + } + + async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) { + await this.loadMarkets (); + let market = undefined; + const request = { + // if orderId is set, it will get orders < that orderId otherwise most recent orders are returned + // 'orderId': '43287482374', + }; + const defaultType = this.safeString (this.options, 'type', 'spot'); + const options = this.safeValue (this.options, 'fetchOpenOrders', {}); + const fetchOpenOrdersType = this.safeString (options, 'type', defaultType); + let type = this.safeString (params, 'type', fetchOpenOrdersType); + if (symbol !== undefined) { + market = this.market (symbol); + request['symbol'] = market['id']; + type = market['type']; + } + const query = this.omit (params, 'type'); + if (limit !== undefined) { + request['limit'] = limit; // default 500, max 1000 + } + let method = 'privateGetOpenOrders'; + if (type === 'future') { + method = 'contractGetOpenOrders'; + } else if (type === 'option') { + method = 'optionGetOpenOrders'; + } + const response = await this[method] (this.extend (request, query)); + // + // spot + // + // [ + // { + // 'orderId': '499902955766523648', + // 'clientOrderId': '157432907618453', + // 'exchangeId': '301', + // 'symbol': 'BHTUSDT', + // 'price': '0.01', + // 'origQty': '50', + // 'executedQty': '0', + // 'cummulativeQuoteQty': '0', + // 'avgPrice': '0', + // 'status': 'NEW', + // 'timeInForce': 'GTC', + // 'type': 'LIMIT', + // 'side': 'BUY', + // 'stopPrice': '0.0', + // 'icebergQty': '0.0', + // 'time': '1574329076202', + // 'updateTime': '0', + // 'isWorking': true + // } + // ] + // + // futures + // + // [ + // { + // "time":"1588353669383", + // "updateTime":"0", + // "orderId":"617549770304599296", + // "clientOrderId":"test-001", + // "symbol":"BTC-PERP-REV", + // "price":"10000", + // "leverage":"1", + // "origQty":"100", + // "executedQty":"0", + // "avgPrice":"0", + // "marginLocked":"0.01", + // "orderType":"LIMIT", + // "side":"SELL_OPEN", + // "fees":[], + // "timeInForce":"GTC", + // "status":"NEW", + // "priceType":"INPUT" + // } + // ] + // + return this.parseOrders (response, market, since, limit); + } + + async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) { + await this.loadMarkets (); + let market = undefined; + const request = { + // if orderId is set, it will get orders < that orderId otherwise most recent orders are returned + // 'orderId': '43287482374', + // 'endTime': this.milliseconds (), // optional + }; + const defaultType = this.safeString (this.options, 'type', 'spot'); + const options = this.safeValue (this.options, 'fetchClosedOrders', {}); + const fetchClosedOrdersType = this.safeString (options, 'type', defaultType); + let type = this.safeString (params, 'type', fetchClosedOrdersType); + if (symbol !== undefined) { + market = this.market (symbol); + request['symbol'] = market['id']; + type = market['type']; + } + const query = this.omit (params, 'type'); + if (limit !== undefined) { + request['limit'] = limit; // default 500, max 1000 + } + if (since !== undefined) { + request['startTime'] = since; + } + let method = 'privateGetHistoryOrders'; + if (type === 'future') { + method = 'contractGetHistoryOrders'; + } else if (type === 'option') { + method = 'optionGetHistoryOrders'; + } + const response = await this[method] (this.extend (request, query)); + // + // spot + // + // [ + // { + // "orderId":"616384027202542080", + // "clientOrderId":"158821470194414688", + // "exchangeId":"301", + // "symbol":"TBTCBUSDT", + // "price":"0", + // "origQty":"0.1", + // "executedQty":"0.1", + // "cummulativeQuoteQty":"682.606", + // "avgPrice":"6826.06", + // "status":"FILLED", + // "timeInForce":"GTC", + // "type":"MARKET", + // "side":"SELL", + // "stopPrice":"0.0", + // "icebergQty":"0.0", + // "time":"1588214701974", + // "updateTime":"0", + // "isWorking":true + // } + // ] + // + return this.parseOrders (response, market, since, limit); + } + + async fetchOrder (id, symbol = undefined, params = {}) { + await this.loadMarkets (); + const clientOrderId = this.safeValue2 (params, 'origClientOrderId', 'clientOrderId'); + const request = {}; + const defaultType = this.safeString (this.options, 'type', 'spot'); + const options = this.safeValue (this.options, 'fetchOrder', {}); + const fetchOrderType = this.safeString (options, 'type', defaultType); + const type = this.safeString (params, 'type', fetchOrderType); + let query = this.omit (params, 'type'); + if (clientOrderId !== undefined) { + request['origClientOrderId'] = clientOrderId; + query = this.omit (query, [ 'origClientOrderId', 'clientOrderId' ]); + } else { + request['orderId'] = id; + } + let method = 'privateGetOrder'; + if (type === 'future') { + method = 'contractGetGetOrder'; + } else if (type === 'option') { + method = 'optionGetGetOrder'; + } + const response = await this[method] (this.extend (request, query)); + return this.parseOrder (response); + } + + async fetchDeposits (code = undefined, since = undefined, limit = undefined, params = {}) { + await this.loadMarkets (); + let currency = undefined; + const request = { + // 'fromId': 'string', // if fromId is set, it will get deposits > that fromId, otherwise most recent deposits are returned + }; + if (code !== undefined) { + currency = this.currency (code); + } + if (since !== undefined) { + request['startTime'] = since; + } + if (limit !== undefined) { + request['limit'] = limit; + } + const response = await this.privateGetDepositOrders (this.extend (request, params)); + // + // [ + // { + // 'time': '1565769575929', + // 'orderId': '428100569859739648', + // 'token': 'USDT', + // 'address': '', + // 'addressTag': '', + // 'fromAddress': '', + // 'fromAddressTag': '', + // 'quantity': '1100', + // }, + // ] + // + return this.parseTransactions (response, currency, since, limit); + } + + async fetchWithdrawals (code = undefined, since = undefined, limit = undefined, params = {}) { + await this.loadMarkets (); + let currency = undefined; + const request = { + // 'fromId': 'string', // if fromId is set, it will get deposits > that fromId, otherwise most recent deposits are returned + }; + if (code !== undefined) { + currency = this.currency (code); + request['token'] = currency['id']; + } + if (since !== undefined) { + request['startTime'] = since; + } + if (limit !== undefined) { + request['limit'] = limit; // default 500, max 1000 + } + const response = await this.privateGetWithdrawalOrders (this.extend (request, params)); + // + // [ + // { + // "time":"1536232111669", + // "orderId":"90161227158286336", + // "accountId":"517256161325920", + // "tokenId":"BHC", + // "tokenName":"BHC", + // "address":"0x815bF1c3cc0f49b8FC66B21A7e48fCb476051209", + // "addressExt":"address tag", + // "quantity":"14", // Withdrawal qty + // "arriveQuantity":"14", // Arrived qty + // "statusCode":"PROCESSING_STATUS", + // "status":3, + // "txid":"", + // "txidUrl":"", + // "walletHandleTime":"1536232111669", + // "feeTokenId":"BHC", + // "feeTokenName":"BHC", + // "fee":"0.1", + // "requiredConfirmNum":0, // Required confirmations + // "confirmNum":0, // Confirmations + // "kernelId":"", // BEAM and GRIN only + // "isInternalTransfer": false // True if this transfer is internal + // } + // ] + // + return this.parseTransactions (response, currency, since, limit); + } + + async withdraw (code, amount, address, tag = undefined, params = {}) { + this.checkAddress (address); + await this.loadMarkets (); + const currency = this.currency (code); + const clientOrderId = this.safeString (params, 'clientOrderId', this.uuid ()); + const request = { + 'clientOrderId': clientOrderId, + 'tokenId': currency['id'], + 'address': address, // the withdrawal address must be in current tag list in your PC/APP client + 'withdrawQuantity': amount, + // 'chainType': 'OMNI', // OMNI, ERC20, TRC20 + }; + if (tag !== undefined) { + request['addressExt'] = tag; + } + const response = await this.privatePostWithdraw (this.extend (request, params)); + // + // { + // "status": 0, + // "success": true, + // "needBrokerAudit": false, // Whether this request needs broker auit + // "orderId": "423885103582776064" // Id for successful withdrawal + // } + // + return { + 'info': response, + 'id': this.safeString (response, 'orderId'), + }; + } + + async fetchAccounts (params = {}) { + const response = await this.privatePostSubAccountQuery (params); + // + // [ + // { + // "accountId": "122216245228131", + // "accountName": "createSubAccountByCurl", // sub-account name + // "accountType": 1, // 1 token trading, 2 options, 3 futures + // "accountIndex": 1, // 0 main account, 1 sub-account + // }, + // ] + // + const result = []; + for (let i = 0; i < response.length; i++) { + const account = response[i]; + const accountId = this.safeString (account, 'accountId'); + const accountType = this.safeString (account, 'accountType'); + let type = accountType; + if (accountType === '1') { + type = 'spot'; + } else if (accountType === '2') { + type = 'option'; + } else if (accountType === '3') { + type = 'future'; + } + result.push ({ + 'id': accountId, + 'type': type, + 'currency': undefined, + 'info': account, + }); + } + return result; + } + + async fetchLedger (code = undefined, since = undefined, limit = undefined, params = {}) { + await this.loadMarkets (); + const request = { + 'accountType': 1, // spot 1, options 2, futures 3 + 'accountIndex': 0, // main 0, sub-account 1 + 'fromFlowId': '', // flowId to start from + 'endFlowId': '', // flowId to end with + 'endTime': 1588450533040, + }; + let currency = undefined; + if (code !== undefined) { + currency = this.currency (code); + request['tokenId'] = currency['id']; + } + if (since !== undefined) { + request['startTime'] = since; + } + if (limit !== undefined) { + request['limit'] = limit; // default 500, max 500 + } + const response = await this.privateGetBalanceFlow (this.extend (request, params)); + // + // [ + // { + // "id": "539870570957903104", + // "accountId": "122216245228131", + // "tokenId": "BTC", + // "tokenName": "BTC", + // "flowTypeValue": 51, + // "flowType": "USER_ACCOUNT_TRANSFER", + // "flowName": "Transfer", + // "change": "-12.5", + // "total": "379.624059937852365", // after change + // "created": "1579093587214" + // }, + // { + // "id": "536072393645448960", + // "accountId": "122216245228131", + // "tokenId": "USDT", + // "tokenName": "USDT", + // "flowTypeValue": 7, + // "flowType": "AIRDROP", + // "flowName": "Airdrop", + // "change": "-2000", + // "total": "918662.0917630848", + // "created": "1578640809195" + // } + // ] + // + return this.parseLedger (response, currency, since, limit); + } + + parseLedgerEntry (item, currency = undefined) { + // + // { + // "id": "539870570957903104", + // "accountId": "122216245228131", + // "tokenId": "BTC", + // "tokenName": "BTC", + // "flowTypeValue": 51, + // "flowType": "USER_ACCOUNT_TRANSFER", + // "flowName": "Transfer", + // "change": "-12.5", + // "total": "379.624059937852365", // after change + // "created": "1579093587214" + // } + // + // { + // "id": "536072393645448960", + // "accountId": "122216245228131", + // "tokenId": "USDT", + // "tokenName": "USDT", + // "flowTypeValue": 7, + // "flowType": "AIRDROP", + // "flowName": "Airdrop", + // "change": "-2000", + // "total": "918662.0917630848", + // "created": "1578640809195" + // } + // + const currencyId = this.safeString (item, 'tokenId'); + const code = this.safeCurrencyCode (currencyId, currency); + const amount = this.safeFloat (item, 'change'); + const after = this.safeFloat (item, 'total'); + const direction = (amount < 0) ? 'out' : 'in'; + let before = undefined; + if (after !== undefined && amount !== undefined) { + const difference = (direction === 'out') ? amount : -amount; + before = this.sum (after, difference); + } + const timestamp = this.safeInteger (item, 'created'); + const type = this.parseLedgerEntryType (this.safeString (item, 'flowType')); + const id = this.safeString (item, 'id'); + const account = this.safeString (item, 'accountId'); + return { + 'id': id, + 'currency': code, + 'account': account, + 'referenceAccount': undefined, + 'referenceId': undefined, + 'status': undefined, + 'amount': amount, + 'before': before, + 'after': after, + 'fee': undefined, + 'direction': direction, + 'timestamp': timestamp, + 'datetime': this.iso8601 (timestamp), + 'type': type, + 'info': item, + }; + } + + parseLedgerEntryType (type) { + const types = { + 'TRADE': 'trade', + 'FEE': 'fee', + 'TRANSFER': 'transfer', + 'DEPOSIT': 'transaction', + 'MAKER_REWARD': 'rebate', + 'PNL': 'pnl', + 'SETTLEMENT': 'settlement', + 'LIQUIDATION': 'liquidation', + 'FUNDING_SETTLEMENT': 'settlement', + 'USER_ACCOUNT_TRANSFER': 'transfer', + 'OTC_BUY_COIN': 'trade', + 'OTC_SELL_COIN': 'trade', + 'OTC_FEE': 'fee', + 'OTC_TRADE': 'trade', + 'ACTIVITY_AWARD': 'referral', + 'INVITATION_REFERRAL_BONUS': 'referral', + 'REGISTER_BONUS': 'referral', + 'AIRDROP': 'airdrop', + 'MINE_REWARD': 'reward', + }; + return this.safeString (types, type, type); + } + + parseTransactionStatus (status) { + const statuses = { + 'BROKER_AUDITING_STATUS': 'pending', + 'BROKER_REJECT_STATUS': 'failed', + 'AUDITING_STATUS': 'pending', + 'AUDIT_REJECT_STATUS': 'failed', + 'PROCESSING_STATUS': 'pending', + 'WITHDRAWAL_SUCCESS_STATUS': 'ok', + 'WITHDRAWAL_FAILURE_STATUS': 'failed', + 'BLOCK_MINING_STATUS': 'ok', + }; + return this.safeString (statuses, status, status); + } + + parseTransaction (transaction, currency = undefined) { + // + // fetchDeposits + // + // { + // 'time': '1565769575929', + // 'orderId': '428100569859739648', + // 'token': 'USDT', + // 'address': '', + // 'addressTag': '', + // 'fromAddress': '', + // 'fromAddressTag': '', + // 'quantity': '1100', + // } + // + // fetchWithdrawals + // + // { + // "time":"1536232111669", + // "orderId":"90161227158286336", + // "accountId":"517256161325920", + // "tokenId":"BHC", + // "tokenName":"BHC", + // "address":"0x815bF1c3cc0f49b8FC66B21A7e48fCb476051209", + // "addressExt":"address tag", + // "quantity":"14", // Withdrawal qty + // "arriveQuantity":"14", // Arrived qty + // "statusCode":"PROCESSING_STATUS", + // "status":3, + // "txid":"", + // "txidUrl":"", + // "walletHandleTime":"1536232111669", + // "feeTokenId":"BHC", + // "feeTokenName":"BHC", + // "fee":"0.1", + // "requiredConfirmNum":0, // Required confirmations + // "confirmNum":0, // Confirmations + // "kernelId":"", // BEAM and GRIN only + // "isInternalTransfer": false // True if this transfer is internal + // } + // + const id = this.safeString (transaction, 'orderId'); + const address = this.safeString (transaction, 'address'); + let tag = this.safeString2 (transaction, 'addressExt', 'addressTag'); + if (tag !== undefined) { + if (tag.length < 1) { + tag = undefined; + } + } + const addressFrom = this.safeString (transaction, 'fromAddress'); + let tagFrom = this.safeString (transaction, 'fromAddressTag'); + if (tagFrom !== undefined) { + if (tagFrom.length < 1) { + tagFrom = undefined; + } + } + const currencyId = this.safeString (transaction, 'tokenId'); + const code = this.safeCurrencyCode (currencyId, currency); + const timestamp = this.safeInteger (transaction, 'time'); + let txid = this.safeString (transaction, 'txid'); + if (txid === '') { + txid = undefined; + } + let type = undefined; + let status = this.parseTransactionStatus (this.safeString (transaction, 'statusCode')); + if (status === undefined) { + type = 'deposit'; + status = 'ok'; + } else { + type = 'withdrawal'; + } + const amount = this.safeFloat (transaction, 'quantity'); + const feeCost = this.safeFloat (transaction, 'fee'); + let fee = undefined; + if (feeCost !== undefined) { + const feeCurrencyId = this.safeString (transaction, 'feeTokenId'); + const feeCurrencyCode = this.safeCurrencyCode (feeCurrencyId); + fee = { + 'currency': feeCurrencyCode, + 'cost': feeCost, + }; + } + return { + 'info': transaction, + 'id': id, + 'txid': txid, + 'timestamp': timestamp, + 'datetime': this.iso8601 (timestamp), + 'addressFrom': addressFrom, + 'address': address, + 'addressTo': address, + 'tagFrom': tagFrom, + 'tag': tag, + 'tagTo': tag, + 'type': type, + 'amount': amount, + 'currency': code, + 'status': status, + 'updated': undefined, + 'fee': fee, + }; + } + + parseTicker (ticker, market = undefined) { + // + // fetchTicker, fetchTickers + // + // { + // "time":1588069860794, + // "symbol":"BNB0501PS16", + // "bestBidPrice":"0.2129", + // "bestAskPrice":"0.3163", + // "volume":"33547", + // "quoteVolume":"10801.987", + // "lastPrice":"0.2625", + // "highPrice":"0.3918", + // "lowPrice":"0.2625", + // "openPrice":"0.362", + // } + // + // fetchBidAsk, fetchBidAsks + // + // { + // "symbol": "LTCBTC", + // "bidPrice": "4.00000000", + // "bidQty": "431.00000000", + // "askPrice": "4.00000200", + // "askQty": "9.00000000" + // } + // + 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 timestamp = this.safeInteger (ticker, 'time'); + const open = this.safeFloat (ticker, 'openPrice'); + const close = this.safeFloat (ticker, 'lastPrice'); + let change = undefined; + let percentage = undefined; + let average = undefined; + if ((open !== undefined) && (close !== undefined)) { + change = close - open; + average = this.sum (open, close) / 2; + if ((close !== undefined) && (close > 0)) { + percentage = (change / open) * 100; + } + } + const quoteVolume = this.safeFloat (ticker, 'quoteVolume'); + const baseVolume = this.safeFloat (ticker, 'volume'); + let vwap = undefined; + if (baseVolume !== undefined && quoteVolume !== undefined && baseVolume > 0) { + vwap = quoteVolume / baseVolume; + } + return { + 'symbol': symbol, + 'timestamp': timestamp, + 'datetime': this.iso8601 (timestamp), + 'high': this.safeFloat (ticker, 'highPrice'), + 'low': this.safeFloat (ticker, 'lowPrice'), + 'bid': this.safeFloat2 (ticker, 'bestBidPrice', 'bidPrice'), + 'bidVolume': this.safeFloat (ticker, 'bidQty'), + 'ask': this.safeFloat2 (ticker, 'bestAskPrice', 'askPrice'), + 'askVolume': this.safeFloat (ticker, 'askQty'), + 'vwap': vwap, + 'open': open, + 'close': close, + 'last': close, + 'previousClose': undefined, + 'change': change, + 'percentage': percentage, + 'average': average, + 'baseVolume': baseVolume, + 'quoteVolume': quoteVolume, + 'info': ticker, + }; + } + + parseTrade (trade, market) { + // + // fetchTrades (public) + // + // { + // "price":"0.025344", + // "time":1588084082060, + // "qty":"1", + // "isBuyerMaker":false + // } + // + // fetchMyTrades (private) + // + // spot + // + // { + // "id":"616384027512920576", + // "symbol":"TBTCBUSDT", + // "orderId":"616384027202542080", + // "matchOrderId":"605124954767266560", + // "price":"6826.06", + // "qty":"0.1", + // "commission":"0.682606", + // "commissionAsset":"BUSDT", + // "time":"1588214701982", + // "isBuyer":false, + // "isMaker":false, + // "fee":{ + // "feeTokenId":"BUSDT", + // "feeTokenName":"BUSDT", + // "fee":"0.682606" + // } + // } + // + const id = this.safeString (trade, 'id'); + const timestamp = this.safeFloat (trade, 'time'); + const type = undefined; + const orderId = this.safeString (trade, 'orderId'); + const price = this.safeFloat (trade, 'price'); + const amount = this.safeFloat (trade, 'qty'); + let cost = undefined; + if (price !== undefined) { + if (amount !== undefined) { + cost = price * amount; + } + } + let side = undefined; + let takerOrMaker = undefined; + if ('isBuyerMaker' in trade) { + side = trade['isBuyerMaker'] ? 'sell' : 'buy'; + } else { + const isMaker = this.safeValue (trade, 'isMaker'); + if (isMaker !== undefined) { + takerOrMaker = isMaker ? 'maker' : 'taker'; + } + const isBuyer = this.safeValue (trade, 'isBuyer'); + side = isBuyer ? 'buy' : 'sell'; + } + let fee = undefined; + const feeCost = this.safeFloat (trade, 'commission'); + if (feeCost !== undefined) { + const feeCurrencyId = this.safeString (trade, 'commissionAsset'); + const feeCurrencyCode = this.safeCurrencyCode (feeCurrencyId); + fee = { + 'cost': feeCost, + 'currency': feeCurrencyCode, + }; + } + let symbol = undefined; + if ((symbol === undefined) && (market !== undefined)) { + symbol = market['symbol']; + } + return { + 'id': id, + 'info': trade, + 'timestamp': timestamp, + 'datetime': this.iso8601 (timestamp), + 'symbol': symbol, + 'type': type, + 'order': orderId, + 'side': side, + 'takerOrMaker': takerOrMaker, + 'price': price, + 'amount': amount, + 'cost': cost, + 'fee': fee, + }; + } + + parseOrder (order, market = undefined) { + // + // createOrder + // + // { + // "symbol":"TBTCBUSDT", + // "orderId":"616376654496877056", + // "clientOrderId":"158821382304516955", + // "transactTime":"1588213823080", + // "price":"0", + // "origQty":"1000", + // "executedQty":"0", + // "status":"NEW", + // "timeInForce":"GTC", + // "type":"MARKET", + // "side":"BUY" + // } + // + // fetchOrder, fetchOpenOrders, fetchClosedOrders + // + // spot + // + // { + // "orderId":"616384027202542080", + // "clientOrderId":"158821470194414688", + // "exchangeId":"301", + // "symbol":"TBTCBUSDT", + // "price":"0", + // "origQty":"0.1", + // "executedQty":"0.1", + // "cummulativeQuoteQty":"682.606", + // "avgPrice":"6826.06", + // "status":"FILLED", + // "timeInForce":"GTC", + // "type":"MARKET", + // "side":"SELL", + // "stopPrice":"0.0", + // "icebergQty":"0.0", + // "time":"1588214701974", + // "updateTime":"0", + // "isWorking":true + // } + // + // future + // + // { + // time: "1588353669383", + // updateTime: "0", + // orderId: "617549770304599296", + // clientOrderId: "test-001", + // symbol: "BTC-PERP-REV", + // price: "10000", + // leverage: "1", + // origQty: "100", + // executedQty: "0", + // avgPrice: "0", + // marginLocked: "0", + // orderType: "LIMIT", + // side: "SELL_OPEN", + // fees: [], + // timeInForce: "GTC", + // status: "CANCELED", + // priceType: "INPUT" + // } + // + // + const id = this.safeString (order, 'orderId'); + const clientOrderId = this.safeString (order, 'clientOrderId'); + let timestamp = this.safeInteger (order, 'time'); + if (timestamp === undefined) { + timestamp = this.safeInteger (order, 'transactTime'); + } + let symbol = undefined; + if (market === undefined) { + let marketId = this.safeString (order, 'symbol'); + if (marketId !== undefined) { + marketId = marketId.toUpperCase (); + if (marketId in this.markets_by_id) { + market = this.markets_by_id[marketId]; + } + } + } + let type = this.safeStringLower (order, 'type'); + const side = this.safeStringLower (order, 'side'); + let price = this.safeFloat (order, 'price'); + let average = this.safeFloat (order, 'avgPrice'); + let amount = undefined; + let cost = this.safeFloat (order, 'cummulativeQuoteQty'); + let filled = undefined; + let remaining = undefined; + if (type === undefined) { + type = this.safeStringLower (order, 'orderType'); + if ((market !== undefined) && market['inverse']) { + cost = this.safeFloat (order, 'executedQty'); + amount = undefined; + } + if (cost === 0.0) { + filled = 0; + } + } else { + amount = this.safeFloat (order, 'origQty'); + if (type === 'market') { + price = undefined; + if (side === 'buy') { + amount = undefined; + } + } + filled = this.safeFloat (order, 'executedQty'); + if (filled !== undefined) { + if (amount !== undefined) { + remaining = amount - filled; + } + } + } + if (average === 0.0) { + average = undefined; + } + const status = this.parseOrderStatus (this.safeString (order, 'status')); + if (market !== undefined) { + symbol = market['symbol']; + } + const result = { + 'info': order, + 'id': id, + 'clientOrderId': clientOrderId, + 'timestamp': timestamp, + 'datetime': this.iso8601 (timestamp), + 'lastTradeTimestamp': undefined, + 'symbol': symbol, + 'type': type, + 'side': side, + 'price': price, + 'average': average, + 'cost': cost, + 'amount': amount, + 'filled': filled, + 'remaining': remaining, + 'status': status, + 'trades': undefined, + 'fee': undefined, + 'fees': undefined, + }; + const fees = this.safeValue (order, 'fees', []); + const numFees = fees.length; + if (numFees > 0) { + result['fees'] = []; + for (let i = 0; i < fees.length; i++) { + const feeCost = this.safeFloat (fees[i], 'fee'); + if (feeCost !== undefined) { + const feeCurrencyId = this.safeString (fees[i], 'feeToken'); + const feeCurrencyCode = this.safeCurrencyCode (feeCurrencyId); + result['fees'].push ({ + 'cost': feeCost, + 'currency': feeCurrencyCode, + }); + } + } + } + return result; + } + + parseOrderStatus (status) { + const statuses = { + 'NEW': 'open', + 'CANCELED': 'canceled', + 'FILLED': 'closed', + 'PENDING_CANCEL': 'canceled', + }; + return this.safeString (statuses, status, status); + } + + sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) { + let url = this.urls['api'][api] + '/' + this.version + '/' + this.implodeParams (path, params); + const query = this.omit (params, this.extractParams (path)); + const isPublicContract = (api === 'contract') && ((path === 'insurance') || (path === 'fundingRate')); + if ((api === 'public') || (api === 'quote') || isPublicContract) { + if (Object.keys (params).length) { + url += '?' + this.urlencode (params); + } + } else { + const timestamp = this.milliseconds (); + this.checkRequiredCredentials (); + const request = this.extend ({ + 'timestamp': timestamp, + }, query); + // 准备待签名数据 + const auth = this.urlencode (request); + const signature = this.hmac (this.encode (auth), this.encode (this.secret), 'sha256'); + request['signature'] = signature; + headers = { + 'X-BH-APIKEY': this.apiKey, + }; + if (method === 'POST') { + body = this.urlencode (request); + headers = this.extend ({ + 'Content-Type': 'application/x-www-form-urlencoded', + }, headers); + } else { + url += '?' + this.urlencode (request); + } + } + return { 'url': url, 'method': method, 'body': body, 'headers': headers }; + } + + handleErrors (httpCode, reason, url, method, headers, body, response, requestHeaders, requestBody) { + if (response === undefined) { + return; // fallback to default error handler + } + if ('code' in response) { + const code = this.safeString (response, 'code'); + if (code !== '0') { + const feedback = this.id + ' ' + body; + this.throwExactlyMatchedException (this.exceptions['exact'], code, feedback); + throw new ExchangeError (feedback); + } + } + } +}; + +},{"./base/Exchange":7,"./base/errors":9,"./base/functions/number":15}],90:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -58302,14 +60104,13 @@ module.exports = class hitbtc extends Exchange { } parseOHLCV (ohlcv, market = undefined, timeframe = '1d', since = undefined, limit = undefined) { - const timestamp = this.parse8601 (ohlcv['timestamp']); return [ - timestamp, - parseFloat (ohlcv['open']), - parseFloat (ohlcv['max']), - parseFloat (ohlcv['min']), - parseFloat (ohlcv['close']), - parseFloat (ohlcv['volume']), + this.parse8601 (this.safeString (ohlcv, 'timestamp')), + this.safeFloat (ohlcv, 'open'), + this.safeFloat (ohlcv, 'max'), + this.safeFloat (ohlcv, 'min'), + this.safeFloat (ohlcv, 'close'), + this.safeFloat (ohlcv, 'volume'), ]; } @@ -59098,26 +60899,7 @@ module.exports = class hitbtc extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10,"./base/functions/number":16}],91:[function(require,module,exports){ -'use strict'; - -// --------------------------------------------------------------------------- - -const hitbtc = require ('./hitbtc'); - -// --------------------------------------------------------------------------- - -module.exports = class hitbtc2 extends hitbtc { - describe () { - // this is a temporary stub for backward compatibility - // https://github.com/ccxt/ccxt/issues/6678 - return this.deepExtend (super.describe (), { - 'id': 'hitbtc2', - }); - } -}; - -},{"./hitbtc":90}],92:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9,"./base/functions/number":15}],91:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -60349,7 +62131,7 @@ module.exports = class hollaex extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10,"./base/functions/number":16}],93:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9,"./base/functions/number":15}],92:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -60515,12 +62297,14 @@ module.exports = class huobipro extends Exchange { 'exceptions': { 'exact': { // err-code + 'bad-request': BadRequest, 'api-not-support-temp-addr': PermissionDenied, // {"status":"error","err-code":"api-not-support-temp-addr","err-msg":"API withdrawal does not support temporary addresses","data":null} 'timeout': RequestTimeout, // {"ts":1571653730865,"status":"error","err-code":"timeout","err-msg":"Request Timeout"} 'gateway-internal-error': ExchangeNotAvailable, // {"status":"error","err-code":"gateway-internal-error","err-msg":"Failed to load data. Try again later.","data":null} 'account-frozen-balance-insufficient-error': InsufficientFunds, // {"status":"error","err-code":"account-frozen-balance-insufficient-error","err-msg":"trade account balance is not enough, left: `0.0027`","data":null} 'invalid-amount': InvalidOrder, // eg "Paramemter `amount` is invalid." 'order-limitorder-amount-min-error': InvalidOrder, // limit order amount error, min: `0.001` + 'order-limitorder-amount-max-error': InvalidOrder, // market order amount error, max: `1000000` 'order-marketorder-amount-min-error': InvalidOrder, // market order amount error, min: `0.01` 'order-limitorder-price-min-error': InvalidOrder, // limit order price error 'order-limitorder-price-max-error': InvalidOrder, // limit order price error @@ -60683,6 +62467,8 @@ module.exports = class huobipro extends Exchange { } parseTicker (ticker, market = undefined) { + // + // fetchTicker // // { // "amount": 26228.672978342216, @@ -60698,25 +62484,47 @@ module.exports = class huobipro extends Exchange { // "bid": [ 9146.86, 0.080758 ], // } // + // fetchTickers + // { + // symbol: "bhdht", + // open: 2.3938, + // high: 2.4151, + // low: 2.3323, + // close: 2.3909, + // amount: 628.992, + // vol: 1493.71841095, + // count: 2088, + // bid: 2.3643, + // bidSize: 0.7136, + // ask: 2.4061, + // askSize: 0.4156 + // } + // let symbol = undefined; if (market !== undefined) { symbol = market['symbol']; } const timestamp = this.safeInteger (ticker, 'ts'); let bid = undefined; - let ask = undefined; let bidVolume = undefined; + let ask = undefined; let askVolume = undefined; if ('bid' in ticker) { if (Array.isArray (ticker['bid'])) { bid = this.safeFloat (ticker['bid'], 0); bidVolume = this.safeFloat (ticker['bid'], 1); + } else { + bid = this.safeFloat (ticker, 'bid'); + bidVolume = this.safeValue (ticker, 'bidSize'); } } if ('ask' in ticker) { if (Array.isArray (ticker['ask'])) { ask = this.safeFloat (ticker['ask'], 0); askVolume = this.safeFloat (ticker['ask'], 1); + } else { + ask = this.safeFloat (ticker, 'ask'); + askVolume = this.safeValue (ticker, 'askSize'); } } const open = this.safeFloat (ticker, 'open'); @@ -61751,7 +63559,7 @@ module.exports = class huobipro extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10}],94:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9}],93:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -61785,13 +63593,13 @@ module.exports = class huobiru extends huobipro { } }; -},{"./huobipro.js":93}],95:[function(require,module,exports){ +},{"./huobipro.js":92}],94:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- const Exchange = require ('./base/Exchange'); -const { ExchangeError, AuthenticationError } = require ('./base/errors'); +const { ExchangeError, AuthenticationError, ArgumentsRequired } = require ('./base/errors'); // --------------------------------------------------------------------------- @@ -62009,7 +63817,7 @@ module.exports = class ice3x extends Exchange { const type = this.safeString (params, 'type'); if ((type !== 'ask') && (type !== 'bid')) { // eslint-disable-next-line quotes - throw new ExchangeError (this.id + " fetchOrderBook requires an exchange-specific extra 'type' param ('bid' or 'ask') when used with a limit"); + throw new ArgumentsRequired (this.id + " fetchOrderBook requires an exchange-specific extra 'type' param ('bid' or 'ask') when used with a limit"); } else { request['items_per_page'] = limit; } @@ -62269,7 +64077,7 @@ module.exports = class ice3x extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10}],96:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9}],95:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -63361,7 +65169,7 @@ module.exports = class idex extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10}],97:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9}],96:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -63795,7 +65603,7 @@ module.exports = class independentreserve extends Exchange { } }; -},{"./base/Exchange":8}],98:[function(require,module,exports){ +},{"./base/Exchange":7}],97:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -64160,7 +65968,7 @@ module.exports = class indodax extends Exchange { async fetchOrder (id, symbol = undefined, params = {}) { if (symbol === undefined) { - throw new ExchangeError (this.id + ' fetchOrder requires a symbol'); + throw new ArgumentsRequired (this.id + ' fetchOrder requires a symbol'); } await this.loadMarkets (); const market = this.market (symbol); @@ -64207,7 +66015,7 @@ module.exports = class indodax extends Exchange { async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) { if (symbol === undefined) { - throw new ExchangeError (this.id + ' fetchOrders requires a symbol'); + throw new ArgumentsRequired (this.id + ' fetchOrders requires a symbol argument'); } await this.loadMarkets (); const request = {}; @@ -64256,7 +66064,7 @@ module.exports = class indodax extends Exchange { } const side = this.safeValue (params, 'side'); if (side === undefined) { - throw new ExchangeError (this.id + ' cancelOrder requires an extra "side" param'); + throw new ArgumentsRequired (this.id + ' cancelOrder requires an extra "side" param'); } await this.loadMarkets (); const market = this.market (symbol); @@ -64362,13 +66170,13 @@ module.exports = class indodax extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10}],99:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9}],98:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- const Exchange = require ('./base/Exchange'); -const { ExchangeError, AuthenticationError } = require ('./base/errors'); +const { ExchangeError, AuthenticationError, ArgumentsRequired } = require ('./base/errors'); // --------------------------------------------------------------------------- @@ -64619,7 +66427,7 @@ module.exports = class itbit extends Exchange { await this.loadMarkets (); const walletId = this.safeString (params, 'walletId'); if (walletId === undefined) { - throw new ExchangeError (this.id + ' fetchMyTrades requires a walletId parameter'); + throw new ArgumentsRequired (this.id + ' fetchMyTrades requires a walletId parameter'); } const request = { 'walletId': walletId, @@ -64998,7 +66806,7 @@ module.exports = class itbit extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10}],100:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9}],99:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -65584,7 +67392,7 @@ module.exports = class kkex extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10}],101:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9}],100:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -65623,6 +67431,7 @@ module.exports = class kraken extends Exchange { 'withdraw': true, 'fetchLedgerEntry': true, 'fetchLedger': true, + 'fetchOrderTrades': 'emulated', }, 'marketsByAltname': {}, 'timeframes': { @@ -65641,7 +67450,7 @@ module.exports = class kraken extends Exchange { 'api': { 'public': 'https://api.kraken.com', 'private': 'https://api.kraken.com', - 'zendesk': 'https://support.kraken.com/hc/en-us/articles', + 'zendesk': 'https://kraken.zendesk.com/api/v2/help_center/en-us/articles', // use the public zendesk api to receive article bodies and bypass new anti-spam protections }, 'www': 'https://www.kraken.com', 'doc': 'https://www.kraken.com/features/api', @@ -65736,9 +67545,9 @@ module.exports = class kraken extends Exchange { 'get': [ // we should really refrain from putting fixed fee numbers and stop hardcoding // we will be using their web APIs to scrape all numbers from these articles - '205893708-What-is-the-minimum-order-size-', - '201396777-What-are-the-deposit-fees-', - '201893608-What-are-the-withdrawal-fees-', + '205893708', // -What-is-the-minimum-order-size- + '360000292886', // -What-are-the-deposit-fees- + '201893608', // -What-are-the-withdrawal-fees- ], }, 'public': { @@ -65821,12 +67630,14 @@ module.exports = class kraken extends Exchange { return this.decimalToPrecision (fee, TRUNCATE, this.markets[symbol]['precision']['amount'], DECIMAL_PLACES); } - async fetchMinOrderAmounts () { - const html = await this.zendeskGet205893708WhatIsTheMinimumOrderSize (); + async fetchMinOrderAmounts (params = {}) { + const response = await this.zendeskGet205893708 (params); + const article = this.safeValue (response, 'article'); + const html = this.safeString (article, 'body'); const parts = html.split (''); const numParts = parts.length; if (numParts < 3) { - throw new NotSupported (this.id + ' fetchMinOrderAmounts HTML page markup has changed: https://support.kraken.com/hc/en-us/articles/205893708-What-is-the-minimum-order-size-'); + throw new NotSupported (this.id + ' fetchMinOrderAmounts HTML page markup has changed: https://kraken.zendesk.com/api/v2/help_center/en-us/articles/205893708'); } const result = {}; // skip the part before the header and the header itself @@ -65849,6 +67660,52 @@ module.exports = class kraken extends Exchange { async fetchMarkets (params = {}) { const response = await this.publicGetAssetPairs (params); + // + // { + // "error":[], + // "result":{ + // "ADAETH":{ + // "altname":"ADAETH", + // "wsname":"ADA\/ETH", + // "aclass_base":"currency", + // "base":"ADA", + // "aclass_quote":"currency", + // "quote":"XETH", + // "lot":"unit", + // "pair_decimals":7, + // "lot_decimals":8, + // "lot_multiplier":1, + // "leverage_buy":[], + // "leverage_sell":[], + // "fees":[ + // [0,0.26], + // [50000,0.24], + // [100000,0.22], + // [250000,0.2], + // [500000,0.18], + // [1000000,0.16], + // [2500000,0.14], + // [5000000,0.12], + // [10000000,0.1] + // ], + // "fees_maker":[ + // [0,0.16], + // [50000,0.14], + // [100000,0.12], + // [250000,0.1], + // [500000,0.08], + // [1000000,0.06], + // [2500000,0.04], + // [5000000,0.02], + // [10000000,0] + // ], + // "fee_volume_currency":"ZUSD", + // "margin_call":80, + // "margin_stop":40 + // }, + // } + // } + // const fetchMinOrderAmounts = this.safeValue (this.options, 'fetchMinOrderAmounts', false); let limits = {}; if (fetchMinOrderAmounts) { @@ -66028,6 +67885,13 @@ module.exports = class kraken extends Exchange { }; } + parseBidAsk (bidask, priceKey = 0, amountKey = 1) { + const price = this.safeFloat (bidask, priceKey); + const amount = this.safeFloat (bidask, amountKey); + const timestamp = this.safeInteger (bidask, 2); + return [ price, amount, timestamp ]; + } + async fetchOrderBook (symbol, limit = undefined, params = {}) { await this.loadMarkets (); const market = this.market (symbol); @@ -66041,7 +67905,27 @@ module.exports = class kraken extends Exchange { request['count'] = limit; // 100 } const response = await this.publicGetDepth (this.extend (request, params)); - const orderbook = response['result'][market['id']]; + // + // { + // "error":[], + // "result":{ + // "XETHXXBT":{ + // "asks":[ + // ["0.023480","4.000",1586321307], + // ["0.023490","50.095",1586321306], + // ["0.023500","28.535",1586321302], + // ], + // "bids":[ + // ["0.023470","59.580",1586321307], + // ["0.023460","20.000",1586321301], + // ["0.023440","67.832",1586321306], + // ] + // } + // } + // } + // + const result = this.safeValue (response, 'result', {}); + const orderbook = this.safeValue (result, market['id']); return this.parseOrderBook (orderbook); } @@ -66295,26 +68179,46 @@ module.exports = class kraken extends Exchange { } parseTrade (trade, market = undefined) { + // + // fetchTrades (public) + // + // [ + // "0.032310", // price + // "4.28169434", // amount + // 1541390792.763, // timestamp + // "s", // sell or buy + // "l", // limit or market + // "" + // ] + // + // fetchOrderTrades (private) + // + // { + // id: 'TIMIRG-WUNNE-RRJ6GT', // injected from outside + // ordertxid: 'OQRPN2-LRHFY-HIFA7D', + // postxid: 'TKH2SE-M7IF5-CFI7LT', + // pair: 'USDCUSDT', + // time: 1586340086.457, + // type: 'sell', + // ordertype: 'market', + // price: '0.99860000', + // cost: '22.16892001', + // fee: '0.04433784', + // vol: '22.20000000', + // margin: '0.00000000', + // misc: '' + // } + // let timestamp = undefined; let side = undefined; let type = undefined; let price = undefined; let amount = undefined; + let cost = undefined; let id = undefined; let order = undefined; let fee = undefined; - const marketId = this.safeString (trade, 'pair'); - const foundMarket = this.findMarketByAltnameOrId (marketId); let symbol = undefined; - if (foundMarket !== undefined) { - market = foundMarket; - } else if (marketId !== undefined) { - // delisted market ids go here - market = this.getDelistedMarketById (marketId); - } - if (market !== undefined) { - symbol = market['symbol']; - } if (Array.isArray (trade)) { timestamp = this.safeTimestamp (trade, 2); side = (trade[3] === 's') ? 'sell' : 'buy'; @@ -66325,17 +68229,27 @@ module.exports = class kraken extends Exchange { if (tradeLength > 6) { id = this.safeString (trade, 6); // artificially added as per #1794 } + } else if (typeof trade === 'string') { + id = trade; } else if ('ordertxid' in trade) { + const marketId = this.safeString (trade, 'pair'); + const foundMarket = this.findMarketByAltnameOrId (marketId); + if (foundMarket !== undefined) { + market = foundMarket; + } else if (marketId !== undefined) { + // delisted market ids go here + market = this.getDelistedMarketById (marketId); + } order = trade['ordertxid']; id = this.safeString2 (trade, 'id', 'postxid'); timestamp = this.safeTimestamp (trade, 'time'); - side = trade['type']; - type = trade['ordertype']; + side = this.safeString (trade, 'type'); + type = this.safeString (trade, 'ordertype'); price = this.safeFloat (trade, 'price'); amount = this.safeFloat (trade, 'vol'); if ('fee' in trade) { let currency = undefined; - if (market) { + if (market !== undefined) { currency = market['quote']; } fee = { @@ -66344,6 +68258,14 @@ module.exports = class kraken extends Exchange { }; } } + if (market !== undefined) { + symbol = market['symbol']; + } + if (price !== undefined) { + if (amount !== undefined) { + cost = price * amount; + } + } return { 'id': id, 'order': order, @@ -66356,7 +68278,7 @@ module.exports = class kraken extends Exchange { 'takerOrMaker': undefined, 'price': price, 'amount': amount, - 'cost': price * amount, + 'cost': cost, 'fee': fee, }; } @@ -66573,6 +68495,11 @@ module.exports = class kraken extends Exchange { const status = this.parseOrderStatus (this.safeString (order, 'status')); const id = this.safeString (order, 'id'); const clientOrderId = this.safeString (order, 'userref'); + const rawTrades = this.safeValue (order, 'trades'); + let trades = undefined; + if (rawTrades !== undefined) { + trades = this.parseTrades (rawTrades, market, undefined, undefined, { 'order': id }); + } return { 'id': id, 'clientOrderId': clientOrderId, @@ -66591,8 +68518,7 @@ module.exports = class kraken extends Exchange { 'average': average, 'remaining': remaining, 'fee': fee, - // 'trades': this.parseTrades (order['trades'], market), - 'trades': undefined, + 'trades': trades, }; } @@ -66613,16 +68539,129 @@ module.exports = class kraken extends Exchange { async fetchOrder (id, symbol = undefined, params = {}) { await this.loadMarkets (); - const response = await this.privatePostQueryOrders (this.extend ({ + const clientOrderId = this.safeValue2 (params, 'userref', 'clientOrderId'); + const request = { 'trades': true, // whether or not to include trades in output (optional, default false) - 'txid': id, // do not comma separate a list of ids - use fetchOrdersByIds instead + // 'txid': id, // do not comma separate a list of ids - use fetchOrdersByIds instead // 'userref': 'optional', // restrict results to given user reference id (optional) - }, params)); - const orders = response['result']; + }; + let query = params; + if (clientOrderId !== undefined) { + request['userref'] = clientOrderId; + query = this.omit (params, [ 'userref', 'clientOrderId' ]); + } else { + request['txid'] = id; + } + const response = await this.privatePostQueryOrders (this.extend (request, query)); + // + // { + // "error":[], + // "result":{ + // "OTLAS3-RRHUF-NDWH5A":{ + // "refid":null, + // "userref":null, + // "status":"closed", + // "reason":null, + // "opentm":1586822919.3342, + // "closetm":1586822919.365, + // "starttm":0, + // "expiretm":0, + // "descr":{ + // "pair":"XBTUSDT", + // "type":"sell", + // "ordertype":"market", + // "price":"0", + // "price2":"0", + // "leverage":"none", + // "order":"sell 0.21804000 XBTUSDT @ market", + // "close":"" + // }, + // "vol":"0.21804000", + // "vol_exec":"0.21804000", + // "cost":"1493.9", + // "fee":"3.8", + // "price":"6851.5", + // "stopprice":"0.00000", + // "limitprice":"0.00000", + // "misc":"", + // "oflags":"fciq", + // "trades":["TT5UC3-GOIRW-6AZZ6R"] + // } + // } + // } + // + const orders = this.safeValue (response, 'result', []); const order = this.parseOrder (this.extend ({ 'id': id }, orders[id])); return this.extend ({ 'info': response }, order); } + async fetchOrderTrades (id, symbol = undefined, since = undefined, limit = undefined, params = {}) { + const orderTrades = this.safeValue (params, 'trades'); + const tradeIds = []; + if (orderTrades === undefined) { + throw new ArgumentsRequired (this.id + " fetchOrderTrades requires a unified order structure in the params argument or a 'trades' param (an array of trade id strings)"); + } else { + for (let i = 0; i < orderTrades.length; i++) { + const orderTrade = orderTrades[i]; + if (typeof orderTrade === 'string') { + tradeIds.push (orderTrade); + } else { + tradeIds.push (orderTrade['id']); + } + } + } + await this.loadMarkets (); + const options = this.safeValue (this.options, 'fetchOrderTrades', {}); + const batchSize = this.safeInteger (options, 'batchSize', 20); + let numBatches = parseInt (tradeIds / batchSize); + numBatches = this.sum (numBatches, 1); + const numTradeIds = tradeIds.length; + let result = []; + for (let j = 0; j < numBatches; j++) { + const requestIds = []; + for (let k = 0; k < batchSize; k++) { + const index = this.sum (j * batchSize, k); + if (index < numTradeIds) { + requestIds.push (tradeIds[index]); + } + } + const request = { + 'txid': requestIds.join (','), + }; + const response = await this.privatePostQueryTrades (request); + // + // { + // error: [], + // result: { + // 'TIMIRG-WUNNE-RRJ6GT': { + // ordertxid: 'OQRPN2-LRHFY-HIFA7D', + // postxid: 'TKH2SE-M7IF5-CFI7LT', + // pair: 'USDCUSDT', + // time: 1586340086.457, + // type: 'sell', + // ordertype: 'market', + // price: '0.99860000', + // cost: '22.16892001', + // fee: '0.04433784', + // vol: '22.20000000', + // margin: '0.00000000', + // misc: '' + // } + // } + // } + // + const rawTrades = this.safeValue (response, 'result'); + const ids = Object.keys (rawTrades); + for (let i = 0; i < ids.length; i++) { + rawTrades[ids[i]]['id'] = ids[i]; + } + const trades = this.parseTrades (rawTrades, undefined, since, limit); + const tradesFilteredBySymbol = this.filterBySymbol (trades, symbol); + result = this.arrayConcat (result, tradesFilteredBySymbol); + } + return result; + } + async fetchOrdersByIds (ids, symbol = undefined, params = {}) { await this.loadMarkets (); const response = await this.privatePostQueryOrders (this.extend ({ @@ -66835,11 +68874,11 @@ module.exports = class kraken extends Exchange { } async fetchDeposits (code = undefined, since = undefined, limit = undefined, params = {}) { - await this.loadMarkets (); // https://www.kraken.com/en-us/help/api#deposit-status if (code === undefined) { throw new ArgumentsRequired (this.id + ' fetchDeposits requires a currency code argument'); } + await this.loadMarkets (); const currency = this.currency (code); const request = { 'asset': currency['id'], @@ -66862,11 +68901,11 @@ module.exports = class kraken extends Exchange { } async fetchWithdrawals (code = undefined, since = undefined, limit = undefined, params = {}) { - await this.loadMarkets (); // https://www.kraken.com/en-us/help/api#withdraw-status if (code === undefined) { throw new ArgumentsRequired (this.id + ' fetchWithdrawals requires a currency code argument'); } + await this.loadMarkets (); const currency = this.currency (code); const request = { 'asset': currency['id'], @@ -66915,7 +68954,7 @@ module.exports = class kraken extends Exchange { } method = this.options['depositMethods'][code][0]['method']; } else { - throw new ExchangeError (this.id + ' fetchDepositAddress() requires an extra `method` parameter. Use fetchDepositMethods ("' + code + '") to get a list of available deposit methods or enable the exchange property .options["cacheDepositMethodsOnFetchDepositAddress"] = true'); + throw new ArgumentsRequired (this.id + ' fetchDepositAddress() requires an extra `method` parameter. Use fetchDepositMethods ("' + code + '") to get a list of available deposit methods or enable the exchange property .options["cacheDepositMethodsOnFetchDepositAddress"] = true'); } } const request = { @@ -67028,7 +69067,7 @@ module.exports = class kraken extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10,"./base/functions/number":16}],102:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9,"./base/functions/number":15}],101:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -67100,7 +69139,9 @@ module.exports = class kucoin extends Exchange { 'public': { 'get': [ 'timestamp', + 'status', 'symbols', + 'markets', 'market/allTickers', 'market/orderbook/level{level}', 'market/orderbook/level2', @@ -67112,6 +69153,9 @@ module.exports = class kucoin extends Exchange { 'market/stats', 'currencies', 'currencies/{currency}', + 'prices', + 'mark-price/{symbol}/current', + 'margin/config', ], 'post': [ 'bullet-public', @@ -67123,6 +69167,10 @@ module.exports = class kucoin extends Exchange { 'accounts/{accountId}', 'accounts/{accountId}/ledgers', 'accounts/{accountId}/holds', + 'accounts/transferable', + 'sub/user', + 'sub-accounts', + 'sub-accounts/{subUserId}', 'deposit-addresses', 'deposits', 'hist-deposits', @@ -67132,8 +69180,20 @@ module.exports = class kucoin extends Exchange { 'withdrawals/quotas', 'orders', 'orders/{orderId}', + 'limit/orders', 'fills', 'limit/fills', + 'margin/account', + 'margin/borrow', + 'margin/borrow/outstanding', + 'margin/borrow/borrow/repaid', + 'margin/lend/active', + 'margin/lend/done', + 'margin/lend/trade/unsettled', + 'margin/lend/trade/settled', + 'margin/lend/assets', + 'margin/market', + 'margin/margin/trade/last', ], 'post': [ 'accounts', @@ -67142,11 +69202,19 @@ module.exports = class kucoin extends Exchange { 'deposit-addresses', 'withdrawals', 'orders', + 'orders/multi', + 'margin/borrow', + 'margin/repay/all', + 'margin/repay/single', + 'margin/lend', + 'margin/toggle-auto-lend', 'bullet-private', ], 'delete': [ 'withdrawals/{withdrawalId}', + 'orders', 'orders/{orderId}', + 'margin/lend/{orderId}', ], }, }, @@ -67278,18 +69346,20 @@ module.exports = class kucoin extends Exchange { async fetchMarkets (params = {}) { const response = await this.publicGetSymbols (params); // - // { quoteCurrency: 'BTC', - // symbol: 'KCS-BTC', - // quoteMaxSize: '9999999', - // quoteIncrement: '0.000001', - // baseMinSize: '0.01', - // quoteMinSize: '0.00001', - // enableTrading: true, - // priceIncrement: '0.00000001', - // name: 'KCS-BTC', - // baseIncrement: '0.01', - // baseMaxSize: '9999999', - // baseCurrency: 'KCS' } + // { + // quoteCurrency: 'BTC', + // symbol: 'KCS-BTC', + // quoteMaxSize: '9999999', + // quoteIncrement: '0.000001', + // baseMinSize: '0.01', + // quoteMinSize: '0.00001', + // enableTrading: true, + // priceIncrement: '0.00000001', + // name: 'KCS-BTC', + // baseIncrement: '0.01', + // baseMaxSize: '9999999', + // baseCurrency: 'KCS' + // } // const data = response['data']; const result = []; @@ -67375,20 +69445,27 @@ module.exports = class kucoin extends Exchange { async fetchAccounts (params = {}) { const response = await this.privateGetAccounts (params); // - // { code: "200000", - // data: [ { balance: "0.00009788", + // { + // code: "200000", + // data: [ + // { + // balance: "0.00009788", // available: "0.00009788", - // holds: "0", - // currency: "BTC", - // id: "5c6a4fd399a1d81c4f9cc4d0", - // type: "trade" }, - // ..., - // { balance: "0.00000001", + // holds: "0", + // currency: "BTC", + // id: "5c6a4fd399a1d81c4f9cc4d0", + // type: "trade" + // }, + // { + // balance: "0.00000001", // available: "0.00000001", - // holds: "0", - // currency: "ETH", - // id: "5c6a49ec99a1d819392e8e9f", - // type: "trade" } ] } + // holds: "0", + // currency: "ETH", + // id: "5c6a49ec99a1d819392e8e9f", + // type: "trade" + // } + // ] + // } // const data = this.safeValue (response, 'data'); const result = []; @@ -67672,30 +69749,72 @@ module.exports = class kucoin extends Exchange { }; } + async fetchL3OrderBook (symbol, limit = undefined, params = {}) { + return await this.fetchOrderBook (symbol, limit, { 'level': 3 }); + } + async fetchOrderBook (symbol, limit = undefined, params = {}) { - let level = '2'; - if (limit !== undefined) { - if ((limit !== 20) && (limit !== 100)) { - throw new ExchangeError (this.id + ' fetchOrderBook limit argument must be undefined, 20 or 100'); + const level = this.safeInteger (params, 'level', 2); + let levelLimit = level.toString (); + if (level === '2') { + if (limit !== undefined) { + if ((limit !== 20) && (limit !== 100)) { + throw new ExchangeError (this.id + ' fetchOrderBook limit argument must be undefined, 20 or 100'); + } + levelLimit += '_' + limit.toString (); } - level += '_' + limit.toString (); } await this.loadMarkets (); const marketId = this.marketId (symbol); - const request = this.extend ({ 'symbol': marketId, 'level': level }, params); - const response = await this.publicGetMarketOrderbookLevelLevel (request); + const request = { 'symbol': marketId, 'level': levelLimit }; + const response = await this.publicGetMarketOrderbookLevelLevel (this.extend (request, params)); // - // { sequence: '1547731421688', - // asks: [ [ '5c419328ef83c75456bd615c', '0.9', '0.09' ], ... ], - // bids: [ [ '5c419328ef83c75456bd615c', '0.9', '0.09' ], ... ], } + // 'market/orderbook/level2' + // 'market/orderbook/level2_20' + // 'market/orderbook/level2_100' // - const data = response['data']; + // { + // "code":"200000", + // "data":{ + // "sequence":"1583235112106", + // "asks":[ + // // ... + // ["0.023197","12.5067468"], + // ["0.023194","1.8"], + // ["0.023191","8.1069672"] + // ], + // "bids":[ + // ["0.02319","1.6000002"], + // ["0.023189","2.2842325"], + // ], + // "time":1586584067274 + // } + // } + // + // 'market/orderbook/level3' + // + // { + // "code":"200000", + // "data":{ + // "sequence":"1583731857120", + // "asks":[ + // // id, price, size, timestamp in nanoseconds + // ["5e915f8acd26670009675300","6925.7","0.2","1586585482194286069"], + // ["5e915f8ace35a200090bba48","6925.7","0.001","1586585482229569826"], + // ["5e915f8a8857740009ca7d33","6926","0.00001819","1586585482149148621"], + // ], + // "bids":[ + // ["5e915f8acca406000ac88194","6925.6","0.05","1586585482384384842"], + // ["5e915f93cd26670009676075","6925.6","0.08","1586585491334914600"], + // ["5e915f906aa6e200099b49f6","6925.4","0.2","1586585488941126340"], + // ], + // "time":1586585492487 + // } + // } + // + const data = this.safeValue (response, 'data', {}); const timestamp = this.safeInteger (data, 'time'); - // level can be a string such as 2_20 or 2_100 - const levelString = this.safeString (request, 'level'); - const levelParts = levelString.split ('_'); - const offset = parseInt (levelParts[0]); - const orderbook = this.parseOrderBook (data, timestamp, 'bids', 'asks', offset - 2, offset - 1); + const orderbook = this.parseOrderBook (data, timestamp, 'bids', 'asks', level - 2, level - 1); orderbook['nonce'] = this.safeInteger (data, 'sequence'); return orderbook; } @@ -67746,7 +69865,7 @@ module.exports = class kucoin extends Exchange { 'datetime': this.iso8601 (timestamp), 'fee': undefined, 'status': 'open', - 'clientOid': clientOid, + 'clientOrderId': clientOid, 'info': data, }; if (!this.safeValue (params, 'quoteAmount')) { @@ -68729,7 +70848,7 @@ module.exports = class kucoin extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10}],103:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9}],102:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -68750,11 +70869,12 @@ module.exports = class kuna extends acx { 'has': { 'CORS': false, 'fetchTickers': true, - 'fetchOHLCV': false, + 'fetchOHLCV': 'emulated', 'fetchOpenOrders': true, 'fetchMyTrades': true, 'withdraw': false, }, + 'timeframes': undefined, 'urls': { 'referral': 'https://kuna.io?r=kunaid-gvfihe8az7o4', 'logo': 'https://user-images.githubusercontent.com/1294454/31697638-912824fa-b3c1-11e7-8c36-cf9606eb94ac.jpg', @@ -68923,15 +71043,34 @@ module.exports = class kuna extends acx { const response = await this.privateGetTradesMy (this.extend (request, params)); return this.parseTrades (response, market, since, limit); } + + async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limits = undefined, params = {}) { + await this.loadMarkets (); + const trades = await this.fetchTrades (symbol, since, limits, params); + const ohlcvc = this.buildOHLCVC (trades, timeframe, since, limits); + const result = []; + for (let i = 0; i < ohlcvc.length; i++) { + const ohlcv = ohlcvc[i]; + result.push ([ + ohlcv[0], + ohlcv[1], + ohlcv[2], + ohlcv[3], + ohlcv[4], + ohlcv[5], + ]); + } + return result; + } }; -},{"./acx.js":4,"./base/errors":10}],104:[function(require,module,exports){ +},{"./acx.js":4,"./base/errors":9}],103:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- const Exchange = require ('./base/Exchange'); -const { ExchangeError } = require ('./base/errors'); +const { ExchangeError, AuthenticationError, BadSymbol, InvalidOrder, InsufficientFunds } = require ('./base/errors'); // --------------------------------------------------------------------------- @@ -68942,6 +71081,7 @@ module.exports = class lakebtc extends Exchange { 'name': 'LakeBTC', 'countries': [ 'US' ], 'version': 'api_v2', + 'rateLimit': 1000, 'has': { 'CORS': true, 'createMarketOrder': false, @@ -68983,6 +71123,14 @@ module.exports = class lakebtc extends Exchange { 'taker': 0.2 / 100, }, }, + 'exceptions': { + 'broad': { + 'Signature': AuthenticationError, + 'invalid symbol': BadSymbol, + 'Volume doit': InvalidOrder, + 'insufficient_balance': InsufficientFunds, + }, + }, }); } @@ -69176,45 +71324,73 @@ module.exports = class lakebtc extends Exchange { } else { this.checkRequiredCredentials (); const nonce = this.nonce (); + const nonceAsString = nonce.toString (); + const requestId = this.seconds (); let queryParams = ''; if ('params' in params) { const paramsList = params['params']; - queryParams = paramsList.join (','); + const stringParams = []; + for (let i = 0; i < paramsList.length; i++) { + let param = paramsList[i]; + if (typeof paramsList !== 'string') { + param = param.toString (); + } + stringParams.push (param); + } + queryParams = stringParams.join (','); + body = { + 'method': path, + 'params': params['params'], + 'id': requestId, + }; + } else { + body = { + 'method': path, + 'params': '', + 'id': requestId, + }; } - const query = this.urlencode ({ - 'tonce': nonce, - 'accesskey': this.apiKey, - 'requestmethod': method.toLowerCase (), - 'id': nonce, - 'method': path, - 'params': queryParams, - }); - body = this.json ({ - 'method': path, - 'params': queryParams, - 'id': nonce, - }); + body = this.json (body); + let query = [ + 'tonce=' + nonceAsString, + 'accesskey=' + this.apiKey, + 'requestmethod=' + method.toLowerCase (), + 'id=' + requestId.toString (), + 'method=' + path, + 'params=' + queryParams, + ]; + query = query.join ('&'); const signature = this.hmac (this.encode (query), this.encode (this.secret), 'sha1'); const auth = this.encode (this.apiKey + ':' + signature); + const signature64 = this.decode (this.stringToBase64 (auth)); headers = { - 'Json-Rpc-Tonce': nonce.toString (), - 'Authorization': 'Basic ' + this.decode (this.stringToBase64 (auth)), + 'Json-Rpc-Tonce': nonceAsString, + 'Authorization': 'Basic ' + signature64, 'Content-Type': 'application/json', }; } return { 'url': url, 'method': method, 'body': body, 'headers': headers }; } - async request (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) { - const response = await this.fetch2 (path, api, method, params, headers, body); - if ('error' in response) { - throw new ExchangeError (this.id + ' ' + this.json (response)); + handleErrors (code, reason, url, method, headers, body, response, requestHeaders, requestBody) { + if (response === undefined) { + return; // fallback to the default error handler + } + // + // {"error":"Failed to submit order: invalid symbol"} + // {"error":"Failed to submit order: La validation a échoué : Volume doit être supérieur ou égal à 1.0"} + // {"error":"Failed to submit order: insufficient_balance"} + // + const feedback = this.id + ' ' + body; + const error = this.safeString (response, 'error'); + if (error !== undefined) { + this.throwBroadlyMatchedException (this.exceptions['broad'], error, feedback); + throw new ExchangeError (feedback); // unknown message } - return response; } }; -},{"./base/Exchange":8,"./base/errors":10}],105:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9}],104:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -70115,13 +72291,13 @@ module.exports = class latoken extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10,"./base/functions/number":16}],106:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9,"./base/functions/number":15}],105:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- const Exchange = require ('./base/Exchange'); -const { ExchangeError, DDoSProtection, AuthenticationError, InvalidOrder } = require ('./base/errors'); +const { ExchangeError, DDoSProtection, AuthenticationError, InvalidOrder, ArgumentsRequired } = require ('./base/errors'); // --------------------------------------------------------------------------- @@ -70457,10 +72633,10 @@ module.exports = class lbank extends Exchange { await this.loadMarkets (); const market = this.market (symbol); if (since === undefined) { - throw new ExchangeError (this.id + ' fetchOHLCV requires a `since` argument'); + throw new ArgumentsRequired (this.id + ' fetchOHLCV requires a `since` argument'); } if (limit === undefined) { - throw new ExchangeError (this.id + ' fetchOHLCV requires a `limit` argument'); + throw new ArgumentsRequired (this.id + ' fetchOHLCV requires a `limit` argument'); } const request = { 'symbol': market['id'], @@ -70788,7 +72964,7 @@ module.exports = class lbank extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10}],107:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9}],106:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -70968,7 +73144,7 @@ module.exports = class liquid extends Exchange { } async fetchMarkets (params = {}) { - const markets = await this.publicGetProducts (); + const spot = await this.publicGetProducts (params); // // [ // { @@ -70999,20 +73175,69 @@ module.exports = class liquid extends Exchange { // }, // ] // + const perpetual = await this.publicGetProducts ({ 'perpetual': '1' }); + // + // [ + // { + // "id": "603", + // "product_type": "Perpetual", + // "code": "CASH", + // "name": null, + // "market_ask": "1143900", + // "market_bid": "1143250", + // "currency": "JPY", + // "currency_pair_code": "P-BTCJPY", + // "pusher_channel": "product_cash_p-btcjpy_603", + // "taker_fee": "0.0", + // "maker_fee": "0.0", + // "low_market_bid": "1124450.0", + // "high_market_ask": "1151750.0", + // "volume_24h": "0.1756", + // "last_price_24h": "1129850.0", + // "last_traded_price": "1144700.0", + // "last_traded_quantity": "0.014", + // "quoted_currency": "JPY", + // "base_currency": "P-BTC", + // "tick_size": "50.0", + // "perpetual_enabled": true, + // "index_price": "1142636.03935", + // "mark_price": "1143522.18417", + // "funding_rate": "0.00033", + // "fair_price": "1143609.31009", + // "timestamp": "1581558659.195353100", + // }, + // ] + // const currencies = await this.fetchCurrencies (); const currenciesByCode = this.indexBy (currencies, 'code'); const result = []; + const markets = this.arrayConcat (spot, perpetual); for (let i = 0; i < markets.length; i++) { const market = markets[i]; - const id = market['id'].toString (); - const baseId = market['base_currency']; - const quoteId = market['quoted_currency']; + const id = this.safeString (market, 'id'); + const baseId = this.safeString (market, 'base_currency'); + const quoteId = this.safeString (market, 'quoted_currency'); + const productType = this.safeString (market, 'product_type'); + let type = 'spot'; + let spot = true; + let swap = false; + if (productType === 'Perpetual') { + spot = false; + swap = true; + type = 'swap'; + } const base = this.safeCurrencyCode (baseId); const quote = this.safeCurrencyCode (quoteId); - const symbol = base + '/' + quote; + let symbol = undefined; + if (swap) { + symbol = this.safeString (market, 'currency_pair_code'); + } else { + symbol = base + '/' + quote; + } const maker = this.safeFloat (market, 'maker_fee'); const taker = this.safeFloat (market, 'taker_fee'); - const active = !market['disabled']; + const disabled = this.safeValue (market, 'disabled', false); + const active = !disabled; const baseCurrency = this.safeValue (currenciesByCode, base); const quoteCurrency = this.safeValue (currenciesByCode, quote); const precision = { @@ -71056,6 +73281,9 @@ module.exports = class liquid extends Exchange { 'quote': quote, 'baseId': baseId, 'quoteId': quoteId, + 'type': type, + 'spot': spot, + 'swap': swap, 'maker': maker, 'taker': taker, 'limits': limits, @@ -71184,7 +73412,7 @@ module.exports = class liquid extends Exchange { return this.parseTicker (response, market); } - parseTrade (trade, market) { + parseTrade (trade, market = undefined) { // { id: 12345, // quantity: "6.789", // price: "98765.4321", @@ -71211,13 +73439,17 @@ module.exports = class liquid extends Exchange { } } const id = this.safeString (trade, 'id'); + let symbol = undefined; + if (market !== undefined) { + symbol = market['symbol']; + } return { 'info': trade, 'id': id, 'order': orderId, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), - 'symbol': market['symbol'], + 'symbol': symbol, 'type': undefined, 'side': side, 'takerOrMaker': takerOrMaker, @@ -71720,7 +73952,7 @@ module.exports = class liquid extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10}],108:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9}],107:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -72162,7 +74394,18 @@ module.exports = class livecoin extends Exchange { } } let symbol = undefined; - if (market !== undefined) { + const marketId = this.safeString (trade, 'symbol'); + if (marketId !== undefined) { + if (marketId in this.markets_by_id) { + market = this.markets_by_id[marketId]; + } else { + const [ baseId, quoteId ] = marketId.split ('/'); + const base = this.safeCurrencyCode (baseId); + const quote = this.safeCurrencyCode (quoteId); + symbol = base + '/' + quote; + } + } + if ((symbol === undefined) && (market !== undefined)) { symbol = market['symbol']; } return { @@ -72183,16 +74426,17 @@ module.exports = class livecoin extends Exchange { } async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) { - if (symbol === undefined) { - throw new ArgumentsRequired (this.id + ' fetchMyTrades requires a symbol argument'); - } await this.loadMarkets (); - const market = this.market (symbol); const request = { - 'currencyPair': market['id'], - // orderDesc': 'true', // or 'false', if true then new orders will be first, otherwise old orders will be first. + // 'currencyPair': market['id'], + // 'orderDesc': 'true', // or 'false', if true then new orders will be first, otherwise old orders will be first. // 'offset': 0, // page offset, position of the first item on the page }; + let market = undefined; + if (symbol !== undefined) { + market = this.market (symbol); + request['currencyPair'] = market['id']; + } if (limit !== undefined) { request['limit'] = limit; } @@ -72638,7 +74882,7 @@ module.exports = class livecoin extends Exchange { }; -},{"./base/Exchange":8,"./base/errors":10,"./base/functions/number":16}],109:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9,"./base/functions/number":15}],108:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -73117,7 +75361,7 @@ module.exports = class luno extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10}],110:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9}],109:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -73598,7 +75842,7 @@ module.exports = class lykke extends Exchange { } }; -},{"./base/Exchange":8}],111:[function(require,module,exports){ +},{"./base/Exchange":7}],110:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -74000,17 +76244,17 @@ module.exports = class mercado extends Exchange { if (code === 'BRL') { const account_ref = ('account_ref' in params); if (!account_ref) { - throw new ExchangeError (this.id + ' requires account_ref parameter to withdraw ' + code); + throw new ArgumentsRequired (this.id + ' requires account_ref parameter to withdraw ' + code); } } else if (code !== 'LTC') { const tx_fee = ('tx_fee' in params); if (!tx_fee) { - throw new ExchangeError (this.id + ' requires tx_fee parameter to withdraw ' + code); + throw new ArgumentsRequired (this.id + ' requires tx_fee parameter to withdraw ' + code); } if (code === 'XRP') { if (tag === undefined) { if (!('destination_tag' in params)) { - throw new ExchangeError (this.id + ' requires a tag argument or destination_tag parameter to withdraw ' + code); + throw new ArgumentsRequired (this.id + ' requires a tag argument or destination_tag parameter to withdraw ' + code); } } else { request['destination_tag'] = tag; @@ -74107,7 +76351,7 @@ module.exports = class mercado extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10}],112:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9}],111:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -74332,7 +76576,7 @@ module.exports = class mixcoins extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10}],113:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9}],112:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -75045,7 +77289,7 @@ module.exports = class oceanex extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10}],114:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9}],113:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -75082,13 +77326,13 @@ module.exports = class okcoin extends okex { } }; -},{"./okex.js":115}],115:[function(require,module,exports){ +},{"./okex.js":114}],114:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- const Exchange = require ('./base/Exchange'); -const { ExchangeError, ExchangeNotAvailable, ArgumentsRequired, BadRequest, AccountSuspended, InvalidAddress, PermissionDenied, DDoSProtection, InsufficientFunds, InvalidNonce, CancelPending, InvalidOrder, OrderNotFound, AuthenticationError, RequestTimeout, NotSupported, BadSymbol } = require ('./base/errors'); +const { ExchangeError, ExchangeNotAvailable, OnMaintenance, ArgumentsRequired, BadRequest, AccountSuspended, InvalidAddress, PermissionDenied, DDoSProtection, InsufficientFunds, InvalidNonce, CancelPending, InvalidOrder, OrderNotFound, AuthenticationError, RequestTimeout, NotSupported, BadSymbol } = require ('./base/errors'); const { TICK_SIZE, TRUNCATE } = require ('./base/functions/number'); // --------------------------------------------------------------------------- @@ -75146,6 +77390,9 @@ module.exports = class okex extends Exchange { 'doc': 'https://www.okex.com/docs/en/', 'fees': 'https://www.okex.com/pages/products/fees.html', 'referral': 'https://www.okex.com/join/1888677', + 'test': { + 'rest': 'https://testnet.okex.com', + }, }, 'api': { 'general': { @@ -75433,8 +77680,9 @@ module.exports = class okex extends Exchange { '30034': ExchangeError, // { "code": 30034, "message": "exchange ID does not exist" } '30035': ExchangeError, // { "code": 30035, "message": "trading is not supported in this website" } '30036': ExchangeError, // { "code": 30036, "message": "no relevant data" } - '30038': AuthenticationError, // { "code": 30038, "message": "user does not exist" } '30037': ExchangeNotAvailable, // { "code": 30037, "message": "endpoint is offline or unavailable" } + // '30038': AuthenticationError, // { "code": 30038, "message": "user does not exist" } + '30038': OnMaintenance, // {"client_oid":"","code":"30038","error_code":"30038","error_message":"Matching engine is being upgraded. Please try in about 1 minute.","message":"Matching engine is being upgraded. Please try in about 1 minute.","order_id":"-1","result":false} // futures '32001': AccountSuspended, // { "code": 32001, "message": "futures account suspended" } '32002': PermissionDenied, // { "code": 32002, "message": "futures account does not exist" } @@ -75877,14 +78125,6 @@ module.exports = class okex extends Exchange { 'price': this.safeFloat (market, 'tick_size'), }; const minAmount = this.safeFloat2 (market, 'min_size', 'base_min_size'); - let minPrice = this.safeFloat (market, 'tick_size'); - if (precision['price'] !== undefined) { - minPrice = Math.pow (10, -precision['price']); - } - let minCost = undefined; - if (minAmount !== undefined && minPrice !== undefined) { - minCost = minAmount * minPrice; - } const active = true; const fees = this.safeValue2 (this.fees, marketType, 'trading', {}); return this.extend (fees, { @@ -75908,11 +78148,11 @@ module.exports = class okex extends Exchange { 'max': undefined, }, 'price': { - 'min': minPrice, + 'min': precision['price'], 'max': undefined, }, 'cost': { - 'min': minCost, + 'min': precision['price'], 'max': undefined, }, }, @@ -76445,8 +78685,18 @@ module.exports = class okex extends Exchange { 'instrument_id': market['id'], 'granularity': this.timeframes[timeframe], }; + const duration = this.parseTimeframe (timeframe); if (since !== undefined) { + if (limit !== undefined) { + request['end'] = this.iso8601 (this.sum (since, limit * duration * 1000)); + } request['start'] = this.iso8601 (since); + } else { + const now = this.milliseconds (); + if (limit !== undefined) { + request['start'] = this.iso8601 (now - limit * duration * 1000); + request['end'] = this.iso8601 (now); + } } const response = await this[method] (this.extend (request, params)); // @@ -76926,28 +79176,7 @@ module.exports = class okex extends Exchange { // "result":true // } // - const timestamp = this.milliseconds (); - const id = this.safeString (response, 'order_id'); - return { - 'info': response, - 'id': id, - 'timestamp': timestamp, - 'datetime': this.iso8601 (timestamp), - 'lastTradeTimestamp': undefined, - 'status': undefined, - 'symbol': symbol, - 'type': type, - 'side': side, - 'price': price, - 'amount': amount, - 'filled': undefined, - 'remaining': undefined, - 'cost': undefined, - 'trades': undefined, - 'fee': undefined, - 'clientOrderId': undefined, - 'average': undefined, - }; + return this.parseOrder (response, market); } async cancelOrder (id, symbol = undefined, params = {}) { @@ -77387,9 +79616,11 @@ module.exports = class okex extends Exchange { } parseDepositAddresses (addresses) { - const result = []; + const result = {}; for (let i = 0; i < addresses.length; i++) { - result.push (this.parseDepositAddress (addresses[i])); + const address = this.parseDepositAddress (addresses[i]); + const code = address['currency']; + result[code] = address; } return result; } @@ -77435,11 +79666,11 @@ module.exports = class okex extends Exchange { // ] // const addresses = this.parseDepositAddresses (response); - const numAddresses = addresses.length; - if (numAddresses < 1) { + const address = this.safeValue (addresses, code); + if (address === undefined) { throw new InvalidAddress (this.id + ' fetchDepositAddress cannot return nonexistent addresses, you should create withdrawal addresses with the exchange website first'); } - return addresses[0]; + return address; } async withdraw (code, amount, address, tag = undefined, params = {}) { @@ -77451,7 +79682,7 @@ module.exports = class okex extends Exchange { } const fee = this.safeString (params, 'fee'); if (fee === undefined) { - throw new ExchangeError (this.id + " withdraw() requires a `fee` string parameter, network transaction fee must be ≥ 0. Withdrawals to OKCoin or OKEx are fee-free, please set '0'. Withdrawing to external digital asset address requires network transaction fee."); + throw new ArgumentsRequired (this.id + " withdraw() requires a `fee` string parameter, network transaction fee must be ≥ 0. Withdrawals to OKCoin or OKEx are fee-free, please set '0'. Withdrawing to external digital asset address requires network transaction fee."); } const request = { 'currency': currency['id'], @@ -78293,7 +80524,7 @@ module.exports = class okex extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10,"./base/functions/number":16}],116:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9,"./base/functions/number":15}],115:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -78323,6 +80554,7 @@ module.exports = class paymium extends Exchange { 'https://github.com/Paymium/api-documentation', 'https://www.paymium.com/page/developers', ], + 'referral': 'https://www.paymium.com/page/sign-up?referral=eDAzPoRQFMvaAB8sf-qj', }, 'api': { 'public': { @@ -78337,12 +80569,12 @@ module.exports = class paymium extends Exchange { }, 'private': { 'get': [ - 'merchant/get_payment/{UUID}', + 'merchant/get_payment/{uuid}', 'user', 'user/addresses', 'user/addresses/{btc_address}', 'user/orders', - 'user/orders/{UUID}', + 'user/orders/{uuid}', 'user/price_alerts', ], 'post': [ @@ -78353,7 +80585,7 @@ module.exports = class paymium extends Exchange { 'merchant/create_payment', ], 'delete': [ - 'user/orders/{UUID}/cancel', + 'user/orders/{uuid}/cancel', 'user/price_alerts/{id}', ], }, @@ -78500,9 +80732,9 @@ module.exports = class paymium extends Exchange { async cancelOrder (id, symbol = undefined, params = {}) { const request = { - 'UUID': id, + 'uuid': id, }; - return await this.privateDeleteUserOrdersUUIDCancel (this.extend (request, params)); + return await this.privateDeleteUserOrdersUuidCancel (this.extend (request, params)); } sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) { @@ -78516,18 +80748,24 @@ module.exports = class paymium extends Exchange { this.checkRequiredCredentials (); const nonce = this.nonce ().toString (); let auth = nonce + url; + headers = { + 'Api-Key': this.apiKey, + 'Api-Nonce': nonce, + }; if (method === 'POST') { if (Object.keys (query).length) { body = this.json (query); auth += body; + headers['Content-Type'] = 'application/json'; + } + } else { + if (Object.keys (query).length) { + const queryString = this.urlencode (query); + auth += queryString; + url += '?' + queryString; } } - headers = { - 'Api-Key': this.apiKey, - 'Api-Signature': this.hmac (this.encode (auth), this.encode (this.secret)), - 'Api-Nonce': nonce, - 'Content-Type': 'application/json', - }; + headers['Api-Signature'] = this.hmac (this.encode (auth), this.encode (this.secret)); } return { 'url': url, 'method': method, 'body': body, 'headers': headers }; } @@ -78541,13 +80779,13 @@ module.exports = class paymium extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10}],117:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9}],116:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- const Exchange = require ('./base/Exchange'); -const { ExchangeError, ExchangeNotAvailable, RequestTimeout, AuthenticationError, PermissionDenied, DDoSProtection, InsufficientFunds, OrderNotFound, OrderNotCached, InvalidOrder, AccountSuspended, CancelPending, InvalidNonce } = require ('./base/errors'); +const { ExchangeError, ExchangeNotAvailable, RequestTimeout, AuthenticationError, PermissionDenied, DDoSProtection, InsufficientFunds, OrderNotFound, OrderNotCached, InvalidOrder, AccountSuspended, CancelPending, InvalidNonce, OnMaintenance } = require ('./base/errors'); // --------------------------------------------------------------------------- @@ -78714,6 +80952,7 @@ module.exports = class poloniex extends Exchange { 'Permission denied': PermissionDenied, 'Connection timed out. Please try again.': RequestTimeout, 'Internal error. Please try again.': ExchangeNotAvailable, + 'Currently in maintenance mode.': OnMaintenance, 'Order not found, or you are not the person who placed it.': OrderNotFound, 'Invalid API key/secret pair.': AuthenticationError, 'Please do not make more than 8 API calls per second.': DDoSProtection, @@ -79995,7 +82234,7 @@ module.exports = class poloniex extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10}],118:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9}],117:[function(require,module,exports){ 'use strict'; const Exchange = require ('./base/Exchange'); @@ -80760,7 +82999,7 @@ module.exports = class rightbtc extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10,"./base/functions/number":16}],119:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9,"./base/functions/number":15}],118:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -81130,7 +83369,7 @@ module.exports = class southxchange extends Exchange { } }; -},{"./base/Exchange":8}],120:[function(require,module,exports){ +},{"./base/Exchange":7}],119:[function(require,module,exports){ (function (module, exports) { 'use strict'; @@ -84658,7 +86897,7 @@ module.exports = class southxchange extends Exchange { }; })(typeof module === 'undefined' || module, this); -},{"buffer":179}],121:[function(require,module,exports){ +},{"buffer":178}],120:[function(require,module,exports){ ;(function (root, factory) { if (typeof exports === "object") { // CommonJS @@ -90647,7 +92886,7 @@ module.exports = class southxchange extends Exchange { return CryptoJS; })); -},{}],122:[function(require,module,exports){ +},{}],121:[function(require,module,exports){ 'use strict'; var elliptic = exports; @@ -90670,7 +92909,7 @@ elliptic.curves = require('./elliptic/curves'); // Protocols elliptic.ec = require('./elliptic/ec'); -},{"./elliptic/curve":125,"./elliptic/curves":128,"./elliptic/ec":129,"./elliptic/utils":133}],123:[function(require,module,exports){ +},{"./elliptic/curve":124,"./elliptic/curves":127,"./elliptic/ec":128,"./elliptic/utils":132}],122:[function(require,module,exports){ 'use strict'; var BN = require('../../../../BN/bn'); @@ -91047,7 +93286,7 @@ BasePoint.prototype.dblp = function dblp(k) { return r; }; -},{"../../../../BN/bn":120,"../../elliptic":122}],124:[function(require,module,exports){ +},{"../../../../BN/bn":119,"../../elliptic":121}],123:[function(require,module,exports){ 'use strict'; var curve = require('../curve'); @@ -91482,7 +93721,7 @@ Point.prototype.eqXToP = function eqXToP(x) { Point.prototype.toP = Point.prototype.normalize; Point.prototype.mixedAdd = Point.prototype.add; -},{"../../../../BN/bn":120,"../../elliptic":122,"../curve":125}],125:[function(require,module,exports){ +},{"../../../../BN/bn":119,"../../elliptic":121,"../curve":124}],124:[function(require,module,exports){ 'use strict'; var curve = exports; @@ -91492,7 +93731,7 @@ curve.short = require('./short'); curve.mont = require('./mont'); curve.edwards = require('./edwards'); -},{"./base":123,"./edwards":124,"./mont":126,"./short":127}],126:[function(require,module,exports){ +},{"./base":122,"./edwards":123,"./mont":125,"./short":126}],125:[function(require,module,exports){ 'use strict'; var curve = require('../curve'); @@ -91674,7 +93913,7 @@ Point.prototype.getX = function getX() { return this.x.fromRed(); }; -},{"../../../../BN/bn":120,"../../elliptic":122,"../curve":125}],127:[function(require,module,exports){ +},{"../../../../BN/bn":119,"../../elliptic":121,"../curve":124}],126:[function(require,module,exports){ 'use strict'; var curve = require('../curve'); @@ -92614,7 +94853,7 @@ JPoint.prototype.isInfinity = function isInfinity() { return this.z.cmpn(0) === 0; }; -},{"../../../../BN/bn":120,"../../elliptic":122,"../curve":125}],128:[function(require,module,exports){ +},{"../../../../BN/bn":119,"../../elliptic":121,"../curve":124}],127:[function(require,module,exports){ 'use strict'; var curves = exports; @@ -92820,7 +95059,7 @@ defineCurve('secp256k1', { ] }); -},{"../elliptic":122,"./precomputed/secp256k1":132}],129:[function(require,module,exports){ +},{"../elliptic":121,"./precomputed/secp256k1":131}],128:[function(require,module,exports){ 'use strict'; var BN = require('../../../../BN/bn'); @@ -93062,7 +95301,7 @@ EC.prototype.getKeyRecoveryParam = function(e, signature, Q, enc) { throw new Error('Unable to find valid recovery factor'); }; -},{"../../../../BN/bn":120,"../../elliptic":122,"../../hmac-drbg/hmac-drbg":134,"./key":130,"./signature":131}],130:[function(require,module,exports){ +},{"../../../../BN/bn":119,"../../elliptic":121,"../../hmac-drbg/hmac-drbg":133,"./key":129,"./signature":130}],129:[function(require,module,exports){ 'use strict'; var BN = require('../../../../BN/bn'); @@ -93183,7 +95422,7 @@ KeyPair.prototype.inspect = function inspect() { ' pub: ' + (this.pub && this.pub.inspect()) + ' >'; }; -},{"../../../../BN/bn":120,"../../elliptic":122}],131:[function(require,module,exports){ +},{"../../../../BN/bn":119,"../../elliptic":121}],130:[function(require,module,exports){ 'use strict'; var BN = require('../../../../BN/bn'); @@ -93209,7 +95448,7 @@ function Signature(options, enc) { } module.exports = Signature; -},{"../../../../BN/bn":120,"../../elliptic":122}],132:[function(require,module,exports){ +},{"../../../../BN/bn":119,"../../elliptic":121}],131:[function(require,module,exports){ module.exports = { doubles: { step: 4, @@ -93991,7 +96230,7 @@ module.exports = { } }; -},{}],133:[function(require,module,exports){ +},{}],132:[function(require,module,exports){ 'use strict'; var utils = exports; @@ -94149,7 +96388,7 @@ function wordArrayToBuffer(wordArray) { utils.wordArrayToBuffer = wordArrayToBuffer; -},{"../../../BN/bn":120}],134:[function(require,module,exports){ +},{"../../../BN/bn":119}],133:[function(require,module,exports){ 'use strict'; var CryptoJS = require('../../../crypto-js/crypto-js'); @@ -94265,7 +96504,7 @@ HmacDRBG.prototype.generate = function generate(len, enc, add, addEnc) { return utils.wordArrayToBuffer(res); }; -},{"../../../../base/functions/encode":13,"../../../crypto-js/crypto-js":121,"../elliptic/utils":133}],135:[function(require,module,exports){ +},{"../../../../base/functions/encode":12,"../../../crypto-js/crypto-js":120,"../elliptic/utils":132}],134:[function(require,module,exports){ 'use strict'; var fetch = require('../node-fetch/index'); @@ -94306,7 +96545,7 @@ module.exports = function (context) { }; }; -},{"../node-fetch/index":136}],136:[function(require,module,exports){ +},{"../node-fetch/index":135}],135:[function(require,module,exports){ (function (global,Buffer){ 'use strict'; @@ -95874,7 +98113,7 @@ exports.Response = Response; exports.FetchError = FetchError; }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {},require("buffer").Buffer) -},{"buffer":179,"http":221,"https":184,"stream":220,"url":227,"zlib":178}],137:[function(require,module,exports){ +},{"buffer":178,"http":220,"https":183,"stream":219,"url":226,"zlib":177}],136:[function(require,module,exports){ (function (Buffer){ /*! * RSA library for Node.js @@ -96101,7 +98340,7 @@ module.exports = (function () { })(); }).call(this,require("buffer").Buffer) -},{"./formats/formats.js":144,"./libs/rsa.js":148,"./schemes/schemes.js":150,"./utils":151,"buffer":179}],138:[function(require,module,exports){ +},{"./formats/formats.js":143,"./libs/rsa.js":147,"./schemes/schemes.js":149,"./utils":150,"buffer":178}],137:[function(require,module,exports){ // Copyright 2011 Mark Cavage All rights reserved. @@ -96116,7 +98355,7 @@ module.exports = { }; -},{}],139:[function(require,module,exports){ +},{}],138:[function(require,module,exports){ // Copyright 2011 Mark Cavage All rights reserved. var errors = require('./errors'); @@ -96139,7 +98378,7 @@ for (var e in errors) { module.exports[e] = errors[e]; } -},{"./errors":138,"./reader":140,"./types":141}],140:[function(require,module,exports){ +},{"./errors":137,"./reader":139,"./types":140}],139:[function(require,module,exports){ (function (Buffer){ // Copyright 2011 Mark Cavage All rights reserved. @@ -96405,7 +98644,7 @@ Reader.prototype._readTag = function (tag) { module.exports = Reader; }).call(this,require("buffer").Buffer) -},{"./errors":138,"./types":141,"assert":174,"buffer":179}],141:[function(require,module,exports){ +},{"./errors":137,"./types":140,"assert":173,"buffer":178}],140:[function(require,module,exports){ // Copyright 2011 Mark Cavage All rights reserved. @@ -96443,7 +98682,7 @@ module.exports = { Context: 128 }; -},{}],142:[function(require,module,exports){ +},{}],141:[function(require,module,exports){ // Copyright 2011 Mark Cavage All rights reserved. // If you have no idea what ASN.1 or BER is, see this: @@ -96462,7 +98701,7 @@ module.exports = { BerReader: Ber.Reader, }; -},{"./ber/index":139}],143:[function(require,module,exports){ +},{"./ber/index":138}],142:[function(require,module,exports){ var _ = require('../utils')._; var utils = require('../utils'); @@ -96535,7 +98774,7 @@ module.exports = { } }; -},{"../utils":151}],144:[function(require,module,exports){ +},{"../utils":150}],143:[function(require,module,exports){ var _ = require('../utils')._; module.exports = { @@ -96568,7 +98807,7 @@ module.exports = { }, }; -},{"../utils":151,"./components":143,"./pkcs1":145,"./pkcs8":146}],145:[function(require,module,exports){ +},{"../utils":150,"./components":142,"./pkcs1":144,"./pkcs8":145}],144:[function(require,module,exports){ (function (Buffer){ var ber = require('../asn1/index').Ber; var _ = require('../utils')._; @@ -96720,7 +98959,7 @@ module.exports = { }; }).call(this,require("buffer").Buffer) -},{"../asn1/index":142,"../utils":151,"buffer":179}],146:[function(require,module,exports){ +},{"../asn1/index":141,"../utils":150,"buffer":178}],145:[function(require,module,exports){ (function (Buffer){ var ber = require('../asn1/index').Ber; var _ = require('../utils')._; @@ -96911,7 +99150,7 @@ module.exports = { }; }).call(this,require("buffer").Buffer) -},{"../asn1/index":142,"../utils":151,"buffer":179}],147:[function(require,module,exports){ +},{"../asn1/index":141,"../utils":150,"buffer":178}],146:[function(require,module,exports){ (function (Buffer){ /* * Basic JavaScript BN library - subset useful for RSA encryption. @@ -98167,7 +100406,7 @@ BigInteger.prototype.square = bnSquare; module.exports = BigInteger; }).call(this,require("buffer").Buffer) -},{"../utils":151,"buffer":179}],148:[function(require,module,exports){ +},{"../utils":150,"buffer":178}],147:[function(require,module,exports){ /* * RSA Encryption / Decryption with PKCS1 v2 Padding. * @@ -98316,7 +100555,7 @@ module.exports.Key = (function () { })(); -},{"../schemes/schemes.js":150,"../utils":151,"../utils.js":151,"./jsbn.js":147}],149:[function(require,module,exports){ +},{"../schemes/schemes.js":149,"../utils":150,"../utils.js":150,"./jsbn.js":146}],148:[function(require,module,exports){ (function (Buffer){ /** * PKCS1 padding and signature scheme @@ -98496,7 +100735,7 @@ function wordArrayToBuffer(wordArray) { } }).call(this,require("buffer").Buffer) -},{"../../crypto-js/crypto-js":121,"../libs/jsbn":147,"buffer":179,"constants":181}],150:[function(require,module,exports){ +},{"../../crypto-js/crypto-js":120,"../libs/jsbn":146,"buffer":178,"constants":180}],149:[function(require,module,exports){ module.exports = { pkcs1: require('./pkcs1'), @@ -98519,7 +100758,7 @@ module.exports = { } }; -},{"./pkcs1":149}],151:[function(require,module,exports){ +},{"./pkcs1":148}],150:[function(require,module,exports){ /* * Utils functions * @@ -98619,7 +100858,7 @@ module.exports.trimSurroundingText = function (data, opening, closing) { return data.substring(trimStartIndex, trimEndIndex); } -},{}],152:[function(require,module,exports){ +},{}],151:[function(require,module,exports){ 'use strict'; var replace = String.prototype.replace; @@ -98639,7 +100878,7 @@ module.exports = { RFC3986: 'RFC3986' }; -},{}],153:[function(require,module,exports){ +},{}],152:[function(require,module,exports){ 'use strict'; var stringify = require('./stringify'); @@ -98652,7 +100891,7 @@ module.exports = { stringify: stringify }; -},{"./formats":152,"./parse":154,"./stringify":155}],154:[function(require,module,exports){ +},{"./formats":151,"./parse":153,"./stringify":154}],153:[function(require,module,exports){ 'use strict'; var utils = require('./utils'); @@ -98896,7 +101135,7 @@ module.exports = function (str, opts) { return utils.compact(obj); }; -},{"./utils":156}],155:[function(require,module,exports){ +},{"./utils":155}],154:[function(require,module,exports){ 'use strict'; var utils = require('./utils'); @@ -99167,7 +101406,7 @@ module.exports = function (object, opts) { return joined.length > 0 ? prefix + joined : ''; }; -},{"./formats":152,"./utils":156}],156:[function(require,module,exports){ +},{"./formats":151,"./utils":155}],155:[function(require,module,exports){ 'use strict'; var has = Object.prototype.hasOwnProperty; @@ -99399,7 +101638,7 @@ module.exports = { merge: merge }; -},{}],157:[function(require,module,exports){ +},{}],156:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -101200,7 +103439,7 @@ module.exports = class stex extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10}],158:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9}],157:[function(require,module,exports){ 'use strict'; // ---------------------------------------------------------------------------- @@ -101993,7 +104232,7 @@ module.exports = class stronghold extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10}],159:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9}],158:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -102027,7 +104266,7 @@ module.exports = class surbitcoin extends foxbit { } }; -},{"./foxbit.js":85}],160:[function(require,module,exports){ +},{"./foxbit.js":84}],159:[function(require,module,exports){ 'use strict'; const Exchange = require ('./base/Exchange'); @@ -102210,6 +104449,9 @@ module.exports = class theocean extends Exchange { } async fetchOHLCV (symbol, timeframe = '5m', since = undefined, limit = undefined, params = {}) { + if (since === undefined) { + throw new ArgumentsRequired (this.id + ' fetchOHLCV requires a since argument'); + } await this.loadMarkets (); const market = this.market (symbol); const request = { @@ -102217,9 +104459,6 @@ module.exports = class theocean extends Exchange { 'quoteTokenAddress': market['quoteId'], 'interval': this.timeframes[timeframe], }; - if (since === undefined) { - throw new ExchangeError (this.id + ' fetchOHLCV requires a since argument'); - } since = parseInt (since); request['startTime'] = since; const response = await this.publicGetCandlesticks (this.extend (request, params)); @@ -102942,7 +105181,7 @@ module.exports = class theocean extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10}],161:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9}],160:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -104173,13 +106412,13 @@ module.exports = class therock extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10}],162:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9}],161:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- const Exchange = require ('./base/Exchange'); -const { ExchangeError, InsufficientFunds, OrderNotFound } = require ('./base/errors'); +const { ExchangeError, InsufficientFunds, OrderNotFound, ArgumentsRequired } = require ('./base/errors'); // --------------------------------------------------------------------------- @@ -104636,7 +106875,7 @@ module.exports = class tidebit extends Exchange { const currency = this.currency (code); const id = this.safeString (params, 'id'); if (id === undefined) { - throw new ExchangeError (this.id + ' withdraw() requires an extra `id` param (withdraw account id according to withdraws/bind_account_list endpoint'); + throw new ArgumentsRequired (this.id + ' withdraw() requires an extra `id` param (withdraw account id according to withdraws/bind_account_list endpoint'); } const request = { 'id': id, @@ -104706,7 +106945,7 @@ module.exports = class tidebit extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10}],163:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9}],162:[function(require,module,exports){ 'use strict'; const Exchange = require ('./base/Exchange'); @@ -105569,7 +107808,7 @@ module.exports = class tidex extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10}],164:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9}],163:[function(require,module,exports){ 'use strict'; const Exchange = require ('./base/Exchange'); @@ -105614,6 +107853,7 @@ module.exports = class timex extends Exchange { 'api': 'https://plasma-relay-backend.timex.io', 'www': 'https://timex.io', 'doc': 'https://docs.timex.io', + 'referral': 'https://timex.io/?refcode=1x27vNkTbP1uwkCck', }, 'api': { 'custody': { @@ -106464,7 +108704,21 @@ module.exports = class timex extends Exchange { // "active": true, // "withdrawalFee": "50000000000000000", // "purchaseCommissions": [] - // }, + // } + // + // https://github.com/ccxt/ccxt/issues/6878 + // + // { + // "symbol":"XRP", + // "name":"Ripple", + // "address":"0x0dc8882914f3ddeebf4cec6dc20edb99df3def6c", + // "decimals":6, + // "tradeDecimals":16, + // "depositEnabled":true, + // "withdrawalEnabled":true, + // "transferEnabled":true, + // "active":true + // } // const id = this.safeString (currency, 'symbol'); const code = this.safeCurrencyCode (id); @@ -106473,20 +108727,22 @@ module.exports = class timex extends Exchange { const active = this.safeValue (currency, 'active'); // const fee = this.safeFloat (currency, 'withdrawalFee'); const feeString = this.safeString (currency, 'withdrawalFee'); - const feeStringLen = feeString.length; const tradeDecimals = this.safeInteger (currency, 'tradeDecimals'); let fee = undefined; - const dotIndex = feeStringLen - tradeDecimals; - if (dotIndex > 0) { - const whole = feeString.slice (0, dotIndex); - const fraction = feeString.slice (-dotIndex); - fee = parseFloat (whole + '.' + fraction); - } else { - let fraction = '.'; - for (let i = 0; i < -dotIndex; i++) { - fraction += '0'; + if ((feeString !== undefined) && (tradeDecimals !== undefined)) { + const feeStringLen = feeString.length; + const dotIndex = feeStringLen - tradeDecimals; + if (dotIndex > 0) { + const whole = feeString.slice (0, dotIndex); + const fraction = feeString.slice (-dotIndex); + fee = parseFloat (whole + '.' + fraction); + } else { + let fraction = '.'; + for (let i = 0; i < -dotIndex; i++) { + fraction += '0'; + } + fee = parseFloat (fraction + feeString); } - fee = parseFloat (fraction + feeString); } return { 'id': code, @@ -106677,7 +108933,7 @@ module.exports = class timex extends Exchange { this.safeFloat (ohlcv, 'high'), this.safeFloat (ohlcv, 'low'), this.safeFloat (ohlcv, 'close'), - this.safeFloat (ohlcv, 'volumeQuote'), + this.safeFloat (ohlcv, 'volume'), ]; } @@ -106808,7 +109064,7 @@ module.exports = class timex extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10}],165:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9}],164:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -106835,7 +109091,7 @@ module.exports = class topq extends bw { } }; -},{"./bw.js":56}],166:[function(require,module,exports){ +},{"./bw.js":55}],165:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -108162,9 +110418,11 @@ module.exports = class upbit extends Exchange { } parseDepositAddresses (addresses) { - const result = []; + const result = {}; for (let i = 0; i < addresses.length; i++) { - result.push (this.parseDepositAddress (addresses[i])); + const address = this.parseDepositAddress (addresses[i]); + const code = address['currency']; + result[code] = address; } return result; } @@ -108366,7 +110624,7 @@ module.exports = class upbit extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10}],167:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9}],166:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -108571,7 +110829,7 @@ module.exports = class vaultoro extends Exchange { } }; -},{"./base/Exchange":8}],168:[function(require,module,exports){ +},{"./base/Exchange":7}],167:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -108605,7 +110863,7 @@ module.exports = class vbtc extends foxbit { } }; -},{"./foxbit.js":85}],169:[function(require,module,exports){ +},{"./foxbit.js":84}],168:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -109237,7 +111495,7 @@ module.exports = class whitebit extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10}],170:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9}],169:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -109602,7 +111860,7 @@ module.exports = class xbtce extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10}],171:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9}],170:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -109772,11 +112030,12 @@ module.exports = class yobit extends Exchange { 'api key dont have trade permission': AuthenticationError, 'invalid parameter': InvalidOrder, 'invalid order': InvalidOrder, + 'The given order has already been cancelled': InvalidOrder, 'Requests too often': DDoSProtection, 'not available': ExchangeNotAvailable, 'data unavailable': ExchangeNotAvailable, 'external service unavailable': ExchangeNotAvailable, - 'Total transaction amount': ExchangeError, // { "success": 0, "error": "Total transaction amount is less than minimal total: 0.00010000"} + 'Total transaction amount': InvalidOrder, // { "success": 0, "error": "Total transaction amount is less than minimal total: 0.00010000"} 'Insufficient funds': InsufficientFunds, 'invalid key': AuthenticationError, 'invalid nonce': InvalidNonce, // {"success":0,"error":"invalid nonce (has already been used)"}' @@ -110537,7 +112796,7 @@ module.exports = class yobit extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10}],172:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9}],171:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -111049,7 +113308,7 @@ module.exports = class zaif extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10}],173:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9}],172:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -111505,7 +113764,7 @@ module.exports = class zb extends Exchange { async fetchOrders (symbol = undefined, since = undefined, limit = 50, params = {}) { if (symbol === undefined) { - throw new ExchangeError (this.id + 'fetchOrders requires a symbol parameter'); + throw new ArgumentsRequired (this.id + 'fetchOrders requires a symbol argument'); } await this.loadMarkets (); const market = this.market (symbol); @@ -111533,7 +113792,7 @@ module.exports = class zb extends Exchange { async fetchOpenOrders (symbol = undefined, since = undefined, limit = 10, params = {}) { if (symbol === undefined) { - throw new ExchangeError (this.id + 'fetchOpenOrders requires a symbol parameter'); + throw new ArgumentsRequired (this.id + 'fetchOpenOrders requires a symbol argument'); } await this.loadMarkets (); const market = this.market (symbol); @@ -111700,7 +113959,7 @@ module.exports = class zb extends Exchange { } }; -},{"./base/Exchange":8,"./base/errors":10}],174:[function(require,module,exports){ +},{"./base/Exchange":7,"./base/errors":9}],173:[function(require,module,exports){ (function (global){ 'use strict'; @@ -112194,7 +114453,7 @@ var objectKeys = Object.keys || function (obj) { }; }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"util/":232}],175:[function(require,module,exports){ +},{"util/":231}],174:[function(require,module,exports){ 'use strict' exports.byteLength = byteLength @@ -112310,9 +114569,9 @@ function fromByteArray (uint8) { return parts.join('') } -},{}],176:[function(require,module,exports){ +},{}],175:[function(require,module,exports){ -},{}],177:[function(require,module,exports){ +},{}],176:[function(require,module,exports){ (function (process,Buffer){ 'use strict'; /* eslint camelcase: "off" */ @@ -112724,7 +114983,7 @@ Zlib.prototype._reset = function () { exports.Zlib = Zlib; }).call(this,require('_process'),require("buffer").Buffer) -},{"_process":201,"assert":174,"buffer":179,"pako/lib/zlib/constants":191,"pako/lib/zlib/deflate.js":193,"pako/lib/zlib/inflate.js":195,"pako/lib/zlib/zstream":199}],178:[function(require,module,exports){ +},{"_process":200,"assert":173,"buffer":178,"pako/lib/zlib/constants":190,"pako/lib/zlib/deflate.js":192,"pako/lib/zlib/inflate.js":194,"pako/lib/zlib/zstream":198}],177:[function(require,module,exports){ (function (process){ 'use strict'; @@ -113336,7 +115595,7 @@ util.inherits(DeflateRaw, Zlib); util.inherits(InflateRaw, Zlib); util.inherits(Unzip, Zlib); }).call(this,require('_process')) -},{"./binding":177,"_process":201,"assert":174,"buffer":179,"stream":220,"util":232}],179:[function(require,module,exports){ +},{"./binding":176,"_process":200,"assert":173,"buffer":178,"stream":219,"util":231}],178:[function(require,module,exports){ /*! * The buffer module from node.js, for the browser. * @@ -115052,7 +117311,7 @@ function numberIsNaN (obj) { return obj !== obj // eslint-disable-line no-self-compare } -},{"base64-js":175,"ieee754":185}],180:[function(require,module,exports){ +},{"base64-js":174,"ieee754":184}],179:[function(require,module,exports){ module.exports = { "100": "Continue", "101": "Switching Protocols", @@ -115118,7 +117377,7 @@ module.exports = { "511": "Network Authentication Required" } -},{}],181:[function(require,module,exports){ +},{}],180:[function(require,module,exports){ module.exports={ "O_RDONLY": 0, "O_WRONLY": 1, @@ -115329,7 +117588,7 @@ module.exports={ "UV_UDP_REUSEADDR": 4 } -},{}],182:[function(require,module,exports){ +},{}],181:[function(require,module,exports){ (function (Buffer){ // Copyright Joyent, Inc. and other Node contributors. // @@ -115440,7 +117699,7 @@ function objectToString(o) { } }).call(this,{"isBuffer":require("../../is-buffer/index.js")}) -},{"../../is-buffer/index.js":187}],183:[function(require,module,exports){ +},{"../../is-buffer/index.js":186}],182:[function(require,module,exports){ // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a @@ -115744,7 +118003,7 @@ function isUndefined(arg) { return arg === void 0; } -},{}],184:[function(require,module,exports){ +},{}],183:[function(require,module,exports){ var http = require('http') var url = require('url') @@ -115777,7 +118036,7 @@ function validateParams (params) { return params } -},{"http":221,"url":227}],185:[function(require,module,exports){ +},{"http":220,"url":226}],184:[function(require,module,exports){ exports.read = function (buffer, offset, isLE, mLen, nBytes) { var e, m var eLen = nBytes * 8 - mLen - 1 @@ -115863,7 +118122,7 @@ exports.write = function (buffer, value, offset, isLE, mLen, nBytes) { buffer[offset + i - d] |= s * 128 } -},{}],186:[function(require,module,exports){ +},{}],185:[function(require,module,exports){ if (typeof Object.create === 'function') { // implementation from standard node.js 'util' module module.exports = function inherits(ctor, superCtor) { @@ -115888,7 +118147,7 @@ if (typeof Object.create === 'function') { } } -},{}],187:[function(require,module,exports){ +},{}],186:[function(require,module,exports){ /*! * Determine if an object is a Buffer * @@ -115911,14 +118170,14 @@ function isSlowBuffer (obj) { return typeof obj.readFloatLE === 'function' && typeof obj.slice === 'function' && isBuffer(obj.slice(0, 0)) } -},{}],188:[function(require,module,exports){ +},{}],187:[function(require,module,exports){ var toString = {}.toString; module.exports = Array.isArray || function (arr) { return toString.call(arr) == '[object Array]'; }; -},{}],189:[function(require,module,exports){ +},{}],188:[function(require,module,exports){ 'use strict'; @@ -116025,7 +118284,7 @@ exports.setTyped = function (on) { exports.setTyped(TYPED_OK); -},{}],190:[function(require,module,exports){ +},{}],189:[function(require,module,exports){ 'use strict'; // Note: adler32 takes 12% for level 0 and 2% for level 6. @@ -116078,7 +118337,7 @@ function adler32(adler, buf, len, pos) { module.exports = adler32; -},{}],191:[function(require,module,exports){ +},{}],190:[function(require,module,exports){ 'use strict'; // (C) 1995-2013 Jean-loup Gailly and Mark Adler @@ -116148,7 +118407,7 @@ module.exports = { //Z_NULL: null // Use -1 or null inline, depending on var type }; -},{}],192:[function(require,module,exports){ +},{}],191:[function(require,module,exports){ 'use strict'; // Note: we can't get significant speed boost here. @@ -116209,7 +118468,7 @@ function crc32(crc, buf, len, pos) { module.exports = crc32; -},{}],193:[function(require,module,exports){ +},{}],192:[function(require,module,exports){ 'use strict'; // (C) 1995-2013 Jean-loup Gailly and Mark Adler @@ -118085,7 +120344,7 @@ exports.deflatePrime = deflatePrime; exports.deflateTune = deflateTune; */ -},{"../utils/common":189,"./adler32":190,"./crc32":192,"./messages":197,"./trees":198}],194:[function(require,module,exports){ +},{"../utils/common":188,"./adler32":189,"./crc32":191,"./messages":196,"./trees":197}],193:[function(require,module,exports){ 'use strict'; // (C) 1995-2013 Jean-loup Gailly and Mark Adler @@ -118432,7 +120691,7 @@ module.exports = function inflate_fast(strm, start) { return; }; -},{}],195:[function(require,module,exports){ +},{}],194:[function(require,module,exports){ 'use strict'; // (C) 1995-2013 Jean-loup Gailly and Mark Adler @@ -119990,7 +122249,7 @@ exports.inflateSyncPoint = inflateSyncPoint; exports.inflateUndermine = inflateUndermine; */ -},{"../utils/common":189,"./adler32":190,"./crc32":192,"./inffast":194,"./inftrees":196}],196:[function(require,module,exports){ +},{"../utils/common":188,"./adler32":189,"./crc32":191,"./inffast":193,"./inftrees":195}],195:[function(require,module,exports){ 'use strict'; // (C) 1995-2013 Jean-loup Gailly and Mark Adler @@ -120335,7 +122594,7 @@ module.exports = function inflate_table(type, lens, lens_index, codes, table, ta return 0; }; -},{"../utils/common":189}],197:[function(require,module,exports){ +},{"../utils/common":188}],196:[function(require,module,exports){ 'use strict'; // (C) 1995-2013 Jean-loup Gailly and Mark Adler @@ -120369,7 +122628,7 @@ module.exports = { '-6': 'incompatible version' /* Z_VERSION_ERROR (-6) */ }; -},{}],198:[function(require,module,exports){ +},{}],197:[function(require,module,exports){ 'use strict'; // (C) 1995-2013 Jean-loup Gailly and Mark Adler @@ -121591,7 +123850,7 @@ exports._tr_flush_block = _tr_flush_block; exports._tr_tally = _tr_tally; exports._tr_align = _tr_align; -},{"../utils/common":189}],199:[function(require,module,exports){ +},{"../utils/common":188}],198:[function(require,module,exports){ 'use strict'; // (C) 1995-2013 Jean-loup Gailly and Mark Adler @@ -121640,7 +123899,7 @@ function ZStream() { module.exports = ZStream; -},{}],200:[function(require,module,exports){ +},{}],199:[function(require,module,exports){ (function (process){ 'use strict'; @@ -121687,7 +123946,7 @@ function nextTick(fn, arg1, arg2, arg3) { } }).call(this,require('_process')) -},{"_process":201}],201:[function(require,module,exports){ +},{"_process":200}],200:[function(require,module,exports){ // shim for using process in browser var process = module.exports = {}; @@ -121873,7 +124132,7 @@ process.chdir = function (dir) { }; process.umask = function() { return 0; }; -},{}],202:[function(require,module,exports){ +},{}],201:[function(require,module,exports){ (function (global){ /*! https://mths.be/punycode v1.4.1 by @mathias */ ;(function(root) { @@ -122410,7 +124669,7 @@ process.umask = function() { return 0; }; }(this)); }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{}],203:[function(require,module,exports){ +},{}],202:[function(require,module,exports){ // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a @@ -122496,7 +124755,7 @@ var isArray = Array.isArray || function (xs) { return Object.prototype.toString.call(xs) === '[object Array]'; }; -},{}],204:[function(require,module,exports){ +},{}],203:[function(require,module,exports){ // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a @@ -122583,16 +124842,16 @@ var objectKeys = Object.keys || function (obj) { return res; }; -},{}],205:[function(require,module,exports){ +},{}],204:[function(require,module,exports){ 'use strict'; exports.decode = exports.parse = require('./decode'); exports.encode = exports.stringify = require('./encode'); -},{"./decode":203,"./encode":204}],206:[function(require,module,exports){ +},{"./decode":202,"./encode":203}],205:[function(require,module,exports){ module.exports = require('./lib/_stream_duplex.js'); -},{"./lib/_stream_duplex.js":207}],207:[function(require,module,exports){ +},{"./lib/_stream_duplex.js":206}],206:[function(require,module,exports){ // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a @@ -122717,7 +124976,7 @@ function forEach(xs, f) { f(xs[i], i); } } -},{"./_stream_readable":209,"./_stream_writable":211,"core-util-is":182,"inherits":186,"process-nextick-args":200}],208:[function(require,module,exports){ +},{"./_stream_readable":208,"./_stream_writable":210,"core-util-is":181,"inherits":185,"process-nextick-args":199}],207:[function(require,module,exports){ // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a @@ -122765,7 +125024,7 @@ function PassThrough(options) { PassThrough.prototype._transform = function (chunk, encoding, cb) { cb(null, chunk); }; -},{"./_stream_transform":210,"core-util-is":182,"inherits":186}],209:[function(require,module,exports){ +},{"./_stream_transform":209,"core-util-is":181,"inherits":185}],208:[function(require,module,exports){ (function (process,global){ // Copyright Joyent, Inc. and other Node contributors. // @@ -123775,7 +126034,7 @@ function indexOf(xs, x) { return -1; } }).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"./_stream_duplex":207,"./internal/streams/BufferList":212,"./internal/streams/destroy":213,"./internal/streams/stream":214,"_process":201,"core-util-is":182,"events":183,"inherits":186,"isarray":188,"process-nextick-args":200,"safe-buffer":219,"string_decoder/":225,"util":176}],210:[function(require,module,exports){ +},{"./_stream_duplex":206,"./internal/streams/BufferList":211,"./internal/streams/destroy":212,"./internal/streams/stream":213,"_process":200,"core-util-is":181,"events":182,"inherits":185,"isarray":187,"process-nextick-args":199,"safe-buffer":218,"string_decoder/":224,"util":175}],209:[function(require,module,exports){ // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a @@ -123990,7 +126249,7 @@ function done(stream, er, data) { return stream.push(null); } -},{"./_stream_duplex":207,"core-util-is":182,"inherits":186}],211:[function(require,module,exports){ +},{"./_stream_duplex":206,"core-util-is":181,"inherits":185}],210:[function(require,module,exports){ (function (process,global){ // Copyright Joyent, Inc. and other Node contributors. // @@ -124657,7 +126916,7 @@ Writable.prototype._destroy = function (err, cb) { cb(err); }; }).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"./_stream_duplex":207,"./internal/streams/destroy":213,"./internal/streams/stream":214,"_process":201,"core-util-is":182,"inherits":186,"process-nextick-args":200,"safe-buffer":219,"util-deprecate":229}],212:[function(require,module,exports){ +},{"./_stream_duplex":206,"./internal/streams/destroy":212,"./internal/streams/stream":213,"_process":200,"core-util-is":181,"inherits":185,"process-nextick-args":199,"safe-buffer":218,"util-deprecate":228}],211:[function(require,module,exports){ 'use strict'; /**/ @@ -124732,7 +126991,7 @@ module.exports = function () { return BufferList; }(); -},{"safe-buffer":219}],213:[function(require,module,exports){ +},{"safe-buffer":218}],212:[function(require,module,exports){ 'use strict'; /**/ @@ -124805,13 +127064,13 @@ module.exports = { destroy: destroy, undestroy: undestroy }; -},{"process-nextick-args":200}],214:[function(require,module,exports){ +},{"process-nextick-args":199}],213:[function(require,module,exports){ module.exports = require('events').EventEmitter; -},{"events":183}],215:[function(require,module,exports){ +},{"events":182}],214:[function(require,module,exports){ module.exports = require('./readable').PassThrough -},{"./readable":216}],216:[function(require,module,exports){ +},{"./readable":215}],215:[function(require,module,exports){ exports = module.exports = require('./lib/_stream_readable.js'); exports.Stream = exports; exports.Readable = exports; @@ -124820,13 +127079,13 @@ exports.Duplex = require('./lib/_stream_duplex.js'); exports.Transform = require('./lib/_stream_transform.js'); exports.PassThrough = require('./lib/_stream_passthrough.js'); -},{"./lib/_stream_duplex.js":207,"./lib/_stream_passthrough.js":208,"./lib/_stream_readable.js":209,"./lib/_stream_transform.js":210,"./lib/_stream_writable.js":211}],217:[function(require,module,exports){ +},{"./lib/_stream_duplex.js":206,"./lib/_stream_passthrough.js":207,"./lib/_stream_readable.js":208,"./lib/_stream_transform.js":209,"./lib/_stream_writable.js":210}],216:[function(require,module,exports){ module.exports = require('./readable').Transform -},{"./readable":216}],218:[function(require,module,exports){ +},{"./readable":215}],217:[function(require,module,exports){ module.exports = require('./lib/_stream_writable.js'); -},{"./lib/_stream_writable.js":211}],219:[function(require,module,exports){ +},{"./lib/_stream_writable.js":210}],218:[function(require,module,exports){ /* eslint-disable node/no-deprecated-api */ var buffer = require('buffer') var Buffer = buffer.Buffer @@ -124890,7 +127149,7 @@ SafeBuffer.allocUnsafeSlow = function (size) { return buffer.SlowBuffer(size) } -},{"buffer":179}],220:[function(require,module,exports){ +},{"buffer":178}],219:[function(require,module,exports){ // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a @@ -125019,7 +127278,7 @@ Stream.prototype.pipe = function(dest, options) { return dest; }; -},{"events":183,"inherits":186,"readable-stream/duplex.js":206,"readable-stream/passthrough.js":215,"readable-stream/readable.js":216,"readable-stream/transform.js":217,"readable-stream/writable.js":218}],221:[function(require,module,exports){ +},{"events":182,"inherits":185,"readable-stream/duplex.js":205,"readable-stream/passthrough.js":214,"readable-stream/readable.js":215,"readable-stream/transform.js":216,"readable-stream/writable.js":217}],220:[function(require,module,exports){ (function (global){ var ClientRequest = require('./lib/request') var extend = require('xtend') @@ -125101,7 +127360,7 @@ http.METHODS = [ 'UNSUBSCRIBE' ] }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"./lib/request":223,"builtin-status-codes":180,"url":227,"xtend":233}],222:[function(require,module,exports){ +},{"./lib/request":222,"builtin-status-codes":179,"url":226,"xtend":232}],221:[function(require,module,exports){ (function (global){ exports.fetch = isFunction(global.fetch) && isFunction(global.ReadableStream) @@ -125174,7 +127433,7 @@ function isFunction (value) { xhr = null // Help gc }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{}],223:[function(require,module,exports){ +},{}],222:[function(require,module,exports){ (function (process,global,Buffer){ var capability = require('./capability') var inherits = require('inherits') @@ -125484,7 +127743,7 @@ var unsafeHeaders = [ ] }).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {},require("buffer").Buffer) -},{"./capability":222,"./response":224,"_process":201,"buffer":179,"inherits":186,"readable-stream":216,"to-arraybuffer":226}],224:[function(require,module,exports){ +},{"./capability":221,"./response":223,"_process":200,"buffer":178,"inherits":185,"readable-stream":215,"to-arraybuffer":225}],223:[function(require,module,exports){ (function (process,global,Buffer){ var capability = require('./capability') var inherits = require('inherits') @@ -125670,7 +127929,7 @@ IncomingMessage.prototype._onXHRProgress = function () { } }).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {},require("buffer").Buffer) -},{"./capability":222,"_process":201,"buffer":179,"inherits":186,"readable-stream":216}],225:[function(require,module,exports){ +},{"./capability":221,"_process":200,"buffer":178,"inherits":185,"readable-stream":215}],224:[function(require,module,exports){ 'use strict'; var Buffer = require('safe-buffer').Buffer; @@ -125943,7 +128202,7 @@ function simpleWrite(buf) { function simpleEnd(buf) { return buf && buf.length ? this.write(buf) : ''; } -},{"safe-buffer":219}],226:[function(require,module,exports){ +},{"safe-buffer":218}],225:[function(require,module,exports){ var Buffer = require('buffer').Buffer module.exports = function (buf) { @@ -125972,7 +128231,7 @@ module.exports = function (buf) { } } -},{"buffer":179}],227:[function(require,module,exports){ +},{"buffer":178}],226:[function(require,module,exports){ // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a @@ -126706,7 +128965,7 @@ Url.prototype.parseHost = function() { if (host) this.hostname = host; }; -},{"./util":228,"punycode":202,"querystring":205}],228:[function(require,module,exports){ +},{"./util":227,"punycode":201,"querystring":204}],227:[function(require,module,exports){ 'use strict'; module.exports = { @@ -126724,7 +128983,7 @@ module.exports = { } }; -},{}],229:[function(require,module,exports){ +},{}],228:[function(require,module,exports){ (function (global){ /** @@ -126795,16 +129054,16 @@ function config (name) { } }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{}],230:[function(require,module,exports){ -arguments[4][186][0].apply(exports,arguments) -},{"dup":186}],231:[function(require,module,exports){ +},{}],229:[function(require,module,exports){ +arguments[4][185][0].apply(exports,arguments) +},{"dup":185}],230:[function(require,module,exports){ module.exports = function isBuffer(arg) { return arg && typeof arg === 'object' && typeof arg.copy === 'function' && typeof arg.fill === 'function' && typeof arg.readUInt8 === 'function'; } -},{}],232:[function(require,module,exports){ +},{}],231:[function(require,module,exports){ (function (process,global){ // Copyright Joyent, Inc. and other Node contributors. // @@ -127394,7 +129653,7 @@ function hasOwnProperty(obj, prop) { } }).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"./support/isBuffer":231,"_process":201,"inherits":230}],233:[function(require,module,exports){ +},{"./support/isBuffer":230,"_process":200,"inherits":229}],232:[function(require,module,exports){ module.exports = extend var hasOwnProperty = Object.prototype.hasOwnProperty; diff --git a/TaskServer/node_modules/ccxt/js/adara.js b/TaskServer/node_modules/ccxt/js/adara.js deleted file mode 100644 index d816df1c3..000000000 --- a/TaskServer/node_modules/ccxt/js/adara.js +++ /dev/null @@ -1,1255 +0,0 @@ -'use strict'; - -// --------------------------------------------------------------------------- - -const Exchange = require ('./base/Exchange'); -const { ExchangeError, BadRequest, AuthenticationError, InvalidOrder, InsufficientFunds, OrderNotFound } = require ('./base/errors'); - -// --------------------------------------------------------------------------- - -module.exports = class adara extends Exchange { - describe () { - return this.deepExtend (super.describe (), { - 'id': 'adara', - 'name': 'Adara', - 'countries': [ 'MT' ], - 'version': 'v1', - 'rateLimit': 1000, - 'certified': false, - // new metainfo interface - 'has': { - 'CORS': false, - 'fetchCurrencies': true, - 'fetchOrderBooks': false, - 'createMarketOrder': false, - 'fetchDepositAddress': false, - 'fetchClosedOrders': true, - 'fetchMyTrades': false, - 'fetchOHLCV': false, - 'fetchOrder': true, - 'fetchOpenOrders': true, - 'fetchTickers': true, - 'withdraw': false, - 'fetchDeposits': false, - 'fetchWithdrawals': false, - 'fetchTransactions': false, - }, - 'requiredCredentials': { - 'apiKey': true, - 'secret': true, - 'token': false, - }, - 'urls': { - 'logo': 'https://user-images.githubusercontent.com/1294454/49189583-0466a780-f380-11e8-9248-57a631aad2d6.jpg', - 'api': 'https://api.adara.io', - 'www': 'https://adara.io', - 'doc': 'https://api.adara.io/v1', - 'fees': 'https://adara.io/fees', - }, - 'api': { - 'public': { - 'get': [ - 'currencies', - 'limits', - 'market', - 'marketDepth', - 'marketInfo', - 'orderBook', - 'quote/', - 'quote/{id}', - 'symbols', - 'trade', - ], - 'post': [ - 'confirmContactEmail', - 'restorePassword', - 'user', // sign up - ], - }, - 'private': { - 'get': [ - 'balance', - 'order', - 'order/{id}', - 'currencyBalance', - 'apiKey', // the list of apiKeys - 'user/{id}', - ], - 'post': [ - 'order', - 'recovery', - 'user', - 'apiKey', // sign in and optionally create an apiKey - 'contact', - ], - 'patch': [ - 'order/{id}', - 'user/{id}', // change password - 'customer', // update user info - ], - 'delete': [ - 'apiKey', - ], - }, - }, - 'fees': { - 'trading': { - 'tierBased': false, - 'percentage': true, - 'maker': 0.001, - 'taker': 0.001, - }, - 'funding': { - 'tierBased': false, - 'percentage': false, - 'withdraw': {}, - 'deposit': {}, - }, - }, - 'exceptions': { - 'exact': { - 'Insufficient funds': InsufficientFunds, - 'Amount is too small': InvalidOrder, - 'operation has invalid value': InvalidOrder, - "closed order can't be changed": InvalidOrder, - 'Order is not found': OrderNotFound, - 'AUTH': AuthenticationError, - 'You are not authorized': AuthenticationError, - 'Bad Request': BadRequest, - '500': ExchangeError, - }, - 'broad': {}, - }, - }); - } - - async fetchMarkets (params = {}) { - const request = { - 'include': 'from,to', - }; - const response = await this.publicGetSymbols (this.extend (request, params)); - const included = this.safeValue (response, 'included', []); - const includedByType = this.groupBy (included, 'type'); - const currencies = this.safeValue (includedByType, 'currency', []); - const currenciesById = this.indexBy (currencies, 'id'); - // - // { meta: { total: 61 }, - // data: [ { id: "XRPUSD", - // type: "symbol", - // attributes: { allowTrade: false, - // createdAt: "2018-10-23T09:31:06.830Z", - // digits: 5, - // fullName: "XRPUSD", - // makerFee: "0.0250", - // name: "XRPUSD", - // takerFee: "0.0250", - // updatedAt: "2018-10-23T09:31:06.830Z" }, - // relationships: { from: { data: { id: "XRP", type: "currency" } }, - // to: { data: { id: "USD", type: "currency" } } } }, - // { id: "XRPETH", - // type: "symbol", - // attributes: { allowTrade: true, - // createdAt: "2018-10-09T22:34:28.268Z", - // digits: 8, - // fullName: "XRPETH", - // makerFee: "0.0025", - // name: "XRPETH", - // takerFee: "0.0025", - // updatedAt: "2018-10-09T22:34:28.268Z" }, - // relationships: { from: { data: { id: "XRP", type: "currency" } }, - // to: { data: { id: "ETH", type: "currency" } } } } ], - // included: [ { id: "XRP", - // type: "currency", - // attributes: { accuracy: 4, - // active: true, - // allowDeposit: true, - // allowTrade: false, - // allowWallet: true, - // allowWithdraw: true, - // name: "Ripple", - // shortName: "XRP", - // transactionUriTemplate: "https://www.ripplescan.com/transactions/:txId", - // walletUriTemplate: "https://www.ripplescan.com/accounts/:address", - // withdrawFee: "0.20000000", - // withdrawMinAmount: "22.00000000" }, - // relationships: { } }, - // { id: "ETH", - // type: "currency", - // attributes: { accuracy: 8, - // active: true, - // allowDeposit: true, - // allowTrade: true, - // allowWallet: true, - // allowWithdraw: true, - // name: "Ethereum", - // shortName: "ETH", - // transactionUriTemplate: "https://etherscan.io/tx/:txId", - // walletUriTemplate: "https://etherscan.io/address/:address", - // withdrawFee: "0.00800000", - // withdrawMinAmount: "0.02000000" }, - // relationships: { } }, - // { id: "USD", - // type: "currency", - // attributes: { accuracy: 6, - // active: true, - // allowDeposit: false, - // allowTrade: true, - // allowWallet: false, - // allowWithdraw: false, - // name: "USD", - // shortName: "USD", - // transactionUriTemplate: null, - // walletUriTemplate: null, - // withdrawFee: "0.00000000", - // withdrawMinAmount: "0.00000000" }, - // relationships: { } } ] } - // - const result = []; - const markets = response['data']; - for (let i = 0; i < markets.length; i++) { - const market = markets[i]; - const id = this.safeString (market, 'id'); - const attributes = this.safeValue (market, 'attributes', {}); - const relationships = this.safeValue (market, 'relationships', {}); - const fromRelationship = this.safeValue (relationships, 'from', {}); - const toRelationship = this.safeValue (relationships, 'to', {}); - const fromRelationshipData = this.safeValue (fromRelationship, 'data', {}); - const toRelationshipData = this.safeValue (toRelationship, 'data', {}); - const baseId = this.safeString (fromRelationshipData, 'id'); - const quoteId = this.safeString (toRelationshipData, 'id'); - const base = this.commonCurrencyCode (baseId); - const quote = this.commonCurrencyCode (quoteId); - const baseCurrency = this.safeValue (currenciesById, baseId, {}); - const baseCurrencyAttributes = this.safeValue (baseCurrency, 'attributes', {}); - const symbol = base + '/' + quote; - const amountPrecision = this.safeInteger (baseCurrencyAttributes, 'accuracy', 8); - const pricePrecision = this.safeInteger (attributes, 'digits', 8); - const precision = { - 'amount': amountPrecision, - 'price': pricePrecision, - }; - const active = this.safeValue (attributes, 'allowTrade'); - const maker = this.safeFloat (attributes, 'makerFee'); - const taker = this.safeFloat (attributes, 'takerFee'); - result.push ({ - 'info': market, - 'id': id, - 'symbol': symbol, - 'base': base, - 'quote': quote, - 'baseId': baseId, - 'quoteId': quoteId, - 'active': active, - 'maker': maker, - 'taker': taker, - 'precision': precision, - 'limits': { - 'amount': { - 'min': Math.pow (10, -precision['amount']), - 'max': undefined, - }, - 'price': { - 'min': Math.pow (10, -precision['price']), - 'max': undefined, - }, - 'cost': { - 'min': undefined, - 'max': undefined, - }, - }, - }); - } - return result; - } - - async fetchCurrencies (params = {}) { - const response = await this.publicGetCurrencies (params); - // - // { meta: { total: 22 }, - // data: [ { id: "USD", - // type: "currency", - // attributes: { accuracy: 6, - // active: true, - // allowDeposit: false, - // allowTrade: true, - // allowWallet: false, - // allowWithdraw: false, - // name: "USD", - // shortName: "USD", - // transactionUriTemplate: null, - // walletUriTemplate: null, - // withdrawFee: "0.00000000", - // withdrawMinAmount: "0.00000000" }, - // relationships: { } }, - // { id: "BTC", - // type: "currency", - // attributes: { accuracy: 8, - // active: true, - // allowDeposit: true, - // allowTrade: true, - // allowWallet: true, - // allowWithdraw: true, - // name: "Bitcoin", - // shortName: "BTC", - // transactionUriTemplate: "https://blockexplorer.com/tx/:txId", - // walletUriTemplate: "https://blockexplorer.com/address/:address", - // withdrawFee: "0.00050000", - // withdrawMinAmount: "0.00200000" }, - // relationships: { } } ], - // included: [] } - // - const currencies = response['data']; - const result = {}; - for (let i = 0; i < currencies.length; i++) { - const currency = currencies[i]; - const id = this.safeString (currency, 'id'); - const attributes = this.safeValue (currency, 'attributes', {}); - const code = this.commonCurrencyCode (id); - const precision = this.safeInteger (attributes, 'accuracy'); - const fee = this.safeFloat (attributes, 'withdrawFee'); - const active = this.safeValue (attributes, 'active'); - const allowDeposit = this.safeValue (attributes, 'allowDeposit'); - const allowWithdraw = this.safeValue (attributes, 'allowWithdraw'); - result[code] = { - 'id': id, - 'code': code, - 'info': currency, - 'name': this.safeString (attributes, 'name'), - 'active': (active && allowDeposit && allowWithdraw), - 'fee': fee, - 'precision': precision, - 'limits': { - 'amount': { - 'min': Math.pow (10, -precision), - 'max': Math.pow (10, precision), - }, - 'price': { - 'min': Math.pow (10, -precision), - 'max': Math.pow (10, precision), - }, - 'cost': { - 'min': undefined, - 'max': undefined, - }, - 'withdraw': { - 'min': this.safeFloat (attributes, 'withdrawMinAmount'), - 'max': Math.pow (10, precision), - }, - }, - }; - } - return result; - } - - async fetchBalance (params = {}) { - await this.loadMarkets (); - const response = await this.privateGetBalance (params); - // - // { data: [ { type: "balance", - // id: "U4f0f0940-39bf-45a8-90bc-12d2899db4f1_BALANCE_FOR_ETH", - // attributes: { totalBalance: 10000, - // onOrders: 0, - // normalizedTotalBalance: 310, - // normalizedOnOrders: 0, - // percentage: 3.004116443856034, - // serializedAt: 1543324487949 }, - // relationships: { currency: { data: { type: "currency", id: "ETH" } }, - // normalizedCurrency: { data: { type: "currency", id: "BTC" } } } } ], - // included: [ { type: "currency", - // id: "BTC", - // attributes: { name: "Bitcoin", - // shortName: "BTC", - // active: true, - // accuracy: 8, - // allowDeposit: true, - // allowWithdraw: true, - // allowWallet: true, - // allowTrade: true, - // serializedAt: 1543324487948 }, - // relationships: { } }, - // { type: "currency", - // id: "ETH", - // attributes: { name: "Ethereum", - // shortName: "ETH", - // active: true, - // accuracy: 8, - // allowDeposit: true, - // allowWithdraw: true, - // allowWallet: true, - // allowTrade: true, - // serializedAt: 1543324487948 } } ] } - // - const result = { 'info': response }; - const data = this.safeValue (response, 'data'); - if (data !== undefined) { - for (let i = 0; i < data.length; i++) { - const balance = data[i]; - const attributes = this.safeValue (balance, 'attributes', {}); - const relationships = this.safeValue (balance, 'relationships', {}); - const currencyRelationship = this.safeValue (relationships, 'currency', {}); - const currencyRelationshipData = this.safeValue (currencyRelationship, 'data'); - const currencyId = this.safeString (currencyRelationshipData, 'id'); - const code = this.commonCurrencyCode (currencyId); - const account = this.account (); - account['total'] = this.safeFloat (attributes, 'totalBalance'); - account['used'] = this.safeFloat (attributes, 'onOrders'); - result[code] = account; - } - } - return this.parseBalance (result); - } - - getSymbolFromMarketId (marketId, market = undefined) { - if (marketId === undefined) { - return undefined; - } - market = this.safeValue (this.markets_by_id, marketId, market); - if (market !== undefined) { - return market['symbol']; - } - const [ baseId, quoteId ] = marketId.split ('-'); - const base = this.commonCurrencyCode (baseId); - const quote = this.commonCurrencyCode (quoteId); - return base + '/' + quote; - } - - parseOrderBook (orderbook, timestamp = undefined, bidsKey = 'bids', asksKey = 'asks', priceKey = 'price', amountKey = 'amount') { - const bids = []; - const asks = []; - const numBidAsks = orderbook.length; - if (numBidAsks > 0) { - timestamp = this.safeInteger (orderbook[0]['attributes'], 'serializedAt'); - } - for (let i = 0; i < orderbook.length; i++) { - const bidask = orderbook[i]; - const attributes = this.safeValue (bidask, 'attributes', {}); - const currenTimestamp = this.safeInteger (attributes, 'serializedAt'); - timestamp = Math.max (timestamp, currenTimestamp); - const id = this.safeString (bidask, 'id'); - if (id.indexOf ('OBID') >= 0) { - bids.push (this.parseBidAsk (bidask['attributes'], priceKey, amountKey)); - } else if (id.indexOf ('OSID') >= 0) { - asks.push (this.parseBidAsk (bidask['attributes'], priceKey, amountKey)); - } else { - throw new ExchangeError (this.id + ' parseOrderBook encountered an unrecognized bidask format: ' + this.json (bidask)); - } - } - return { - 'bids': this.sortBy (bids, 0, true), - 'asks': this.sortBy (asks, 0), - 'timestamp': timestamp, - 'datetime': this.iso8601 (timestamp), - 'nonce': undefined, - }; - } - - async fetchOrderBook (symbol, limit = undefined, params = {}) { - await this.loadMarkets (); - const market = this.market (symbol); - const filters = 'filters[symbol]'; - const request = {}; - request[filters] = market['id']; - const response = await this.publicGetOrderBook (this.extend (request, params)); - // - // { data: [ { type: "orderBook", - // id: "OBID0SLTCETHS0", - // attributes: { price: 1, - // amount: 4, - // serializedAt: 1543116143473 } }, - // { type: "orderBook", - // id: "OSID3SLTCETHS0", - // attributes: { price: 12, - // amount: 12, - // serializedAt: 1543116143474 } } ] } - // - return this.parseOrderBook (response['data'], undefined, 'bids', 'asks', 'price', 'amount'); - } - - parseTicker (ticker, market = undefined) { - // - // { type: "quote", - // id: "XRPETH", - // attributes: { currentPrice: 1, - // low: 1, - // high: 1, - // baseVolume: 0, - // quoteVolume: 0, - // change: 0, - // percentChange: 0, - // serializedAt: 1543109275996 }, - // relationships: { symbol: { data: { type: "symbol", id: "ETHBTC" } } } } - // - const symbol = this.getSymbolFromMarketId (this.safeString (ticker, 'id'), market); - const attributes = this.safeValue (ticker, 'attributes', {}); - const timestamp = this.safeInteger (attributes, 'serializedAt'); - const last = this.safeFloat (attributes, 'currentPrice'); - const change = this.safeFloat (attributes, 'change'); - let open = undefined; - if (change !== undefined) { - if (last !== undefined) { - open = last - change; - } - } - const percentage = this.safeFloat (attributes, 'percentChange'); - return { - 'symbol': symbol, - 'timestamp': timestamp, - 'datetime': this.iso8601 (timestamp), - 'high': this.safeFloat (attributes, 'high'), - 'low': this.safeFloat (attributes, 'low'), - 'bid': undefined, - 'bidVolume': undefined, - 'ask': undefined, - 'askVolume': undefined, - 'vwap': undefined, - 'open': open, - 'close': last, - 'last': last, - 'previousClose': undefined, - 'change': change, - 'percentage': percentage, - 'average': undefined, - 'baseVolume': this.safeFloat (ticker, 'baseVolume'), - 'quoteVolume': this.safeFloat (ticker, 'quoteVolume'), - 'info': ticker, - }; - } - - async fetchTickers (symbols = undefined, params = {}) { - await this.loadMarkets (); - const response = await this.publicGetQuote (params); - const data = this.safeValue (response, 'data', []); - // - // { data: [ { type: "quote", - // id: "XRPETH", - // attributes: { currentPrice: 1, - // low: 1, - // high: 1, - // baseVolume: 0, - // quoteVolume: 0, - // change: 0, - // percentChange: 0, - // serializedAt: 1543109275996 }, - // relationships: { symbol: { data: { type: "symbol", id: "ETHBTC" } } } } ], - // included: [ { type: "currency", - // id: "XRP", - // attributes: { name: "Ripple", - // shortName: "XRP", - // active: true, - // accuracy: 4, - // allowDeposit: true, - // allowWithdraw: true, - // allowWallet: true, - // allowTrade: false, - // serializedAt: 1543109275996 }, - // relationships: { } }, - // { type: "symbol", - // id: "XRPETH", - // attributes: { fullName: "XRPETH", - // digits: 8, - // allowTrade: true, - // serializedAt: 1543109275996 }, - // relationships: { from: { data: { type: "currency", id: "XRP" } }, - // to: { data: { type: "currency", id: "ETH" } } } } ] } - // - const result = {}; - for (let t = 0; t < data.length; t++) { - const ticker = this.parseTicker (data[t]); - const symbol = ticker['symbol']; - result[symbol] = ticker; - } - return result; - } - - async fetchTicker (symbol, params = {}) { - await this.loadMarkets (); - const market = this.market (symbol); - const request = { - 'id': market['id'], - }; - const response = await this.publicGetQuoteId (this.extend (request, params)); - // - // { included: [ { type: "currency", - // id: "ETH", - // attributes: { name: "Ethereum", - // shortName: "ETH", - // active: true, - // accuracy: 8, - // allowDeposit: true, - // allowWithdraw: true, - // allowWallet: true, - // allowTrade: true, - // serializedAt: 1543111444033 } }, - // { type: "currency", - // id: "BTC", - // attributes: { name: "Bitcoin", - // shortName: "BTC", - // active: true, - // accuracy: 8, - // allowDeposit: true, - // allowWithdraw: true, - // allowWallet: true, - // allowTrade: true, - // serializedAt: 1543111444033 } }, - // { type: "symbol", - // id: "ETHBTC", - // attributes: { fullName: "ETHBTC", - // digits: 6, - // allowTrade: true, - // serializedAt: 1543111444033 }, - // relationships: { from: { data: { type: "currency", id: "ETH" } }, - // to: { data: { type: "currency", id: "BTC" } } } } ], - // data: { type: "quote", - // id: "ETHBTC", - // attributes: { currentPrice: 34, - // low: 34, - // high: 34, - // baseVolume: 0, - // quoteVolume: 0, - // change: 0, - // percentChange: 0, - // serializedAt: 1543111444033 }, - // relationships: { symbol: { data: { type: "symbol", id: "ETHBTC" } } } } } (fetchTicker @ adara.js:546) - // - return this.parseTicker (response['data']); - } - - parseTrade (trade, market = undefined) { - // - // fetchTrades - // - // - // { type: "trade", - // id: "1542988964359136846136847", - // attributes: { price: 34, - // amount: 4, - // total: 136, - // operation: "buy", - // createdAt: "2018-11-23T16:02:44.359Z", - // serializedAt: 1543112364995 }, - // relationships: { symbol: { data: { type: "symbol", id: "ETHBTC" } } } } ], - // - const id = this.safeString (trade, 'id', 'uuid'); - const attributes = this.safeValue (trade, 'attributes', {}); - const relationships = this.safeValue (trade, 'relationships', {}); - const symbolRelationship = this.safeValue (relationships, 'symbol', {}); - const symbolRelationshipData = this.safeValue (symbolRelationship, 'data', {}); - const marketId = this.safeString (symbolRelationshipData, 'id'); - market = this.safeValue (this.markets_by_id, marketId, market); - let symbol = undefined; - let feeCurrency = undefined; - if (market !== undefined) { - symbol = market['symbol']; - feeCurrency = market['quote']; - } else if (marketId !== undefined) { - const baseIdLength = marketId.length - 3; - const baseId = marketId.slice (0, baseIdLength); - const quoteId = marketId.slice (baseIdLength); - const base = this.commonCurrencyCode (baseId); - const quote = this.commonCurrencyCode (quoteId); - symbol = base + '/' + quote; - feeCurrency = quote; - } - const orderId = undefined; - const timestamp = this.parse8601 (this.safeString (attributes, 'createdAt')); - const side = this.safeString (attributes, 'operation'); - const price = this.safeFloat (attributes, 'price'); - const amount = this.safeFloat (attributes, 'amount'); - let cost = this.safeFloat (attributes, 'total'); - if (cost === undefined) { - if (amount !== undefined) { - if (price !== undefined) { - cost = parseFloat (this.costToPrecision (symbol, price * amount)); - } - } - } - const feeCost = this.safeFloat (attributes, 'fee'); - let fee = undefined; - if (feeCost !== undefined) { - fee = { - 'cost': feeCost, - 'currency': feeCurrency, - }; - } - return { - 'id': id, - 'info': trade, - 'order': orderId, - 'timestamp': timestamp, - 'datetime': this.iso8601 (timestamp), - 'symbol': symbol, - 'type': undefined, - 'side': side, - 'takerOrMaker': undefined, - 'price': price, - 'amount': amount, - 'cost': cost, - 'fee': fee, - }; - } - - async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) { - await this.loadMarkets (); - let market = undefined; - if (symbol !== undefined) { - market = this.market (symbol); - } - const request = { - // 'id': market['id'], - }; - const response = await this.publicGetTrade (this.extend (request, params)); - // - // { data: [ { type: "trade", - // id: "1542988964359136846136847", - // attributes: { price: 34, - // amount: 4, - // total: 136, - // operation: "buy", - // createdAt: "2018-11-23T16:02:44.359Z", - // serializedAt: 1543112364995 }, - // relationships: { symbol: { data: { type: "symbol", id: "ETHBTC" } } } } ], - // included: [ { type: "currency", - // id: "ETH", - // attributes: { name: "Ethereum", - // shortName: "ETH", - // active: true, - // accuracy: 8, - // allowDeposit: true, - // allowWithdraw: true, - // allowWallet: true, - // allowTrade: true, - // serializedAt: 1543112364995 }, - // relationships: { } }, - // { type: "currency", - // id: "BTC", - // attributes: { name: "Bitcoin", - // ... - // serializedAt: 1543112364995 }, - // relationships: { } }, - // { type: "symbol", - // id: "ETHBTC", - // attributes: { fullName: "ETHBTC", - // digits: 6, - // allowTrade: true, - // serializedAt: 1543112364995 }, - // relationships: { from: { data: { type: "currency", id: "ETH" } }, - // to: { data: { type: "currency", id: "BTC" } } } } } - // - return this.parseTrades (response['data'], market, since, limit); - } - - async createOrder (symbol, type, side, amount, price = undefined, params = {}) { - await this.loadMarkets (); - const market = this.market (symbol); - const request = { - 'data': { - 'type': 'order', - 'attributes': { - 'amount': parseFloat (this.amountToPrecision (symbol, amount)), - 'operation': side, - 'orderType': type, - 'price': parseFloat (this.priceToPrecision (symbol, price)), - }, - 'relationships': { - 'symbol': { - 'data': { - 'id': market['id'], - 'type': 'symbol', - }, - }, - }, - }, - 'included': [ - { - 'id': market['id'], - 'type': 'symbol', - }, - ], - }; - const response = await this.privatePostOrder (this.extend (request, params)); - // - // { included: [ { type: "currency", - // id: "XLM", - // attributes: { name: "Stellar", - // shortName: "XLM", - // active: true, - // accuracy: 8, - // allowDeposit: true, - // allowWithdraw: true, - // allowWallet: true, - // allowTrade: false, - // serializedAt: 1543434477449 } }, - // { type: "currency", - // id: "BTC", - // attributes: { name: "Bitcoin", - // shortName: "BTC", - // active: true, - // accuracy: 8, - // allowDeposit: true, - // allowWithdraw: true, - // allowWallet: true, - // allowTrade: true, - // serializedAt: 1543434477449 } }, - // { type: "symbol", - // id: "XLMBTC", - // attributes: { fullName: "XLMBTC", - // digits: 6, - // allowTrade: true, - // serializedAt: 1543434477449 }, - // relationships: { from: { data: { type: "currency", id: "XLM" } }, - // to: { data: { type: "currency", id: "BTC" } } } } ], - // data: { type: "order", - // id: "34793", - // attributes: { serializedAt: 1543434477449, - // operation: "buy", - // orderType: "limit", - // clientId: "4733ea40-7d5c-4ddc-aec5-eb41baf90555", - // amount: 220, - // price: 0.000035, - // averagePrice: 0, - // fee: 0, - // timeOpen: "2018-11-28T19:47:57.435Z", - // timeClose: null, - // status: "open", - // filled: 0, - // flags: [] }, - // relationships: { symbol: { data: { type: "symbol", id: "XLMBTC" } } } } } - // - return this.parseOrder (response['data']); - } - - async cancelOrder (id, symbol = undefined, params = {}) { - await this.loadMarkets (); - const request = { - 'id': id, - 'data': { - 'attributes': { - 'status': 'canceled', - }, - }, - }; - const response = await this.privatePatchOrderId (this.extend (request, params)); - // - // { included: [ { type: "currency", - // id: "XLM", - // attributes: { name: "Stellar", - // shortName: "XLM", - // active: true, - // accuracy: 8, - // allowDeposit: true, - // allowWithdraw: true, - // allowWallet: true, - // allowTrade: false, - // serializedAt: 1543437874742 } }, - // { type: "currency", - // id: "BTC", - // attributes: { name: "Bitcoin", - // shortName: "BTC", - // active: true, - // accuracy: 8, - // allowDeposit: true, - // allowWithdraw: true, - // allowWallet: true, - // allowTrade: true, - // serializedAt: 1543437874742 } }, - // { type: "symbol", - // id: "XLMBTC", - // attributes: { fullName: "XLMBTC", - // digits: 6, - // allowTrade: true, - // serializedAt: 1543437874742 }, - // relationships: { from: { data: { type: "currency", id: "XLM" } }, - // to: { data: { type: "currency", id: "BTC" } } } } ], - // data: { type: "order", - // id: "34794", - // attributes: { serializedAt: 1543437874742, - // operation: "buy", - // orderType: "limit", - // clientId: "4733ea40-7d5c-4ddc-aec5-eb41baf90555", - // amount: 110, - // price: 0.000034, - // averagePrice: 0, - // fee: 0, - // timeOpen: "2018-11-28T20:42:35.486Z", - // timeClose: null, - // status: "canceled", - // filled: 0, - // flags: [] }, - // relationships: { symbol: { data: { type: "symbol", id: "XLMBTC" } } } } } - // - return this.parseOrder (response['data']); - } - - parseOrderStatus (status) { - const statuses = { - 'open': 'open', - 'closed': 'closed', - 'canceled': 'canceled', - }; - return this.safeString (statuses, status, status); - } - - parseOrder (order, market = undefined) { - // - // { type: "order", - // id: "34793", - // attributes: { serializedAt: 1543435013349, - // operation: "buy", - // orderType: "limit", - // clientId: "4733ea40-7d5c-4ddc-aec5-eb41baf90555", - // amount: 220, - // price: 0.000035, - // averagePrice: 0.000035, - // fee: 0.0001925, - // timeOpen: "2018-11-28T19:47:57.435Z", - // timeClose: "2018-11-28T19:47:57.452Z", - // status: "closed", - // filled: 220, - // flags: null }, - // relationships: { symbol: { data: { type: "symbol", id: "XLMBTC" } } } } - // - const id = this.safeString (order, 'id'); - const attributes = this.safeValue (order, 'attributes', {}); - const relationships = this.safeValue (order, 'relationships', {}); - const symbolRelationship = this.safeValue (relationships, 'symbol', {}); - const symbolRelationshipData = this.safeValue (symbolRelationship, 'data', {}); - const tradesRelationship = this.safeValue (relationships, 'trades', {}); - const tradesRelationshipData = this.safeValue (tradesRelationship, 'data'); - const marketId = this.safeString (symbolRelationshipData, 'id'); - market = this.safeValue (this.markets_by_id, marketId, market); - let feeCurrency = undefined; - let symbol = undefined; - if (market !== undefined) { - symbol = market['symbol']; - feeCurrency = market['quote']; - } else if (marketId !== undefined) { - const baseIdLength = marketId.length - 3; - const baseId = marketId.slice (0, baseIdLength); - const quoteId = marketId.slice (baseIdLength); - const base = this.commonCurrencyCode (baseId); - const quote = this.commonCurrencyCode (quoteId); - symbol = base + '/' + quote; - feeCurrency = quote; - } - const timestamp = this.parse8601 (this.safeString (attributes, 'timeOpen')); - const side = this.safeString (attributes, 'operation'); - const type = this.safeString (attributes, 'orderType'); - const status = this.parseOrderStatus (this.safeString (attributes, 'status')); - const lastTradeTimestamp = this.parse8601 (this.safeString (attributes, 'timeClose')); - const price = this.safeFloat (attributes, 'price'); - const amount = this.safeFloat (attributes, 'amount'); - const filled = this.safeFloat (attributes, 'filled'); - let remaining = undefined; - if (amount !== undefined) { - if (filled !== undefined) { - remaining = Math.max (0, amount - filled); - } - } - let cost = undefined; - const average = this.safeFloat (attributes, 'averagePrice'); - if (cost === undefined) { - if ((average !== undefined) && (filled !== undefined)) { - cost = parseFloat (this.costToPrecision (symbol, average * filled)); - } - } - let fee = undefined; - const feeCost = this.safeFloat (attributes, 'fee'); - if (feeCost !== undefined) { - fee = { - 'currency': feeCurrency, - 'cost': feeCost, - }; - } - let trades = undefined; - if (tradesRelationshipData !== undefined) { - const numTrades = tradesRelationshipData.length; - if (numTrades > 0) { - trades = this.parseTrades (tradesRelationshipData, market); - } - } - const result = { - 'info': order, - 'id': id, - 'clientOrderId': undefined, - 'timestamp': timestamp, - 'datetime': this.iso8601 (timestamp), - 'lastTradeTimestamp': lastTradeTimestamp, - 'symbol': symbol, - 'type': type, - 'side': side, - 'price': price, - 'cost': cost, - 'average': average, - 'amount': amount, - 'filled': filled, - 'remaining': remaining, - 'status': status, - 'fee': fee, - 'trades': trades, - }; - return result; - } - - async fetchOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) { - await this.loadMarkets (); - const request = { - 'include': 'trades', - }; - let market = undefined; - if (symbol !== undefined) { - market = this.market (symbol); - const filters = 'filters[symbol]'; - request[filters] = market['id']; - } - const response = await this.privateGetOrder (this.extend (request, params)); - // - // { data: [ { type: "order", - // id: "34793", - // attributes: { serializedAt: 1543436770259, - // operation: "buy", - // orderType: "limit", - // amount: 220, - // price: 0.000035, - // averagePrice: 0.000035, - // fee: 0.0001925, - // timeOpen: "2018-11-28T19:47:57.435Z", - // timeClose: "2018-11-28T19:47:57.452Z", - // status: "closed", - // filled: 220, - // flags: null }, - // relationships: { symbol: { data: { type: "symbol", id: "XLMBTC" } }, - // trades: { data: [{ type: "trade", id: "34789_34793" }] } } } ], - // included: [ { type: "currency", - // id: "XLM", - // attributes: { name: "Stellar", - // shortName: "XLM", - // active: true, - // accuracy: 8, - // allowDeposit: true, - // allowWithdraw: true, - // allowWallet: true, - // allowTrade: false, - // serializedAt: 1543436770259 } }, - // { type: "currency", - // id: "BTC", - // attributes: { name: "Bitcoin", - // shortName: "BTC", - // active: true, - // accuracy: 8, - // allowDeposit: true, - // allowWithdraw: true, - // allowWallet: true, - // allowTrade: true, - // serializedAt: 1543436770259 } }, - // { type: "symbol", - // id: "XLMBTC", - // attributes: { fullName: "XLMBTC", - // digits: 6, - // allowTrade: true, - // serializedAt: 1543436770259 }, - // relationships: { from: { data: { type: "currency", id: "XLM" } }, - // to: { data: { type: "currency", id: "BTC" } } } }, - // { type: "trade", - // id: "34789_34793", - // attributes: { fee: 0.0001925, - // price: 0.000035, - // amount: 220, - // total: 0.0077, - // operation: "buy", - // createdAt: "2018-11-28T19:47:57.451Z" } } ], - // meta: { total: 1 } } - // - return this.parseOrdersResponse (response, market, since, limit); - } - - async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) { - const filters = 'filters[status][]'; - const request = {}; - request[filters] = 'open'; - return await this.fetchOrders (symbol, since, limit, this.extend (request, params)); - } - - async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) { - const filters = 'filters[status][]'; - const request = {}; - request[filters] = 'closed'; - return await this.fetchOrders (symbol, since, limit, this.extend (request, params)); - } - - parseOrdersResponse (response, market = undefined, since = undefined, limit = undefined) { - const included = this.safeValue (response, 'included', []); - const includedByType = this.groupBy (included, 'type'); - const unparsedTrades = this.safeValue (includedByType, 'trade', []); - const trades = this.parseTrades (unparsedTrades, market); - const tradesById = this.indexBy (trades, 'id'); - const orders = this.parseOrders (this.safeValue (response, 'data', []), market, since, limit); - const result = []; - for (let i = 0; i < orders.length; i++) { - const order = orders[i]; - const orderTrades = []; - const orderFee = this.safeValue (order, 'fee', {}); - const orderFeeCurrency = this.safeString (orderFee, 'currency'); - if (order['trades'] !== undefined) { - for (let j = 0; j < order['trades'].length; j++) { - const orderTrade = order['trades'][j]; - const orderTradeId = orderTrade['id']; - if (orderTradeId in tradesById) { - orderTrades.push (this.deepExtend (tradesById[orderTradeId], { - 'order': order['id'], - 'type': order['type'], - 'symbol': order['symbol'], - 'fee': { - 'currency': orderFeeCurrency, - }, - })); - } - } - } - const numOrderTrades = orderTrades.length; - if (numOrderTrades > 0) { - order['trades'] = orderTrades; - } - result.push (order); - } - return result; - } - - async fetchOrder (id, symbol = undefined, params = {}) { - await this.loadMarkets (); - const request = { - 'id': id, - 'include': 'trades', - }; - const response = await this.privateGetOrderId (this.extend (request, params)); - // - // { included: [ { type: "currency", - // id: "XLM", - // attributes: { name: "Stellar", - // shortName: "XLM", - // active: true, - // accuracy: 8, - // allowDeposit: true, - // allowWithdraw: true, - // allowWallet: true, - // allowTrade: false, - // serializedAt: 1543436451996 } }, - // { type: "currency", - // id: "BTC", - // attributes: { name: "Bitcoin", - // shortName: "BTC", - // active: true, - // accuracy: 8, - // allowDeposit: true, - // allowWithdraw: true, - // allowWallet: true, - // allowTrade: true, - // serializedAt: 1543436451996 } }, - // { type: "symbol", - // id: "XLMBTC", - // attributes: { fullName: "XLMBTC", - // digits: 6, - // allowTrade: true, - // serializedAt: 1543436451996 }, - // relationships: { from: { data: { type: "currency", id: "XLM" } }, - // to: { data: { type: "currency", id: "BTC" } } } }, - // { type: "trade", - // id: "34789_34793", - // attributes: { fee: 0.0001925, - // price: 0.000035, - // amount: 220, - // total: 0.0077, - // operation: "buy", - // createdAt: "2018-11-28T19:47:57.451Z" } } ], - // data: { type: "order", - // id: "34793", - // attributes: { serializedAt: 1543436451996, - // operation: "buy", - // orderType: "limit", - // clientId: "4733ea40-7d5c-4ddc-aec5-eb41baf90555", - // amount: 220, - // price: 0.000035, - // averagePrice: 0.000035, - // fee: 0.0001925, - // timeOpen: "2018-11-28T19:47:57.435Z", - // timeClose: "2018-11-28T19:47:57.452Z", - // status: "closed", - // filled: 220, - // flags: null }, - // relationships: { symbol: { data: { type: "symbol", id: "XLMBTC" } }, - // trades: { data: [{ type: "trade", id: "34789_34793" }] } } } } - // - const data = this.safeValue (response, 'data'); - response['data'] = []; - response['data'].push (data); - const orders = this.parseOrdersResponse (response); - const ordersById = this.indexBy (orders, 'id'); - if (id in ordersById) { - return ordersById[id]; - } - throw new OrderNotFound (this.id + ' fetchOrder could not find order id ' + id.toString ()); - } - - nonce () { - return this.milliseconds (); - } - - sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) { - let payload = '/' + this.implodeParams (path, params); - let url = this.urls['api'] + '/' + this.version + payload; - const query = this.omit (params, this.extractParams (path)); - if (method === 'GET') { - if (Object.keys (query).length) { - url += '?' + this.urlencode (query); - } - } - if (api === 'private') { - const nonce = this.nonce (); - let expiredAt = this.sum (nonce, this.safeInteger (this.options, 'expiredAt', 10000)); - expiredAt = expiredAt.toString (); - if ((method === 'POST') || (method === 'PATCH')) { - body = this.json (query); - payload = body; - } - if (this.token) { - headers = { - 'Cookie': 'token=' + this.token, - }; - } else { - this.checkRequiredCredentials (); - const auth = method + payload + 'expiredAt=' + expiredAt; - const signature = this.hmac (this.encode (auth), this.encode (this.secret), 'sha512', 'base64'); - headers = { - 'X-ADX-EXPIRE': expiredAt, - 'X-ADX-APIKEY': this.apiKey, - 'X-ADX-SIGNATURE': signature, - }; - } - if (method !== 'GET') { - headers['Content-Type'] = 'application/json'; - } - } - return { 'url': url, 'method': method, 'body': body, 'headers': headers }; - } - - handleErrors (code, reason, url, method, headers, body, response, requestHeaders, requestBody) { - if (response === undefined) { - return; // fallback to default error handler - } - const errors = this.safeValue (response, 'errors', []); - const numErrors = errors.length; - if (numErrors > 0) { - const error = errors[0]; - const code = this.safeString (error, 'code'); - const status = this.safeString (error, 'status'); - const title = this.safeString (error, 'title'); - const detail = this.safeString (error, 'detail'); - const feedback = this.id + ' ' + this.json (response); - this.throwExactlyMatchedException (this.exceptions['exact'], code, feedback); - this.throwExactlyMatchedException (this.exceptions['exact'], status, feedback); - this.throwExactlyMatchedException (this.exceptions['exact'], title, feedback); - this.throwExactlyMatchedException (this.exceptions['exact'], detail, feedback); - this.throwBroadlyMatchedException (this.exceptions['broad'], body, feedback); - throw new ExchangeError (feedback); // unknown message - } - } -}; diff --git a/TaskServer/node_modules/ccxt/js/aofex.js b/TaskServer/node_modules/ccxt/js/aofex.js index f5e72f678..779d280c7 100644 --- a/TaskServer/node_modules/ccxt/js/aofex.js +++ b/TaskServer/node_modules/ccxt/js/aofex.js @@ -30,6 +30,7 @@ module.exports = class aofex extends Exchange { 'fetchOpenOrders': true, 'fetchClosedOrders': true, 'fetchClosedOrder': true, + 'fetchOrderTrades': true, 'fetchTradingFee': true, }, 'timeframes': { @@ -559,7 +560,7 @@ module.exports = class aofex extends Exchange { // const id = this.safeString (trade, 'id'); const ctime = this.parse8601 (this.safeString (trade, 'ctime')); - const timestamp = this.safeTimestamp (trade, 'ts', ctime); + const timestamp = this.safeTimestamp (trade, 'ts', ctime) - 28800000; // 8 hours, adjust to UTC; let symbol = undefined; if ((symbol === undefined) && (market !== undefined)) { symbol = market['symbol']; @@ -725,7 +726,7 @@ module.exports = class aofex extends Exchange { base = market['base']; quote = market['quote']; } - const timestamp = this.parse8601 (this.safeString (order, 'ctime')); + const timestamp = this.parse8601 (this.safeString (order, 'ctime')) - 28800000; // 8 hours, adjust to UTC const orderType = this.safeString (order, 'type'); const type = (orderType === '2') ? 'limit' : 'market'; const side = this.safeString (order, 'side'); @@ -883,11 +884,16 @@ module.exports = class aofex extends Exchange { return this.parseOrder (order); } + async fetchOrderTrades (id, symbol = undefined, since = undefined, limit = undefined, params = {}) { + const response = await this.fetchClosedOrder (id, symbol, params); + return this.safeValue (response, 'trades', []); + } + async fetchOrdersWithMethod (method, symbol = undefined, since = undefined, limit = undefined, params = {}) { await this.loadMarkets (); const request = { // 'from': 'BM7442641584965237751ZMAKJ5', // query start order_sn - // 'direct': 'prev', // next + 'direct': 'prev', // next }; let market = undefined; if (symbol !== undefined) { diff --git a/TaskServer/node_modules/ccxt/js/base/Exchange.js b/TaskServer/node_modules/ccxt/js/base/Exchange.js index 52cdf8b0e..f818dd8a6 100644 --- a/TaskServer/node_modules/ccxt/js/base/Exchange.js +++ b/TaskServer/node_modules/ccxt/js/base/Exchange.js @@ -288,8 +288,9 @@ module.exports = class Exchange { const config = deepExtend (this.describe (), userConfig) // merge to this - for (const [property, value] of Object.entries (config)) + for (const [property, value] of Object.entries (config)) { this[property] = deepExtend (this[property], value) + } if (!this.httpAgent) { this.httpAgent = defaultFetch.http ? new defaultFetch.http.Agent ({ 'keepAlive': true }) : undefined @@ -304,13 +305,15 @@ module.exports = class Exchange { this['has' + capitalize (k)] = !!this.has[k] // converts 'emulated' to true } - if (this.api) + if (this.api) { this.defineRestApi (this.api, 'request') + } this.initRestRateLimiter () - if (this.markets) + if (this.markets) { this.setMarkets (this.markets) + } } defaults () { @@ -342,20 +345,23 @@ module.exports = class Exchange { checkAddress (address) { - if (address === undefined) + if (address === undefined) { throw new InvalidAddress (this.id + ' address is undefined') + } // check the address is not the same letter like 'aaaaa' nor too short nor has a space - if ((unique (address).length === 1) || address.length < this.minFundingAddressLength || address.includes (' ')) + if ((unique (address).length === 1) || address.length < this.minFundingAddressLength || address.includes (' ')) { throw new InvalidAddress (this.id + ' address is invalid or has less than ' + this.minFundingAddressLength.toString () + ' characters: "' + this.json (address) + '"') + } return address } initRestRateLimiter () { - if (this.rateLimit === undefined) + if (this.rateLimit === undefined) { throw new Error (this.id + '.rateLimit property is not configured') + } this.tokenBucket = this.extend ({ delay: 1, @@ -386,15 +392,17 @@ module.exports = class Exchange { const promise = fetchImplementation (url, this.extend (params, this.fetchOptions)) .catch ((e) => { - if (isNode) + if (isNode) { throw new ExchangeNotAvailable ([ this.id, method, url, e.type, e.message ].join (' ')) + } throw e // rethrow all unknown errors }) - .then (response => this.handleRestResponse (response, url, method, headers, body)) + .then ((response) => this.handleRestResponse (response, url, method, headers, body)) return timeout (this.timeout, promise).catch ((e) => { - if (e instanceof TimedOut) + if (e instanceof TimedOut) { throw new RequestTimeout (this.id + ' ' + method + ' ' + url + ' request timed out (' + this.timeout + ' ms)') + } throw e }) } @@ -442,16 +450,20 @@ module.exports = class Exchange { let underscore = type + '_' + lowercaseMethod + '_' + underscoreSuffix if ('suffixes' in options) { - if ('camelcase' in options['suffixes']) + if ('camelcase' in options['suffixes']) { camelcase += options['suffixes']['camelcase'] - if ('underscore' in options.suffixes) + } + if ('underscore' in options.suffixes) { underscore += options['suffixes']['underscore'] + } } - if ('underscore_suffix' in options) + if ('underscore_suffix' in options) { underscore += options.underscoreSuffix; - if ('camelcase_suffix' in options) + } + if ('camelcase_suffix' in options) { camelcase += options.camelcaseSuffix; + } let partial = async params => this[methodName] (path, type, uppercaseMethod, params || {}) @@ -594,7 +606,7 @@ module.exports = class Exchange { getResponseHeaders (response) { const result = {} response.headers.forEach ((value, key) => { - key = key.split ('-').map (word => capitalize (word)).join ('-') + key = key.split ('-').map ((word) => capitalize (word)).join ('-') result[key] = value }) return result @@ -632,7 +644,7 @@ module.exports = class Exchange { } setMarkets (markets, currencies = undefined) { - const values = Object.values (markets).map (market => deepExtend ({ + const values = Object.values (markets).map ((market) => deepExtend ({ 'limits': this.limits, 'precision': this.precision, }, this.fees['trading'], market)) @@ -803,6 +815,22 @@ module.exports = class Exchange { throw new NotSupported (this.id + ' fetchOrder not supported yet'); } + fetchUnifiedOrder (order, params = {}) { + return this.fetchOrder (this.safeValue (order, 'id'), this.safeValue (order, 'symbol'), params); + } + + createOrder (symbol, type, side, amount, price = undefined, params = {}) { + throw new NotSupported (this.id + ' createOrder not supported yet'); + } + + cancelOrder (id, symbol = undefined, params = {}) { + throw new NotSupported (this.id + ' cancelOrder not supported yet'); + } + + cancelUnifiedOrder (order, params = {}) { + return this.cancelOrder (this.safeValue (order, 'id'), this.safeValue (order, 'symbol'), params); + } + fetchOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) { throw new NotSupported (this.id + ' fetchOrders not supported yet'); } diff --git a/TaskServer/node_modules/ccxt/js/base/functions/number.js b/TaskServer/node_modules/ccxt/js/base/functions/number.js index e2f28933c..82c8f0f28 100644 --- a/TaskServer/node_modules/ccxt/js/base/functions/number.js +++ b/TaskServer/node_modules/ccxt/js/base/functions/number.js @@ -45,23 +45,27 @@ function numberToString (x) { // avoids scientific notation for too large and to if (typeof x === 'string') return x + const s = x.toString () if (Math.abs (x) < 1.0) { - const s = x.toString () const e = parseInt (s.split ('e-')[1]) const neg = (s[0] === '-') if (e) { x *= Math.pow (10, e - 1) x = (neg ? '-' : '') + '0.' + (new Array (e)).join ('0') + x.toString ().substring (neg ? 3 : 2) + return x } } else { - let e = parseInt (x.toString ().split ('+')[1]) - if (e > 20) { - e -= 20 - x /= Math.pow (10, e) - x += (new Array (e + 1)).join ('0') + const parts = s.split ('e') + if (parts[1]) { + let e = parseInt (parts[1]) + const m = parts[0].split ('.') + if (m[1]) { + e -= m[1].length + } + return m[0] + m[1] + (new Array (e + 1)).join ('0') } } - return x.toString () + return s; } //----------------------------------------------------------------------------- diff --git a/TaskServer/node_modules/ccxt/js/binance.js b/TaskServer/node_modules/ccxt/js/binance.js index 5853cb91a..9c4cddc24 100644 --- a/TaskServer/node_modules/ccxt/js/binance.js +++ b/TaskServer/node_modules/ccxt/js/binance.js @@ -3,7 +3,7 @@ // --------------------------------------------------------------------------- const Exchange = require ('./base/Exchange'); -const { ExchangeError, ArgumentsRequired, ExchangeNotAvailable, InsufficientFunds, OrderNotFound, InvalidOrder, DDoSProtection, InvalidNonce, AuthenticationError, InvalidAddress, RateLimitExceeded, PermissionDenied } = require ('./base/errors'); +const { ExchangeError, ArgumentsRequired, ExchangeNotAvailable, InsufficientFunds, OrderNotFound, InvalidOrder, DDoSProtection, InvalidNonce, AuthenticationError, InvalidAddress, RateLimitExceeded, PermissionDenied, NotSupported } = require ('./base/errors'); const { ROUND, TRUNCATE } = require ('./base/functions/number'); // --------------------------------------------------------------------------- @@ -37,6 +37,7 @@ module.exports = class binance extends Exchange { 'fetchTransactions': false, 'fetchTradingFee': true, 'fetchTradingFees': true, + 'cancelAllOrders': true, }, 'timeframes': { '1m': '1m', @@ -57,6 +58,10 @@ module.exports = class binance extends Exchange { }, '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', + }, 'api': { 'web': 'https://www.binance.com', 'wapi': 'https://api.binance.com/wapi/v3', @@ -130,6 +135,8 @@ module.exports = class binance extends Exchange { 'lending/union/purchaseRecord', 'lending/union/redemptionRecord', 'lending/union/interestHistory', + 'lending/project/list', + 'lending/project/position/list', ], 'post': [ 'asset/dust', @@ -146,6 +153,7 @@ module.exports = class binance extends Exchange { 'userDataStream', 'futures/transfer', // lending + 'lending/customizedFixed/purchase', 'lending/daily/purchase', 'lending/daily/redeem', ], @@ -211,6 +219,8 @@ module.exports = class binance extends Exchange { 'income', ], 'post': [ + 'batchOrders', + 'positionSide/dual', 'positionMargin', 'marginType', 'order', @@ -221,6 +231,7 @@ module.exports = class binance extends Exchange { 'listenKey', ], 'delete': [ + 'batchOrders', 'order', 'allOpenOrders', 'listenKey', @@ -267,6 +278,7 @@ module.exports = class binance extends Exchange { 'order/test', ], 'delete': [ + 'openOrders', // added on 2020-04-25 for canceling all open orders per symbol 'orderList', // oco 'order', ], @@ -289,7 +301,6 @@ module.exports = class binance extends Exchange { 'fetchTradesMethod': 'publicGetAggTrades', // publicGetTrades, publicGetHistoricalTrades 'fetchTickersMethod': 'publicGetTicker24hr', 'defaultTimeInForce': 'GTC', // 'GTC' = Good To Cancel (default), 'IOC' = Immediate Or Cancel - 'defaultLimitOrderType': 'limit', // or 'limit_maker' 'defaultType': 'spot', // 'spot', 'future' 'hasAlreadyAuthenticatedSuccessfully': false, 'warnOnFetchOpenOrdersWithoutSymbol': true, @@ -326,6 +337,32 @@ module.exports = class binance extends Exchange { }); } + setSandboxMode (enabled) { + if (enabled) { // eslint-disable-line no-extra-boolean-cast + if ('test' in this.urls) { + const type = this.safeString (this.options, 'defaultType', 'spot'); + if (type !== 'future') { + throw new NotSupported (this.id + ' does not have a sandbox URL for ' + type + " markets, set exchange.options['defaultType'] = 'future' or don't use the sandbox for " + this.id); + } + if (typeof this.urls['api'] === 'string') { + this.urls['api_backup'] = this.urls['api']; + this.urls['api'] = this.urls['test']; + } else { + this.urls['api_backup'] = this.extend ({}, this.urls['api']); + this.urls['api'] = this.extend ({}, this.urls['test']); + } + } else { + throw new NotSupported (this.id + ' does not have a sandbox URL'); + } + } else if ('api_backup' in this.urls) { + if (typeof this.urls['api'] === 'string') { + this.urls['api'] = this.urls['api_backup']; + } else { + this.urls['api'] = this.extend ({}, this.urls['api_backup']); + } + } + } + nonce () { return this.milliseconds () - this.options['timeDifference']; } @@ -476,7 +513,7 @@ module.exports = class binance extends Exchange { 'max': undefined, }, 'cost': { - 'min': -1 * Math.log10 (precision['amount']), + 'min': undefined, 'max': undefined, }, }, @@ -720,7 +757,7 @@ module.exports = class binance extends Exchange { async fetchBidsAsks (symbols = undefined, params = {}) { await this.loadMarkets (); - const defaultType = this.safeString2 (this.options, 'fetchOpenOrders', 'defaultType', 'spot'); + 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'; @@ -737,12 +774,12 @@ module.exports = class binance extends Exchange { parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) { return [ - ohlcv[0], - parseFloat (ohlcv[1]), - parseFloat (ohlcv[2]), - parseFloat (ohlcv[3]), - parseFloat (ohlcv[4]), - parseFloat (ohlcv[5]), + this.safeInteger (ohlcv, 0), + this.safeFloat (ohlcv, 1), + this.safeFloat (ohlcv, 2), + this.safeFloat (ohlcv, 3), + this.safeFloat (ohlcv, 4), + this.safeFloat (ohlcv, 5), ]; } @@ -870,6 +907,10 @@ module.exports = class binance extends Exchange { if (market !== undefined) { symbol = market['symbol']; } + let cost = undefined; + if ((price !== undefined) && (amount !== undefined)) { + cost = price * amount; + } return { 'info': trade, 'timestamp': timestamp, @@ -878,11 +919,11 @@ module.exports = class binance extends Exchange { 'id': id, 'order': orderId, 'type': undefined, - 'takerOrMaker': takerOrMaker, 'side': side, + 'takerOrMaker': takerOrMaker, 'price': price, 'amount': amount, - 'cost': price * amount, + 'cost': cost, 'fee': fee, }; } @@ -1180,6 +1221,8 @@ module.exports = class binance extends Exchange { } else if (uppercaseType === 'STOP') { stopPriceIsRequired = true; priceIsRequired = true; + } else if (uppercaseType === 'STOP_MARKET') { + stopPriceIsRequired = true; } if (priceIsRequired) { if (price === undefined) { @@ -1339,6 +1382,27 @@ module.exports = class binance extends Exchange { return this.parseOrder (response); } + async cancelAllOrders (symbol = undefined, params = {}) { + if (symbol === undefined) { + throw new ArgumentsRequired (this.id + ' cancelAllOrders requires a symbol argument'); + } + await this.loadMarkets (); + const market = this.market (symbol); + const request = { + 'symbol': market['id'], + }; + const defaultType = this.safeString2 (this.options, 'cancelAllOrders', 'defaultType', 'spot'); + const type = this.safeString (params, 'type', defaultType); + const query = this.omit (params, 'type'); + const method = (type === 'spot') ? 'privateDeleteOpenOrders' : 'fapiPrivateDeleteAllOpenOrders'; + const response = await this[method] (this.extend (request, query)); + if (Array.isArray (response)) { + return this.parseOrders (response, market); + } else { + return response; + } + } + async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) { if (symbol === undefined) { throw new ArgumentsRequired (this.id + ' fetchMyTrades requires a symbol argument'); @@ -1571,10 +1635,7 @@ module.exports = class binance extends Exchange { } parseTransactionStatusByType (status, type = undefined) { - if (type === undefined) { - return status; - } - const statuses = { + const statusesByType = { 'deposit': { '0': 'pending', '1': 'ok', @@ -1589,32 +1650,38 @@ module.exports = class binance extends Exchange { '6': 'ok', // Completed }, }; - return (status in statuses[type]) ? statuses[type][status] : status; + const statuses = this.safeValue (statusesByType, type, {}); + return this.safeString (statuses, status, status); } parseTransaction (transaction, currency = undefined) { // // fetchDeposits - // { insertTime: 1517425007000, - // amount: 0.3, - // address: "0x0123456789abcdef", - // addressTag: "", - // txId: "0x0123456789abcdef", - // asset: "ETH", - // status: 1 } + // + // { + // insertTime: 1517425007000, + // amount: 0.3, + // address: "0x0123456789abcdef", + // addressTag: "", + // txId: "0x0123456789abcdef", + // asset: "ETH", + // status: 1 + // } // // fetchWithdrawals // - // { amount: 14, - // address: "0x0123456789abcdef...", + // { + // amount: 14, + // address: "0x0123456789abcdef...", // successTime: 1514489710000, - // transactionFee: 0.01, - // addressTag: "", - // txId: "0x0123456789abcdef...", - // id: "0123456789abcdef...", - // asset: "ETH", - // applyTime: 1514488724000, - // status: 6 } + // transactionFee: 0.01, + // addressTag: "", + // txId: "0x0123456789abcdef...", + // id: "0123456789abcdef...", + // asset: "ETH", + // applyTime: 1514488724000, + // status: 6 + // } // const id = this.safeString (transaction, 'id'); const address = this.safeString (transaction, 'address'); @@ -1624,7 +1691,7 @@ module.exports = class binance extends Exchange { tag = undefined; } } - const txid = this.safeValue (transaction, 'txId'); + const txid = this.safeString (transaction, 'txId'); const currencyId = this.safeString (transaction, 'asset'); const code = this.safeCurrencyCode (currencyId, currency); let timestamp = undefined; @@ -1854,6 +1921,11 @@ module.exports = class binance extends Exchange { 'timestamp': this.nonce (), 'recvWindow': this.options['recvWindow'], }, params)); + } else if (path === 'batchOrders') { + query = this.rawencode (this.extend ({ + 'timestamp': this.nonce (), + 'recvWindow': this.options['recvWindow'], + }, params)); } else { query = this.urlencode (this.extend ({ 'timestamp': this.nonce (), diff --git a/TaskServer/node_modules/ccxt/js/binanceus.js b/TaskServer/node_modules/ccxt/js/binanceus.js index e8c600cfc..aafd7745e 100644 --- a/TaskServer/node_modules/ccxt/js/binanceus.js +++ b/TaskServer/node_modules/ccxt/js/binanceus.js @@ -31,10 +31,10 @@ module.exports = class binanceus extends binance { }, 'fees': { 'trading': { - 'tierBased': false, + 'tierBased': true, 'percentage': true, - 'taker': 0.0, // 0.1% trading fee, zero fees for all trading pairs before November 1 - 'maker': 0.0, // 0.1% trading fee, zero fees for all trading pairs before November 1 + 'taker': 0.001, // 0.1% trading fee, zero fees for all trading pairs before November 1 + 'maker': 0.001, // 0.1% trading fee, zero fees for all trading pairs before November 1 }, }, }); diff --git a/TaskServer/node_modules/ccxt/js/bitbay.js b/TaskServer/node_modules/ccxt/js/bitbay.js index c2180de6e..f800a571f 100644 --- a/TaskServer/node_modules/ccxt/js/bitbay.js +++ b/TaskServer/node_modules/ccxt/js/bitbay.js @@ -3,7 +3,7 @@ // --------------------------------------------------------------------------- const Exchange = require ('./base/Exchange'); -const { InvalidNonce, InsufficientFunds, AuthenticationError, InvalidOrder, ExchangeError, OrderNotFound, AccountSuspended, BadSymbol, OrderImmediatelyFillable, RateLimitExceeded } = require ('./base/errors'); +const { InvalidNonce, InsufficientFunds, AuthenticationError, InvalidOrder, ExchangeError, OrderNotFound, AccountSuspended, BadSymbol, OrderImmediatelyFillable, RateLimitExceeded, OnMaintenance } = require ('./base/errors'); // --------------------------------------------------------------------------- @@ -53,6 +53,7 @@ module.exports = class bitbay extends Exchange { 'https://github.com/BitBayNet/API', 'https://docs.bitbay.net/v1.0.1-en/reference', ], + 'support': 'https://support.bitbay.net', 'fees': 'https://bitbay.net/en/fees', }, 'api': { @@ -117,8 +118,60 @@ module.exports = class bitbay extends Exchange { }, 'fees': { 'trading': { + 'maker': 0.0, + 'taker': 0.1 / 100, + 'percentage': true, + 'tierBased': false, + }, + 'fiat': { 'maker': 0.30 / 100, 'taker': 0.43 / 100, + 'percentage': true, + 'tierBased': true, + 'tiers': { + 'taker': [ + [ 0.0043, 0 ], + [ 0.0042, 1250 ], + [ 0.0041, 3750 ], + [ 0.0040, 7500 ], + [ 0.0039, 10000 ], + [ 0.0038, 15000 ], + [ 0.0037, 20000 ], + [ 0.0036, 25000 ], + [ 0.0035, 37500 ], + [ 0.0034, 50000 ], + [ 0.0033, 75000 ], + [ 0.0032, 100000 ], + [ 0.0031, 150000 ], + [ 0.0030, 200000 ], + [ 0.0029, 250000 ], + [ 0.0028, 375000 ], + [ 0.0027, 500000 ], + [ 0.0026, 625000 ], + [ 0.0025, 875000 ], + ], + 'maker': [ + [ 0.0030, 0 ], + [ 0.0029, 1250 ], + [ 0.0028, 3750 ], + [ 0.0028, 7500 ], + [ 0.0027, 10000 ], + [ 0.0026, 15000 ], + [ 0.0025, 20000 ], + [ 0.0025, 25000 ], + [ 0.0024, 37500 ], + [ 0.0023, 50000 ], + [ 0.0023, 75000 ], + [ 0.0022, 100000 ], + [ 0.0021, 150000 ], + [ 0.0021, 200000 ], + [ 0.0020, 250000 ], + [ 0.0019, 375000 ], + [ 0.0018, 500000 ], + [ 0.0018, 625000 ], + [ 0.0017, 875000 ], + ], + }, }, 'funding': { 'withdraw': { @@ -135,6 +188,9 @@ module.exports = class bitbay extends Exchange { }, }, }, + 'options': { + 'fiatCurrencies': [ 'EUR', 'USD', 'GBP', 'PLN' ], + }, 'exceptions': { '400': ExchangeError, // At least one parameter wasn't set '401': InvalidOrder, // Invalid order type @@ -159,12 +215,14 @@ module.exports = class bitbay extends Exchange { 'OFFER_NOT_FOUND': OrderNotFound, 'OFFER_WOULD_HAVE_BEEN_PARTIALLY_FILLED': OrderImmediatelyFillable, 'ACTION_LIMIT_EXCEEDED': RateLimitExceeded, + 'UNDER_MAINTENANCE': OnMaintenance, }, }); } async fetchMarkets (params = {}) { const response = await this.v1_01PublicGetTradingTicker (params); + const fiatCurrencies = this.safeValue (this.options, 'fiatCurrencies', []); // // { // status: 'Ok', @@ -203,6 +261,12 @@ module.exports = class bitbay extends Exchange { 'amount': this.safeInteger (first, 'scale'), 'price': this.safeInteger (second, 'scale'), }; + let fees = this.safeValue (this.fees, 'trading', {}); + if (this.inArray (base, fiatCurrencies) || this.inArray (quote, fiatCurrencies)) { + fees = this.safeValue (this.fees, 'fiat', {}); + } + const maker = this.safeFloat (fees, 'maker'); + const taker = this.safeFloat (fees, 'taker'); // todo: check that the limits have ben interpreted correctly // todo: parse the fees page result.push ({ @@ -214,7 +278,8 @@ module.exports = class bitbay extends Exchange { 'quoteId': quoteId, 'precision': precision, 'active': undefined, - 'fee': undefined, + 'maker': maker, + 'taker': taker, 'limits': { 'amount': { 'min': this.safeFloat (first, 'minOffer'), diff --git a/TaskServer/node_modules/ccxt/js/bitfinex.js b/TaskServer/node_modules/ccxt/js/bitfinex.js index 883301578..95768e94f 100644 --- a/TaskServer/node_modules/ccxt/js/bitfinex.js +++ b/TaskServer/node_modules/ccxt/js/bitfinex.js @@ -905,12 +905,12 @@ module.exports = class bitfinex extends Exchange { parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) { return [ - ohlcv[0], - ohlcv[1], - ohlcv[3], - ohlcv[4], - ohlcv[2], - ohlcv[5], + this.safeInteger (ohlcv, 0), + this.safeFloat (ohlcv, 1), + this.safeFloat (ohlcv, 3), + this.safeFloat (ohlcv, 4), + this.safeFloat (ohlcv, 2), + this.safeFloat (ohlcv, 5), ]; } diff --git a/TaskServer/node_modules/ccxt/js/bitfinex2.js b/TaskServer/node_modules/ccxt/js/bitfinex2.js index 89beea91a..86d97b188 100644 --- a/TaskServer/node_modules/ccxt/js/bitfinex2.js +++ b/TaskServer/node_modules/ccxt/js/bitfinex2.js @@ -699,6 +699,7 @@ module.exports = class bitfinex2 extends bitfinex { 'PARTIALLY FILLED': 'open', 'EXECUTED': 'closed', 'CANCELED': 'canceled', + 'CANCELED was: PARTIALLY FILLED': 'canceled', 'INSUFFICIENT MARGIN': 'canceled', 'INSUFFICIENT BALANCE (G1) was: PARTIALLY FILLED': 'canceled', 'RSN_DUST': 'rejected', diff --git a/TaskServer/node_modules/ccxt/js/bithumb.js b/TaskServer/node_modules/ccxt/js/bithumb.js index 057ea9b0a..88324e947 100644 --- a/TaskServer/node_modules/ccxt/js/bithumb.js +++ b/TaskServer/node_modules/ccxt/js/bithumb.js @@ -3,7 +3,7 @@ // --------------------------------------------------------------------------- const Exchange = require ('./base/Exchange'); -const { ExchangeError, ExchangeNotAvailable, AuthenticationError, BadRequest, PermissionDenied, InvalidAddress } = require ('./base/errors'); +const { ExchangeError, ExchangeNotAvailable, AuthenticationError, BadRequest, PermissionDenied, InvalidAddress, ArgumentsRequired, InvalidOrder } = require ('./base/errors'); // --------------------------------------------------------------------------- @@ -16,7 +16,12 @@ module.exports = class bithumb extends Exchange { 'rateLimit': 500, 'has': { 'CORS': true, + 'createOrder': true, + 'cancelOrder': true, + 'createMarketOrder': true, 'fetchTickers': true, + 'fetchOpenOrders': true, + 'fetchOrder': true, 'withdraw': true, }, 'urls': { @@ -48,8 +53,8 @@ module.exports = class bithumb extends Exchange { 'info/ticker', 'info/orders', 'info/user_transactions', - 'trade/place', 'info/order_detail', + 'trade/place', 'trade/cancel', 'trade/btc_withdrawal', 'trade/krw_deposit', @@ -165,15 +170,53 @@ module.exports = class bithumb extends Exchange { 'currency': market['base'], }; if (limit !== undefined) { - request['count'] = limit; // max = 50 + request['count'] = limit; // default 30, max 30 } const response = await this.publicGetOrderbookCurrency (this.extend (request, params)); - const orderbook = this.safeValue (response, 'data'); - const timestamp = this.safeInteger (orderbook, 'timestamp'); - return this.parseOrderBook (orderbook, timestamp, 'bids', 'asks', 'price', 'quantity'); + // + // { + // "status":"0000", + // "data":{ + // "timestamp":"1587621553942", + // "payment_currency":"KRW", + // "order_currency":"BTC", + // "bids":[ + // {"price":"8652000","quantity":"0.0043"}, + // {"price":"8651000","quantity":"0.0049"}, + // {"price":"8650000","quantity":"8.4791"}, + // ], + // "asks":[ + // {"price":"8654000","quantity":"0.119"}, + // {"price":"8655000","quantity":"0.254"}, + // {"price":"8658000","quantity":"0.119"}, + // ] + // } + // } + // + const data = this.safeValue (response, 'data', {}); + const timestamp = this.safeInteger (data, 'timestamp'); + return this.parseOrderBook (data, timestamp, 'bids', 'asks', 'price', 'quantity'); } parseTicker (ticker, market = undefined) { + // + // fetchTicker, fetchTickers + // + // { + // "opening_price":"227100", + // "closing_price":"228400", + // "min_price":"222300", + // "max_price":"230000", + // "units_traded":"82618.56075337", + // "acc_trade_value":"18767376138.6031", + // "prev_closing_price":"227100", + // "units_traded_24H":"151871.13484676", + // "acc_trade_value_24H":"34247610416.8974", + // "fluctate_24H":"8700", + // "fluctate_rate_24H":"3.96", + // "date":"1587710327264", // fetchTickers inject this + // } + // const timestamp = this.safeInteger (ticker, 'date'); let symbol = undefined; if (market !== undefined) { @@ -224,9 +267,31 @@ module.exports = class bithumb extends Exchange { async fetchTickers (symbols = undefined, params = {}) { await this.loadMarkets (); const response = await this.publicGetTickerAll (params); + // + // { + // "status":"0000", + // "data":{ + // "BTC":{ + // "opening_price":"9045000", + // "closing_price":"9132000", + // "min_price":"8938000", + // "max_price":"9168000", + // "units_traded":"4619.79967497", + // "acc_trade_value":"42021363832.5187", + // "prev_closing_price":"9041000", + // "units_traded_24H":"8793.5045804", + // "acc_trade_value_24H":"78933458515.4962", + // "fluctate_24H":"530000", + // "fluctate_rate_24H":"6.16" + // }, + // "date":"1587710878669" + // } + // } + // const result = {}; - const timestamp = this.safeInteger (response['data'], 'date'); - const tickers = this.omit (response['data'], 'date'); + const data = this.safeValue (response, 'data', {}); + const timestamp = this.safeInteger (data, 'date'); + const tickers = this.omit (data, 'date'); const ids = Object.keys (tickers); for (let i = 0; i < ids.length; i++) { const id = ids[i]; @@ -253,19 +318,72 @@ module.exports = class bithumb extends Exchange { 'currency': market['base'], }; const response = await this.publicGetTickerCurrency (this.extend (request, params)); - return this.parseTicker (response['data'], market); + // + // { + // "status":"0000", + // "data":{ + // "opening_price":"227100", + // "closing_price":"228400", + // "min_price":"222300", + // "max_price":"230000", + // "units_traded":"82618.56075337", + // "acc_trade_value":"18767376138.6031", + // "prev_closing_price":"227100", + // "units_traded_24H":"151871.13484676", + // "acc_trade_value_24H":"34247610416.8974", + // "fluctate_24H":"8700", + // "fluctate_rate_24H":"3.96", + // "date":"1587710327264" + // } + // } + // + const data = this.safeValue (response, 'data', {}); + return this.parseTicker (data, market); } parseTrade (trade, market = undefined) { + // + // fetchTrades (public) + // + // { + // "transaction_date":"2020-04-23 22:21:46", + // "type":"ask", + // "units_traded":"0.0125", + // "price":"8667000", + // "total":"108337" + // } + // + // fetchOrder (private) + // + // { + // "transaction_date": "1572497603902030", + // "price": "8601000", + // "units": "0.005", + // "fee_currency": "KRW", + // "fee": "107.51", + // "total": "43005" + // } + // // a workaround for their bug in date format, hours are not 0-padded - const parts = trade['transaction_date'].split (' '); - const transaction_date = parts[0]; - let transaction_time = parts[1]; - if (transaction_time.length < 8) { - transaction_time = '0' + transaction_time; + let timestamp = undefined; + const transactionDatetime = this.safeString (trade, 'transaction_date'); + if (transactionDatetime !== undefined) { + const parts = transactionDatetime.split (' '); + const numParts = parts.length; + if (numParts > 1) { + const transactionDate = parts[0]; + let transactionTime = parts[1]; + if (transactionTime.length < 8) { + transactionTime = '0' + transactionTime; + } + timestamp = this.parse8601 (transactionDate + ' ' + transactionTime); + } else { + timestamp = this.safeIntegerProduct (trade, 'transaction_date', 0.001); + } + } + if (timestamp !== undefined) { + timestamp -= 9 * 3600000; // they report UTC + 9 hours, server in Korean timezone } - let timestamp = this.parse8601 (transaction_date + ' ' + transaction_time); - timestamp -= 9 * 3600000; // they report UTC + 9 hours (server in Korean timezone) const type = undefined; let side = this.safeString (trade, 'type'); side = (side === 'ask') ? 'sell' : 'buy'; @@ -276,12 +394,24 @@ module.exports = class bithumb extends Exchange { } const price = this.safeFloat (trade, 'price'); const amount = this.safeFloat (trade, 'units_traded'); - let cost = undefined; - if (amount !== undefined) { - if (price !== undefined) { - cost = price * amount; + let cost = this.safeFloat (trade, 'total'); + if (cost === undefined) { + if (amount !== undefined) { + if (price !== undefined) { + cost = price * amount; + } } } + let fee = undefined; + const feeCost = this.safeFloat (trade, 'fee'); + if (feeCost !== undefined) { + const feeCurrencyId = this.safeString (trade, 'fee_currency'); + const feeCurrencyCode = this.commonCurrencyCode (feeCurrencyId); + fee = { + 'cost': feeCost, + 'currency': feeCurrencyCode, + }; + } return { 'id': id, 'info': trade, @@ -295,7 +425,7 @@ module.exports = class bithumb extends Exchange { 'price': price, 'amount': amount, 'cost': cost, - 'fee': undefined, + 'fee': fee, }; } @@ -309,57 +439,276 @@ module.exports = class bithumb extends Exchange { request['count'] = limit; // default 20, max 100 } const response = await this.publicGetTransactionHistoryCurrency (this.extend (request, params)); - return this.parseTrades (response['data'], market, since, limit); + // + // { + // "status":"0000", + // "data":[ + // { + // "transaction_date":"2020-04-23 22:21:46", + // "type":"ask", + // "units_traded":"0.0125", + // "price":"8667000", + // "total":"108337" + // }, + // ] + // } + // + const data = this.safeValue (response, 'data', []); + return this.parseTrades (data, market, since, limit); } async createOrder (symbol, type, side, amount, price = undefined, params = {}) { await this.loadMarkets (); const market = this.market (symbol); - let request = undefined; - let method = 'privatePostTrade'; + const request = { + 'order_currency': market['id'], + 'Payment_currency': market['quote'], + 'units': amount, + }; + let method = 'privatePostTradePlace'; if (type === 'limit') { - request = { - 'order_currency': market['id'], - 'Payment_currency': market['quote'], - 'units': amount, - 'price': price, - 'type': (side === 'buy') ? 'bid' : 'ask', - }; - method += 'Place'; - } else if (type === 'market') { - request = { - 'currency': market['id'], - 'units': amount, - }; - method += 'Market' + this.capitalize (side); + request['price'] = price; + request['type'] = (side === 'buy') ? 'bid' : 'ask'; + } else { + method = 'privatePostTradeMarket' + this.capitalize (side); } const response = await this[method] (this.extend (request, params)); const id = this.safeString (response, 'order_id'); + if (id === undefined) { + throw new InvalidOrder (this.id + ' createOrder did not return an order id'); + } return { 'info': response, + 'symbol': symbol, + 'type': type, + 'side': side, 'id': id, }; } + async fetchOrder (id, symbol = undefined, params = {}) { + if (symbol === undefined) { + throw new ArgumentsRequired (this.id + ' fetchOrder requires a symbol argument'); + } + await this.loadMarkets (); + const market = this.market (symbol); + const request = { + 'order_id': id, + 'count': 1, + 'order_currency': market['base'], + 'payment_currency': market['quote'], + }; + const response = await this.privatePostInfoOrderDetail (this.extend (request, params)); + // + // { + // "status": "0000", + // "data": { + // "transaction_date": "1572497603668315", + // "type": "bid", + // "order_status": "Completed", + // "order_currency": "BTC", + // "payment_currency": "KRW", + // "order_price": "8601000", + // "order_qty": "0.007", + // "cancel_date": "", + // "cancel_type": "", + // "contract": [ + // { + // "transaction_date": "1572497603902030", + // "price": "8601000", + // "units": "0.005", + // "fee_currency": "KRW", + // "fee": "107.51", + // "total": "43005" + // }, + // ] + // } + // } + // + const data = this.safeValue (response, 'data'); + return this.parseOrder (this.extend (data, { 'order_id': id }), market); + } + + parseOrderStatus (status) { + const statuses = { + 'Pending': 'open', + 'Completed': 'closed', + 'Cancel': 'canceled', + }; + return this.safeString (statuses, status, status); + } + + parseOrder (order, market = undefined) { + // + // fetchOrder + // + // { + // "transaction_date": "1572497603668315", + // "type": "bid", + // "order_status": "Completed", + // "order_currency": "BTC", + // "payment_currency": "KRW", + // "order_price": "8601000", + // "order_qty": "0.007", + // "cancel_date": "", + // "cancel_type": "", + // "contract": [ + // { + // "transaction_date": "1572497603902030", + // "price": "8601000", + // "units": "0.005", + // "fee_currency": "KRW", + // "fee": "107.51", + // "total": "43005" + // }, + // ] + // } + // + // fetchOpenOrders + // + // { + // "order_currency": "BTC", + // "payment_currency": "KRW", + // "order_id": "C0101000007408440032", + // "order_date": "1571728739360570", + // "type": "bid", + // "units": "5.0", + // "units_remaining": "5.0", + // "price": "501000", + // } + // + const timestamp = this.safeIntegerProduct (order, 'order_date', 0.001); + const sideProperty = this.safeValue2 (order, 'type', 'side'); + const side = (sideProperty === 'bid') ? 'buy' : 'sell'; + const status = this.parseOrderStatus (this.safeString (order, 'order_status')); + let price = this.safeFloat2 (order, 'order_price', 'price'); + let type = 'limit'; + if (price === 0) { + price = undefined; + type = 'market'; + } + const amount = this.safeFloat2 (order, 'order_qty', 'units'); + let remaining = this.safeFloat (order, 'units_remaining'); + if (remaining === undefined) { + if (status === 'closed') { + remaining = 0; + } else { + remaining = amount; + } + } + let filled = undefined; + if ((amount !== undefined) && (remaining !== undefined)) { + filled = amount - remaining; + } + let symbol = undefined; + const baseId = this.safeString (order, 'order_currency'); + const quoteId = this.safeString (order, 'payment_currency'); + const base = this.safeCurrencyCode (baseId); + const quote = this.safeCurrencyCode (quoteId); + if ((base !== undefined) && (quote !== undefined)) { + symbol = base + '/' + quote; + } + if ((symbol === undefined) && (market !== undefined)) { + symbol = market['symbol']; + } + const rawTrades = this.safeValue (order, 'contract'); + let trades = undefined; + const id = this.safeString (order, 'order_id'); + if (rawTrades !== undefined) { + trades = this.parseTrades (rawTrades, market, undefined, undefined, { + 'side': side, + 'symbol': symbol, + 'order': id, + }); + } + return { + 'info': order, + 'id': id, + 'timestamp': timestamp, + 'datetime': this.iso8601 (timestamp), + 'lastTradeTimestamp': undefined, + 'symbol': symbol, + 'type': type, + 'side': side, + 'price': price, + 'amount': amount, + 'cost': undefined, + 'average': undefined, + 'filled': filled, + 'remaining': remaining, + 'status': status, + 'fee': undefined, + 'trades': trades, + }; + } + + async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) { + if (symbol === undefined) { + throw new ArgumentsRequired (this.id + ' fetchOpenOrders requires a symbol argument'); + } + await this.loadMarkets (); + const market = this.market (symbol); + if (limit === undefined) { + limit = 100; + } + const request = { + 'count': limit, + 'order_currency': market['base'], + 'payment_currency': market['quote'], + }; + if (since !== undefined) { + request['after'] = since; + } + const response = await this.privatePostInfoOrders (this.extend (request, params)); + // + // { + // "status": "0000", + // "data": [ + // { + // "order_currency": "BTC", + // "payment_currency": "KRW", + // "order_id": "C0101000007408440032", + // "order_date": "1571728739360570", + // "type": "bid", + // "units": "5.0", + // "units_remaining": "5.0", + // "price": "501000", + // } + // ] + // } + // + const data = this.safeValue (response, 'data', []); + return this.parseOrders (data, market, since, limit); + } + async cancelOrder (id, symbol = undefined, params = {}) { const side_in_params = ('side' in params); if (!side_in_params) { - throw new ExchangeError (this.id + ' cancelOrder requires a `side` parameter (sell or buy) and a `currency` parameter'); + throw new ArgumentsRequired (this.id + ' cancelOrder requires a `symbol` argument and a `side` parameter (sell or buy)'); } - const currency = this.safeString (params, 'currency'); - if (currency === undefined) { - throw new ExchangeError (this.id + ' cancelOrder requires a `currency` parameter (a currency id)'); + if (symbol === undefined) { + throw new ArgumentsRequired (this.id + ' cancelOrder requires a `symbol` argument and a `side` parameter (sell or buy)'); } + const market = this.market (symbol); const side = (params['side'] === 'buy') ? 'bid' : 'ask'; params = this.omit (params, [ 'side', 'currency' ]); + // https://github.com/ccxt/ccxt/issues/6771 const request = { 'order_id': id, 'type': side, - 'currency': currency, + 'order_currency': market['base'], + 'payment_currency': market['quote'], }; return await this.privatePostTradeCancel (this.extend (request, params)); } + cancelUnifiedOrder (order, params = {}) { + const request = { + 'side': order['side'], + }; + return this.cancelOrder (order['id'], order['symbol'], this.extend (request, params)); + } + async withdraw (code, amount, address, tag = undefined, params = {}) { this.checkAddress (address); await this.loadMarkets (); @@ -372,7 +721,7 @@ module.exports = class bithumb extends Exchange { if (currency === 'XRP' || currency === 'XMR') { const destination = this.safeString (params, 'destination'); if ((tag === undefined) && (destination === undefined)) { - throw new ExchangeError (this.id + ' ' + code + ' withdraw() requires a tag argument or an extra destination param'); + throw new ArgumentsRequired (this.id + ' ' + code + ' withdraw() requires a tag argument or an extra destination param'); } else if (tag !== undefined) { request['destination'] = tag; } diff --git a/TaskServer/node_modules/ccxt/js/bitmart.js b/TaskServer/node_modules/ccxt/js/bitmart.js index c9a3a9bb3..a25f8aeed 100644 --- a/TaskServer/node_modules/ccxt/js/bitmart.js +++ b/TaskServer/node_modules/ccxt/js/bitmart.js @@ -35,6 +35,7 @@ module.exports = class bitmart extends Exchange { 'fetchClosedOrders': true, 'fetchCanceledOrders': true, 'fetchOrder': true, + 'signIn': true, }, 'urls': { 'logo': 'https://user-images.githubusercontent.com/1294454/61835713-a2662f80-ae85-11e9-9d00-6442919701fd.jpg', @@ -42,6 +43,7 @@ module.exports = class bitmart extends Exchange { 'www': 'https://www.bitmart.com/', 'doc': 'https://github.com/bitmartexchange/bitmart-official-api-docs', 'referral': 'http://www.bitmart.com/?r=rQCFLh', + 'fees': 'https://www.bitmart.com/fee/en', }, 'requiredCredentials': { 'apiKey': true, diff --git a/TaskServer/node_modules/ccxt/js/bitstamp.js b/TaskServer/node_modules/ccxt/js/bitstamp.js index 124d385fc..74d767234 100644 --- a/TaskServer/node_modules/ccxt/js/bitstamp.js +++ b/TaskServer/node_modules/ccxt/js/bitstamp.js @@ -1134,11 +1134,19 @@ module.exports = class bitstamp extends Exchange { body = this.urlencode (query); contentType = 'application/x-www-form-urlencoded'; headers['Content-Type'] = contentType; + } else { + // sending an empty POST request will trigger + // an API0020 error returned by the exchange + // therefore for empty requests we send a dummy object + // https://github.com/ccxt/ccxt/issues/6846 + body = this.urlencode ({ 'foo': 'bar' }); + contentType = 'application/x-www-form-urlencoded'; + headers['Content-Type'] = contentType; } } const authBody = body ? body : ''; const auth = xAuth + method + url.replace ('https://', '') + contentType + xAuthNonce + xAuthTimestamp + xAuthVersion + authBody; - const signature = this.encode (this.hmac (this.encode (auth), this.encode (this.secret))); + const signature = this.hmac (this.encode (auth), this.encode (this.secret)); headers['X-Auth-Signature'] = signature; } } diff --git a/TaskServer/node_modules/ccxt/js/bitz.js b/TaskServer/node_modules/ccxt/js/bitz.js index 0bf24b0ee..50fa901e8 100644 --- a/TaskServer/node_modules/ccxt/js/bitz.js +++ b/TaskServer/node_modules/ccxt/js/bitz.js @@ -650,7 +650,7 @@ module.exports = class bitz extends Exchange { } } else { if (since !== undefined) { - throw new ExchangeError (this.id + ' fetchOHLCV requires a limit argument if the since argument is specified'); + throw new ArgumentsRequired (this.id + ' fetchOHLCV requires a limit argument if the since argument is specified'); } } const response = await this.marketGetKline (this.extend (request, params)); diff --git a/TaskServer/node_modules/ccxt/js/bleutrade.js b/TaskServer/node_modules/ccxt/js/bleutrade.js index 3bfdc13e9..9bbd8a207 100644 --- a/TaskServer/node_modules/ccxt/js/bleutrade.js +++ b/TaskServer/node_modules/ccxt/js/bleutrade.js @@ -73,6 +73,9 @@ module.exports = class bleutrade extends Exchange { ], }, 'v3Private': { + 'get': [ + 'statement', + ], 'post': [ 'getbalance', 'getbalances', @@ -189,8 +192,8 @@ module.exports = class bleutrade extends Exchange { // MarketCurrencyLong: 'Litecoin', // BaseCurrencyLong: 'Tether' } const id = this.safeString (market, 'MarketName'); - const baseId = this.safeString (market, 'MarketCurrency'); - const quoteId = this.safeString (market, 'BaseCurrency'); + const baseId = this.safeString (market, 'MarketAsset'); + const quoteId = this.safeString (market, 'BaseAsset'); const base = this.safeCurrencyCode (baseId); const quote = this.safeCurrencyCode (quoteId); const symbol = base + '/' + quote; diff --git a/TaskServer/node_modules/ccxt/js/btctradeua.js b/TaskServer/node_modules/ccxt/js/btctradeua.js index 8c056885c..553ec77f2 100644 --- a/TaskServer/node_modules/ccxt/js/btctradeua.js +++ b/TaskServer/node_modules/ccxt/js/btctradeua.js @@ -18,6 +18,7 @@ module.exports = class btctradeua extends Exchange { 'CORS': false, 'createMarketOrder': false, 'fetchOpenOrders': true, + 'signIn': true, }, 'urls': { 'referral': 'https://btc-trade.com.ua/registration/22689', diff --git a/TaskServer/node_modules/ccxt/js/buda.js b/TaskServer/node_modules/ccxt/js/buda.js index 3416ad8c4..e92a1617a 100644 --- a/TaskServer/node_modules/ccxt/js/buda.js +++ b/TaskServer/node_modules/ccxt/js/buda.js @@ -3,7 +3,7 @@ // --------------------------------------------------------------------------- const Exchange = require ('./base/Exchange'); -const { AddressPending, AuthenticationError, ExchangeError, NotSupported, PermissionDenied } = require ('./base/errors'); +const { AddressPending, AuthenticationError, ExchangeError, NotSupported, PermissionDenied, ArgumentsRequired } = require ('./base/errors'); // --------------------------------------------------------------------------- @@ -692,7 +692,7 @@ module.exports = class buda extends Exchange { async fetchDeposits (code = undefined, since = undefined, limit = undefined, params = {}) { await this.loadMarkets (); if (code === undefined) { - throw new ExchangeError (this.id + ': fetchDeposits() requires a currency code argument'); + throw new ArgumentsRequired (this.id + ': fetchDeposits() requires a currency code argument'); } const currency = this.currency (code); const request = { @@ -707,7 +707,7 @@ module.exports = class buda extends Exchange { async fetchWithdrawals (code = undefined, since = undefined, limit = undefined, params = {}) { await this.loadMarkets (); if (code === undefined) { - throw new ExchangeError (this.id + ': fetchDeposits() requires a currency code argument'); + throw new ArgumentsRequired (this.id + ': fetchDeposits() requires a currency code argument'); } const currency = this.currency (code); const request = { diff --git a/TaskServer/node_modules/ccxt/js/bybit.js b/TaskServer/node_modules/ccxt/js/bybit.js index a27c9eec5..5010ba98c 100644 --- a/TaskServer/node_modules/ccxt/js/bybit.js +++ b/TaskServer/node_modules/ccxt/js/bybit.js @@ -4,7 +4,7 @@ const Exchange = require ('./base/Exchange'); const { TICK_SIZE } = require ('./base/functions/number'); -const { AuthenticationError, ExchangeError, ArgumentsRequired, PermissionDenied, InvalidOrder, OrderNotFound, InsufficientFunds, BadRequest, RateLimitExceeded, InvalidNonce } = require ('./base/errors'); +const { AuthenticationError, ExchangeError, ArgumentsRequired, PermissionDenied, InvalidOrder, OrderNotFound, InsufficientFunds, BadRequest, RateLimitExceeded, InvalidNonce, NotSupported } = require ('./base/errors'); // --------------------------------------------------------------------------- @@ -48,7 +48,7 @@ module.exports = class bybit extends Exchange { '30m': '30', '1h': '60', '2h': '120', - '3h': '180', + '4h': '240', '6h': '360', '12h': '720', '1d': 'D', @@ -63,6 +63,7 @@ module.exports = class bybit extends Exchange { 'www': 'https://www.bybit.com/', 'doc': [ 'https://bybit-exchange.github.io/docs/inverse/', + 'https://bybit-exchange.github.io/docs/linear/', 'https://github.com/bybit-exchange', ], 'fees': 'https://help.bybit.com/hc/en-us/articles/360039261154', @@ -116,6 +117,41 @@ module.exports = class bybit extends Exchange { 'position/trading-stop', ], }, + 'publicLinear': { + 'get': [ + 'kline', + 'recent-trading-records', + 'funding/prev-funding-rate', + 'mark-price-kline', + ], + }, + 'privateLinear': { + 'get': [ + 'order/list', + 'order/search', + 'stop-order/list', + 'stop-order/search', + 'position/list', + 'position/set-auto-add-margin', + 'position/set-leverage', + 'position/switch-isolated', + 'position/trading-stop', + 'position/add-margin', + 'trade/execution/list', + 'trade/closed-pnl/list', + 'risk-limit', + 'funding/prev-funding', + 'funding/predicted-funding', + ], + 'post': [ + 'order/create', + 'order/cancel', + 'order/cancelAll', + 'stop-order/create', + 'stop-order/cancel', + 'stop-order/cancelAll', + ], + }, 'position': { 'post': [ 'change-position-margin', @@ -227,6 +263,9 @@ module.exports = class bybit extends Exchange { }, 'precisionMode': TICK_SIZE, 'options': { + 'marketTypes': { + 'BTC/USDT': 'linear', + }, 'code': 'BTC', 'fetchBalance': { 'code': 'BTC', @@ -309,6 +348,8 @@ module.exports = class bybit extends Exchange { // } // const markets = this.safeValue (response, 'result', []); + const options = this.safeValue (this.options, 'fetchMarkets', {}); + const linearQuoteCurrencies = this.safeValue (options, 'linear', { 'USDT': true }); const result = []; for (let i = 0; i < markets.length; i++) { const market = markets[i]; @@ -317,6 +358,8 @@ module.exports = class bybit extends Exchange { const quoteId = this.safeString (market, 'quote_currency'); const base = this.safeCurrencyCode (baseId); const quote = this.safeCurrencyCode (quoteId); + const linear = (quote in linearQuoteCurrencies); + const inverse = !linear; const symbol = base + '/' + quote; const lotSizeFilter = this.safeValue (market, 'lot_size_filter', {}); const priceFilter = this.safeValue (market, 'price_filter', {}); @@ -333,6 +376,12 @@ module.exports = class bybit extends Exchange { 'precision': precision, 'taker': this.safeFloat (market, 'taker_fee'), 'maker': this.safeFloat (market, 'maker_fee'), + 'type': 'future', + 'spot': false, + 'future': true, + 'option': false, + 'linear': linear, + 'inverse': inverse, 'limits': { 'amount': { 'min': this.safeFloat (lotSizeFilter, 'min_trading_qty'), @@ -347,10 +396,6 @@ module.exports = class bybit extends Exchange { 'max': undefined, }, }, - 'type': 'future', - 'spot': false, - 'future': true, - 'option': false, 'info': market, }); } @@ -610,13 +655,25 @@ module.exports = class bybit extends Exchange { // turnover: '162.32773718999994' // }, // + // { + // "id":143536, + // "symbol":"BTCUSDT", + // "period":"15", + // "start_at":1587883500, + // "volume":1.035, + // "open":7540.5, + // "high":7541, + // "low":7540.5, + // "close":7541 + // } + // return [ - this.safeTimestamp (ohlcv, 'open_time'), + this.safeTimestamp2 (ohlcv, 'open_time', 'start_at'), this.safeFloat (ohlcv, 'open'), this.safeFloat (ohlcv, 'high'), this.safeFloat (ohlcv, 'low'), this.safeFloat (ohlcv, 'close'), - this.safeFloat (ohlcv, 'turnover'), + this.safeFloat2 (ohlcv, 'turnover', 'volume'), ]; } @@ -641,7 +698,13 @@ module.exports = class bybit extends Exchange { if (limit !== undefined) { request['limit'] = limit; // max 200, default 200 } - const response = await this.publicGetKlineList (this.extend (request, params)); + const marketTypes = this.safeValue (this.options, 'marketTypes', {}); + const marketType = this.safeString (marketTypes, symbol); + const method = (marketType === 'linear') ? 'publicLinearGetKline' : 'publicGetKlineList'; + const response = await this[method] (this.extend (request, params)); + // + // inverse perpetual BTC/USD + // // { // ret_code: 0, // ret_msg: 'OK', @@ -662,6 +725,30 @@ module.exports = class bybit extends Exchange { // ], // time_now: '1583953082.397330' // } + // + // linear perpetual BTC/USDT + // + // { + // "ret_code":0, + // "ret_msg":"OK", + // "ext_code":"", + // "ext_info":"", + // "result":[ + // { + // "id":143536, + // "symbol":"BTCUSDT", + // "period":"15", + // "start_at":1587883500, + // "volume":1.035, + // "open":7540.5, + // "high":7541, + // "low":7540.5, + // "close":7541 + // } + // ], + // "time_now":"1587884120.168077" + // } + // const result = this.safeValue (response, 'result', {}); return this.parseOHLCVs (result, market, timeframe, since, limit); } @@ -688,6 +775,8 @@ module.exports = class bybit extends Exchange { // "exec_id": "256e5ef8-abfe-5772-971b-f944e15e0d68", // "exec_price": "8178.5", // "exec_qty": 1, + // // the docs say the exec_time field is "abandoned" now + // // the user should use "trade_time_ms" // "exec_time": "1571676941.70682", // "exec_type": "Trade", //Exec Type Enum // "exec_value": "0.00012227", @@ -702,30 +791,35 @@ module.exports = class bybit extends Exchange { // "order_type": "Market", //Order Type Enum // "side": "Buy", //Side Enum // "symbol": "BTCUSD", //Symbol Enum - // "user_id": 1 + // "user_id": 1, + // "trade_time_ms": 1577480599000 // } // const id = this.safeString2 (trade, 'id', 'exec_id'); let symbol = undefined; let base = undefined; const marketId = this.safeString (trade, 'symbol'); + let amount = this.safeFloat2 (trade, 'qty', 'exec_qty'); + let cost = this.safeFloat (trade, 'exec_value'); + const price = this.safeFloat2 (trade, 'price', 'exec_price'); if (marketId in this.markets_by_id) { market = this.markets_by_id[marketId]; symbol = market['symbol']; base = market['base']; } - if ((symbol === undefined) && (market !== undefined)) { - symbol = market['symbol']; - base = market['base']; + if (market !== undefined) { + if (symbol === undefined) { + symbol = market['symbol']; + base = market['base']; + } + // if private trade + if ('exec_fee' in trade) { + if (market['inverse']) { + amount = this.safeFloat (trade, 'exec_value'); + cost = this.safeFloat (trade, 'exec_qty'); + } + } } - let timestamp = this.parse8601 (this.safeString (trade, 'time')); - if (timestamp === undefined) { - timestamp = this.safeTimestamp (trade, 'exec_time'); - } - const side = this.safeStringLower (trade, 'side'); - const price = this.safeFloat2 (trade, 'price', 'exec_price'); - const amount = this.safeFloat2 (trade, 'qty', 'exec_qty'); - let cost = this.safeFloat (trade, 'exec_value'); if (cost === undefined) { if (amount !== undefined) { if (price !== undefined) { @@ -733,6 +827,11 @@ module.exports = class bybit extends Exchange { } } } + let timestamp = this.parse8601 (this.safeString (trade, 'time')); + if (timestamp === undefined) { + timestamp = this.safeInteger (trade, 'trade_time_ms'); + } + const side = this.safeStringLower (trade, 'side'); const lastLiquidityInd = this.safeString (trade, 'last_liquidity_ind'); const takerOrMaker = (lastLiquidityInd === 'AddedLiquidity') ? 'maker' : 'taker'; const feeCost = this.safeFloat (trade, 'exec_fee'); @@ -771,7 +870,10 @@ module.exports = class bybit extends Exchange { if (limit !== undefined) { request['count'] = limit; // default 500, max 1000 } - const response = await this.publicGetTradingRecords (this.extend (request, params)); + const marketTypes = this.safeValue (this.options, 'marketTypes', {}); + const marketType = this.safeString (marketTypes, symbol); + const method = (marketType === 'linear') ? 'publicLinearGetRecentTradingRecords' : 'publicGetTradingRecords'; + const response = await this[method] (this.extend (request, params)); // // { // ret_code: 0, @@ -885,8 +987,8 @@ module.exports = class bybit extends Exchange { // "last_exec_time": 0, // "last_exec_price": 0, // "leaves_qty": 1, - // "cum_exec_qty": 0, - // "cum_exec_value": 0, + // "cum_exec_qty": 0, // in contracts, where 1 contract = 1 quote currency unit (USD for inverse contracts) + // "cum_exec_value": 0, // in contract's underlying currency (BTC for inverse contracts) // "cum_exec_fee": 0, // "reject_reason": "", // "order_link_id": "", @@ -894,18 +996,69 @@ module.exports = class bybit extends Exchange { // "updated_at": "2019-11-30T11:03:43.455Z" // } // + // fetchOrder + // + // { + // "user_id" : 599946, + // "symbol" : "BTCUSD", + // "side" : "Buy", + // "order_type" : "Limit", + // "price" : "7948", + // "qty" : 10, + // "time_in_force" : "GoodTillCancel", + // "order_status" : "Filled", + // "ext_fields" : { + // "o_req_num" : -1600687220498, + // "xreq_type" : "x_create" + // }, + // "last_exec_time" : "1588150113.968422", + // "last_exec_price" : "7948", + // "leaves_qty" : 0, + // "leaves_value" : "0", + // "cum_exec_qty" : 10, + // "cum_exec_value" : "0.00125817", + // "cum_exec_fee" : "-0.00000031", + // "reject_reason" : "", + // "cancel_type" : "", + // "order_link_id" : "", + // "created_at" : "2020-04-29T08:45:24.399146Z", + // "updated_at" : "2020-04-29T08:48:33.968422Z", + // "order_id" : "dd2504b9-0157-406a-99e1-efa522373944" + // } + // + const marketId = this.safeString (order, 'symbol'); + let symbol = undefined; + let base = undefined; + if (marketId in this.markets_by_id) { + market = this.markets_by_id[marketId]; + } const timestamp = this.parse8601 (this.safeString (order, 'created_at')); const id = this.safeString (order, 'order_id'); const price = this.safeFloat (order, 'price'); const average = this.safeFloat (order, 'average_price'); - const amount = this.safeFloat (order, 'qty'); - let filled = this.safeFloat (order, 'cum_exec_qty'); - let remaining = this.safeFloat (order, 'leaves_qty'); + let amount = undefined; + let cost = undefined; + let filled = undefined; + let remaining = undefined; + if (market !== undefined) { + symbol = market['symbol']; + base = market['base']; + if (market['inverse']) { + cost = this.safeFloat (order, 'cum_exec_qty'); + filled = this.safeFloat (order, 'cum_exec_value'); + remaining = this.safeFloat (order, 'leaves_value'); + amount = this.sum (filled, remaining); + } else { + amount = this.safeFloat (order, 'qty'); + cost = this.safeFloat (order, 'cum_exec_value'); + filled = this.safeFloat (order, 'cum_exec_qty'); + remaining = this.safeFloat (order, 'leaves_qty'); + } + } let lastTradeTimestamp = this.safeTimestamp (order, 'last_exec_time'); if (lastTradeTimestamp === 0) { lastTradeTimestamp = undefined; } - let cost = this.safeFloat (order, 'cum_exec_value'); if ((filled === undefined) && (amount !== undefined) && (remaining !== undefined)) { filled = amount - remaining; } @@ -920,22 +1073,6 @@ module.exports = class bybit extends Exchange { } } const status = this.parseOrderStatus (this.safeString (order, 'order_status')); - const marketId = this.safeString (order, 'symbol'); - let symbol = undefined; - let base = undefined; - if (marketId in this.markets_by_id) { - market = this.markets_by_id[marketId]; - symbol = market['symbol']; - base = market['base']; - } - if (market !== undefined) { - if (symbol === undefined) { - symbol = market['symbol']; - } - if (base === undefined) { - base = market['base']; - } - } const side = this.safeStringLower (order, 'side'); let feeCost = this.safeFloat (order, 'cum_exec_fee'); let fee = undefined; @@ -987,7 +1124,9 @@ module.exports = class bybit extends Exchange { // conditional orders --------------------------------------------- // 'stop_order_id': id, // one of stop_order_id or order_link_id is required for conditional orders }; - let method = 'privateGetOrder'; + const marketTypes = this.safeValue (this.options, 'marketTypes', {}); + const marketType = this.safeString (marketTypes, symbol); + let method = (marketType === 'linear') ? 'privateLinearGetOrderSearch' : 'privateGetOrder'; const stopOrderId = this.safeString (params, 'stop_order_id'); if (stopOrderId === undefined) { const orderLinkId = this.safeString (params, 'order_link_id'); @@ -995,7 +1134,7 @@ module.exports = class bybit extends Exchange { request['order_id'] = id; } } else { - method = 'privateGetStopOrder'; + method = (marketType === 'linear') ? 'privateLinearGetStopOrderSearch' : 'privateGetStopOrder'; } const response = await this[method] (this.extend (request, params)); // @@ -1107,12 +1246,14 @@ module.exports = class bybit extends Exchange { } const stopPx = this.safeValue (params, 'stop_px'); const basePrice = this.safeValue (params, 'base_price'); - let method = 'privatePostOrderCreate'; + const marketTypes = this.safeValue (this.options, 'marketTypes', {}); + const marketType = this.safeString (marketTypes, symbol); + let method = (marketType === 'linear') ? 'privateLinearPostOrderCreate' : 'privatePostOrderCreate'; if (stopPx !== undefined) { if (basePrice === undefined) { throw new ArgumentsRequired (this.id + ' createOrder requires both the stop_px and base_price params for a conditional ' + type + ' order'); } else { - method = 'openapiPostStopOrderCreate'; + method = (marketType === 'linear') ? 'privateLinearPostStopOrderCreate' : 'openapiPostStopOrderCreate'; request['stop_px'] = this.priceToPrecision (symbol, stopPx); request['base_price'] = this.priceToPrecision (symbol, basePrice); params = this.omit (params, [ 'stop_px', 'base_price' ]); @@ -1206,6 +1347,11 @@ module.exports = class bybit extends Exchange { if (symbol === undefined) { throw new ArgumentsRequired (this.id + ' editOrder requires an symbol argument'); } + const marketTypes = this.safeValue (this.options, 'marketTypes', {}); + const marketType = this.safeString (marketTypes, symbol); + if (marketType === 'linear') { + throw new NotSupported (this.id + ' does not support editOrder for ' + marketType + ' ' + symbol + ' market type'); + } await this.loadMarkets (); const market = this.market (symbol); const request = { @@ -1283,7 +1429,9 @@ module.exports = class bybit extends Exchange { // conditional orders --------------------------------------------- // 'stop_order_id': id, // one of stop_order_id or order_link_id is required for conditional orders }; - let method = 'privatePostOrderCancel'; + const marketTypes = this.safeValue (this.options, 'marketTypes', {}); + const marketType = this.safeValue (marketTypes, symbol); + let method = (marketType === 'linear') ? 'privateLinearPostOrderCancel' : 'privatePostOrderCancel'; const stopOrderId = this.safeString (params, 'stop_order_id'); if (stopOrderId === undefined) { const orderLinkId = this.safeString (params, 'order_link_id'); @@ -1291,7 +1439,7 @@ module.exports = class bybit extends Exchange { request['order_id'] = id; } } else { - method = 'openapiPostStopOrderCancel'; + method = (marketType === 'linear') ? 'privateLinearPostStopOrderCancel' : 'openapiPostStopOrderCancel'; } const response = await this[method] (this.extend (request, params)); const result = this.safeValue (response, 'result', {}); @@ -1308,7 +1456,10 @@ module.exports = class bybit extends Exchange { 'symbol': market['id'], }; const options = this.safeValue (this.options, 'cancelAllOrders'); - const method = this.safeString (options, 'method', 'privatePostOrderCancelAll'); + const marketTypes = this.safeValue (this.options, 'marketTypes', {}); + const marketType = this.safeString (marketTypes, symbol); + const defaultMethod = (marketType === 'linear') ? 'privateLinearPostOrderCancelAll' : 'privatePostOrderCancelAll'; + const method = this.safeString (options, 'method', defaultMethod); const response = await this[method] (this.extend (request, params)); const result = this.safeValue (response, 'result', []); return this.parseOrders (result, market); @@ -1337,7 +1488,9 @@ module.exports = class bybit extends Exchange { request['limit'] = limit; } const options = this.safeValue (this.options, 'fetchOrders', {}); - let defaultMethod = 'openapiGetOrderList'; + const marketTypes = this.safeValue (this.options, 'marketTypes', {}); + const marketType = this.safeString (marketTypes, symbol); + let defaultMethod = (marketType === 'linear') ? 'privateLinearGetOrderList' : 'openapiGetOrderList'; let query = params; if (('stop_order_id' in params) || ('stop_order_status' in params)) { let stopOrderStatus = this.safeValue (params, 'stopOrderStatus'); @@ -1348,7 +1501,7 @@ module.exports = class bybit extends Exchange { request['stop_order_status'] = stopOrderStatus; query = this.omit (params, 'stop_order_status'); } - defaultMethod = 'openapiGetStopOrderList'; + defaultMethod = (marketType === 'linear') ? 'privateLinearGetStopOrderList' : 'openapiGetStopOrderList'; } const method = this.safeString (options, 'method', defaultMethod); const response = await this[method] (this.extend (request, query)); @@ -1524,12 +1677,15 @@ module.exports = class bybit extends Exchange { request['symbol'] = market['id']; } if (since !== undefined) { - request['start_time'] = parseInt (since / 1000); + request['start_time'] = since; } if (limit !== undefined) { request['limit'] = limit; // default 20, max 50 } - const response = await this.privateGetExecutionList (this.extend (request, params)); + const marketTypes = this.safeValue (this.options, 'marketTypes', {}); + const marketType = this.safeString (marketTypes, symbol); + const method = (marketType === 'linear') ? 'privateLinearGetTradeExecutionList' : 'privateGetExecutionList'; + const response = await this[method] (this.extend (request, params)); // // { // "ret_code": 0, @@ -1864,6 +2020,11 @@ module.exports = class bybit extends Exchange { if (Object.keys (params).length) { request += '?' + this.rawencode (params); } + } else if (api === 'publicLinear') { + request = '/public/linear/' + request; + if (Object.keys (params).length) { + request += '?' + this.rawencode (params); + } } else { this.checkRequiredCredentials (); if (api === 'openapi') { @@ -1871,14 +2032,16 @@ module.exports = class bybit extends Exchange { } else if (api === 'private') { // private v2 request = '/' + this.version + '/' + api + '/' + request; + } else if (api === 'privateLinear') { + request = '/private/linear/' + request; } else { // position, user - request += '/' + api + '/' + request; + request = '/' + api + '/' + request; } const timestamp = this.nonce (); const query = this.extend (params, { 'api_key': this.apiKey, - 'recvWindow': this.options['recvWindow'], + 'recv_window': this.options['recvWindow'], 'timestamp': timestamp, }); const auth = this.rawencode (this.keysort (query)); diff --git a/TaskServer/node_modules/ccxt/js/bytetrade.js b/TaskServer/node_modules/ccxt/js/bytetrade.js index 3019af02f..b0d50b5cc 100644 --- a/TaskServer/node_modules/ccxt/js/bytetrade.js +++ b/TaskServer/node_modules/ccxt/js/bytetrade.js @@ -47,9 +47,15 @@ module.exports = class bytetrade extends Exchange { '1M': '1M', }, 'urls': { - 'test': 'https://api-v2-test.byte-trade.com', + 'test': { + 'market': 'https://api-v2-test.byte-trade.com', + 'public': 'https://api-v2-test.byte-trade.com', + }, 'logo': 'https://user-images.githubusercontent.com/1294454/67288762-2f04a600-f4e6-11e9-9fd6-c60641919491.jpg', - 'api': 'https://api-v2.byte-trade.com', + 'api': { + 'market': 'https://api-v2.bytetrade.com', + 'public': 'https://api-v2.bytetrade.com', + }, 'www': 'https://www.byte-trade.com', 'doc': 'https://github.com/Bytetrade/bytetrade-official-api-docs/wiki', }, @@ -1222,7 +1228,7 @@ module.exports = class bytetrade extends Exchange { this.numberToLE (address.length, 1), this.stringToBinary (this.encode (address)), this.numberToLE (parseInt (coinId), 4), - this.numberToLE (Math.floor (parseInt (parseFloat (this.integerDivide (amountChain, eightBytes)))), 8), + this.numberToLE (this.integerDivide (amountChain, eightBytes), 8), this.numberToLE (this.integerModulo (amountChain, eightBytes), 8), this.numberToLE (1, 1), this.numberToLE (this.integerDivide (assetFee, eightBytes), 8), @@ -1255,7 +1261,7 @@ module.exports = class bytetrade extends Exchange { this.numberToLE (middleAddress.length, 1), this.stringToBinary (this.encode (middleAddress)), this.numberToLE (parseInt (coinId), 4), - this.numberToLE (Math.floor (parseInt (parseFloat (this.integerDivide (amountChain, eightBytes)))), 8), + this.numberToLE (this.integerDivide (amountChain, eightBytes), 8), this.numberToLE (this.integerModulo (amountChain, eightBytes), 8), this.numberToLE (0, 1), this.numberToLE (1, 1), @@ -1358,7 +1364,7 @@ module.exports = class bytetrade extends Exchange { } sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) { - let url = this.urls['api']; + let url = this.urls['api'][api]; url += '/' + path; if (Object.keys (params).length) { url += '?' + this.urlencode (params); diff --git a/TaskServer/node_modules/ccxt/js/cex.js b/TaskServer/node_modules/ccxt/js/cex.js index 24efe1a0e..dd8ab9391 100644 --- a/TaskServer/node_modules/ccxt/js/cex.js +++ b/TaskServer/node_modules/ccxt/js/cex.js @@ -564,9 +564,45 @@ module.exports = class cex extends Exchange { request['order_type'] = type; } const response = await this.privatePostPlaceOrderPair (this.extend (request, params)); + // + // { + // "id": "12978363524", + // "time": 1586610022259, + // "type": "buy", + // "price": "0.033934", + // "amount": "0.10722802", + // "pending": "0.10722802", + // "complete": false + // } + // + const placedAmount = this.safeFloat (response, 'amount'); + const remaining = this.safeFloat (response, 'pending'); + const timestamp = this.safeValue (response, 'time'); + const complete = this.safeValue (response, 'complete'); + const status = complete ? 'closed' : 'open'; + let filled = undefined; + if ((placedAmount !== undefined) && (remaining !== undefined)) { + filled = Math.max (placedAmount - remaining, 0); + } return { + 'id': this.safeString (response, 'id'), 'info': response, - 'id': response['id'], + 'clientOrderId': undefined, + 'timestamp': timestamp, + 'datetime': this.iso8601 (timestamp), + 'lastTradeTimestamp': undefined, + 'type': type, + 'side': this.safeString (response, 'type'), + 'symbol': symbol, + 'status': status, + 'price': this.safeFloat (response, 'price'), + 'amount': placedAmount, + 'cost': undefined, + 'average': undefined, + 'remaining': remaining, + 'filled': filled, + 'fee': undefined, + 'trades': undefined, }; } diff --git a/TaskServer/node_modules/ccxt/js/coinmate.js b/TaskServer/node_modules/ccxt/js/coinmate.js index 0046f4303..6e5196f01 100644 --- a/TaskServer/node_modules/ccxt/js/coinmate.js +++ b/TaskServer/node_modules/ccxt/js/coinmate.js @@ -561,6 +561,7 @@ module.exports = class coinmate extends Exchange { const statuses = { 'FILLED': 'closed', 'CANCELLED': 'canceled', + 'PARTIALLY_FILLED': 'open', 'OPEN': 'open', }; return this.safeString (statuses, status, status); @@ -623,12 +624,15 @@ module.exports = class coinmate extends Exchange { const price = this.safeFloat (order, 'price'); const amount = this.safeFloat2 (order, 'originalAmount', 'amount'); const remaining = this.safeFloat (order, 'remainingAmount', amount); - const status = this.parseOrderStatus (this.safeString (order, 'status')); + let status = this.parseOrderStatus (this.safeString (order, 'status')); const type = this.parseOrderType (this.safeString (order, 'orderTradeType')); let filled = undefined; let cost = undefined; if ((amount !== undefined) && (remaining !== undefined)) { - filled = amount - remaining; + filled = Math.min (amount - remaining, 0); + if (remaining === 0) { + status = 'closed'; + } if (price !== undefined) { cost = filled * price; } diff --git a/TaskServer/node_modules/ccxt/js/crex24.js b/TaskServer/node_modules/ccxt/js/crex24.js index cb448a0ff..c99799c7e 100644 --- a/TaskServer/node_modules/ccxt/js/crex24.js +++ b/TaskServer/node_modules/ccxt/js/crex24.js @@ -129,7 +129,6 @@ module.exports = class crex24 extends Exchange { 'fetchClosedOrdersMethod': 'tradingGetOrderHistory', // or 'tradingGetActiveOrders' 'fetchTickersMethod': 'publicGetTicker24hr', 'defaultTimeInForce': 'GTC', // 'GTC' = Good To Cancel (default), 'IOC' = Immediate Or Cancel - 'defaultLimitOrderType': 'limit', // or 'limit_maker' 'hasAlreadyAuthenticatedSuccessfully': false, 'warnOnFetchOpenOrdersWithoutSymbol': true, 'parseOrderToPrecision': false, // force amounts and costs in parseOrder to precision diff --git a/TaskServer/node_modules/ccxt/js/deribit.js b/TaskServer/node_modules/ccxt/js/deribit.js index 04f0380a8..6f4827691 100644 --- a/TaskServer/node_modules/ccxt/js/deribit.js +++ b/TaskServer/node_modules/ccxt/js/deribit.js @@ -525,11 +525,13 @@ module.exports = class deribit extends Exchange { 'info': response, }; const balance = this.safeValue (response, 'result', {}); + const currencyId = this.safeString (balance, 'currency'); + const currencyCode = this.safeCurrencyCode (currencyId); const account = this.account (); account['free'] = this.safeFloat (balance, 'availableFunds'); account['used'] = this.safeFloat (balance, 'maintenanceMargin'); account['total'] = this.safeFloat (balance, 'equity'); - result[code] = account; + result[currencyCode] = account; return this.parseBalance (result); } @@ -883,7 +885,7 @@ module.exports = class deribit extends Exchange { // M = maker, T = taker, MT = both takerOrMaker = (liquidity === 'M') ? 'maker' : 'taker'; } - const feeCost = this.safeFloat (trade, 'feeCost'); + const feeCost = this.safeFloat (trade, 'fee'); let fee = undefined; if (feeCost !== undefined) { const feeCurrencyId = this.safeString (trade, 'fee_currency'); diff --git a/TaskServer/node_modules/ccxt/js/exmo.js b/TaskServer/node_modules/ccxt/js/exmo.js index dcf0f2036..6cc36522d 100644 --- a/TaskServer/node_modules/ccxt/js/exmo.js +++ b/TaskServer/node_modules/ccxt/js/exmo.js @@ -3,7 +3,7 @@ // --------------------------------------------------------------------------- const Exchange = require ('./base/Exchange'); -const { ArgumentsRequired, ExchangeError, OrderNotFound, AuthenticationError, InsufficientFunds, InvalidOrder, InvalidNonce, NotSupported, OnMaintenance, RateLimitExceeded } = require ('./base/errors'); +const { ArgumentsRequired, ExchangeError, OrderNotFound, AuthenticationError, InsufficientFunds, InvalidOrder, InvalidNonce, NotSupported, OnMaintenance, RateLimitExceeded, BadRequest, PermissionDenied } = require ('./base/errors'); // --------------------------------------------------------------------------- @@ -14,7 +14,7 @@ module.exports = class exmo extends Exchange { 'name': 'EXMO', 'countries': [ 'ES', 'RU' ], // Spain, Russia 'rateLimit': 350, // once every 350 ms ≈ 180 requests per minute ≈ 3 requests per second - 'version': 'v1', + 'version': 'v1.1', 'has': { 'CORS': false, 'fetchClosedOrders': 'emulated', @@ -32,6 +32,21 @@ module.exports = class exmo extends Exchange { 'fetchFundingFees': true, 'fetchCurrencies': true, 'fetchTransactions': true, + 'fetchOHLCV': true, + }, + 'timeframes': { + '1m': '1', + '5m': '5', + '15m': '15', + '30m': '30', + '45m': '45', + '1h': '60', + '2h': '120', + '3h': '180', + '4h': '240', + '1d': 'D', + '1w': 'W', + '1M': 'M', }, 'urls': { 'logo': 'https://user-images.githubusercontent.com/1294454/27766491-1b0ea956-5eda-11e7-9225-40d67b481b8d.jpg', @@ -62,6 +77,7 @@ module.exports = class exmo extends Exchange { 'pair_settings', 'ticker', 'trades', + 'candles_history', ], }, 'private': { @@ -69,6 +85,8 @@ module.exports = class exmo extends Exchange { 'user_info', 'order_create', 'order_cancel', + 'stop_market_order_create', + 'stop_market_order_cancel', 'user_open_orders', 'user_trades', 'user_cancelled_orders', @@ -103,86 +121,90 @@ module.exports = class exmo extends Exchange { 'error': '', 'data': { 'limits': [ - { 'pair': 'EXM/USDT', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '100000' }, - { 'pair': 'EXM/ETH', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '5000' }, + { 'pair': 'ALGO/EXM', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.001', 'max_p': '10000', 'min_a': '1', 'max_a': '50000000' }, + { 'pair': 'ALGO/BTC', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.000001', 'max_a': '50' }, + { 'pair': 'ATOM/EXM', 'min_q': '1', 'max_q': '500000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '200', 'max_a': '50000000' }, + { 'pair': 'ATOM/BTC', 'min_q': '1', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, { 'pair': 'BTC/USD', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '1', 'max_p': '30000', 'min_a': '1', 'max_a': '500000' }, - { 'pair': 'BTC/KZT', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '1000', 'max_p': '12000000', 'min_a': '1000', 'max_a': '100000000' }, - { 'pair': 'ETH/KZT', 'min_q': '0.001', 'max_q': '5000', 'min_p': '4', 'max_p': '40000000', 'min_a': '3', 'max_a': '500000' }, - { 'pair': 'USDT/KZT', 'min_q': '1', 'max_q': '500000', 'min_p': '200', 'max_p': '4000', 'min_a': '0.1', 'max_a': '500000' }, - { 'pair': 'ONT/EXM', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '200', 'max_a': '15000000' }, - { 'pair': 'ONT/BTC', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.00001', 'max_a': '10' }, - { 'pair': 'ONT/RUB', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '100', 'max_a': '6000000' }, - { 'pair': 'ONT/UAH', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '200', 'max_a': '250000' }, - { 'pair': 'ONG/EXM', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '100', 'max_a': '15000000' }, - { 'pair': 'ONG/BTC', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.00001', 'max_a': '10' }, - { 'pair': 'ONG/RUB', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '100', 'max_a': '250000' }, - { 'pair': 'ONG/UAH', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '50', 'max_a': '6000000' }, - { 'pair': 'CRON/BTC', 'min_q': '1', 'max_q': '100000', 'min_p': '0.0000001', 'max_p': '1', 'min_a': '0.00001', 'max_a': '100' }, - { 'pair': 'CRON/ETH', 'min_q': '1', 'max_q': '100000', 'min_p': '0.0000001', 'max_p': '10', 'min_a': '0.00001', 'max_a': '5000' }, - { 'pair': 'CRON/USDT', 'min_q': '1', 'max_q': '100000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.001', 'max_a': '500000' }, - { 'pair': 'CRON/EXM', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '100000' }, { 'pair': 'BTC/RUB', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '1', 'max_p': '2000000', 'min_a': '10', 'max_a': '50000000' }, { 'pair': 'BTC/EUR', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '1', 'max_p': '30000', 'min_a': '1', 'max_a': '500000' }, { 'pair': 'BTC/UAH', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '1', 'max_p': '15000000', 'min_a': '10', 'max_a': '15000000' }, + { 'pair': 'BTC/GBP', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '1', 'max_p': '30000', 'min_a': '1', 'max_a': '500000' }, + { 'pair': 'ETH/GBP', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '3', 'max_a': '500000' }, + { 'pair': 'XRP/GBP', 'min_q': '1', 'max_q': '5000000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.001', 'max_a': '500000' }, + { 'pair': 'USDT/GBP', 'min_q': '1', 'max_q': '500000', 'min_p': '0.5', 'max_p': '10', 'min_a': '0.1', 'max_a': '500000' }, { 'pair': 'BTC/PLN', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '1', 'max_p': '20000000', 'min_a': '50', 'max_a': '2000000' }, { 'pair': 'BTC/TRY', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '1', 'max_p': '800000', 'min_a': '40', 'max_a': '6000000' }, + { 'pair': 'BTC/KZT', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '1000', 'max_p': '12000000', 'min_a': '1000', 'max_a': '100000000' }, { 'pair': 'BTC/USDT', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '0.01', 'max_p': '30000', 'min_a': '3', 'max_a': '500000' }, { 'pair': 'ETH/BTC', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.001', 'max_a': '100' }, { 'pair': 'ETH/USD', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '3', 'max_a': '500000' }, { 'pair': 'ETH/RUB', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '150', 'max_a': '50000000' }, - { 'pair': 'XRP/BTC', 'min_q': '1', 'max_q': '100000', 'min_p': '0.0000001', 'max_p': '1', 'min_a': '0.00001', 'max_a': '100' }, - { 'pair': 'XRP/USD', 'min_q': '1', 'max_q': '100000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.001', 'max_a': '500000' }, - { 'pair': 'XRP/RUB', 'min_q': '1', 'max_q': '100000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '50000000' }, + { 'pair': 'XRP/BTC', 'min_q': '1', 'max_q': '5000000', 'min_p': '0.0000001', 'max_p': '1', 'min_a': '0.00001', 'max_a': '100' }, + { 'pair': 'XRP/USD', 'min_q': '1', 'max_q': '5000000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.001', 'max_a': '500000' }, + { 'pair': 'XRP/RUB', 'min_q': '1', 'max_q': '5000000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '50000000' }, { 'pair': 'ADA/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, { 'pair': 'ADA/ETH', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.001', 'max_a': '5000' }, { 'pair': 'ADA/USD', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '500000' }, - { 'pair': 'BCH/USD', 'min_q': '0.003', 'max_q': '10000', 'min_p': '0.00000001', 'max_p': '30000', 'min_a': '0.0001', 'max_a': '500000' }, - { 'pair': 'BCH/RUB', 'min_q': '0.003', 'max_q': '10000', 'min_p': '0.00000001', 'max_p': '2000000', 'min_a': '0.0001', 'max_a': '50000000' }, - { 'pair': 'BCH/EUR', 'min_q': '0.003', 'max_q': '100000', 'min_p': '0.01', 'max_p': '300000', 'min_a': '3', 'max_a': '500000' }, - { 'pair': 'BCH/UAH', 'min_q': '0.003', 'max_q': '100000', 'min_p': '0.1', 'max_p': '30000', 'min_a': '10', 'max_a': '15000000' }, - { 'pair': 'BCH/BTC', 'min_q': '0.003', 'max_q': '10000', 'min_p': '0.00000001', 'max_p': '5', 'min_a': '0.0001', 'max_a': '100' }, - { 'pair': 'BCH/ETH', 'min_q': '0.003', 'max_q': '10000', 'min_p': '0.0000001', 'max_p': '200', 'min_a': '0.0001', 'max_a': '5000' }, - { 'pair': 'BCH/USDT', 'min_q': '0.003', 'max_q': '100000', 'min_p': '0.01', 'max_p': '5000', 'min_a': '3', 'max_a': '500000' }, + { 'pair': 'ALGO/USDT', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '1', 'max_a': '500000' }, + { 'pair': 'ALGO/RUB', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.000001', 'max_p': '10000', 'min_a': '1', 'max_a': '50000000' }, + { 'pair': 'ALGO/EUR', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '1', 'max_a': '500000' }, + { 'pair': 'ATOM/USD', 'min_q': '1', 'max_q': '500000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.5', 'max_a': '500000' }, + { 'pair': 'ATOM/EUR', 'min_q': '1', 'max_q': '500000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.5', 'max_a': '500000' }, + { 'pair': 'BCH/USD', 'min_q': '0.003', 'max_q': '5000', 'min_p': '0.00000001', 'max_p': '30000', 'min_a': '0.0001', 'max_a': '500000' }, + { 'pair': 'BCH/RUB', 'min_q': '0.003', 'max_q': '5000', 'min_p': '0.00000001', 'max_p': '2000000', 'min_a': '0.0001', 'max_a': '50000000' }, + { 'pair': 'BCH/EUR', 'min_q': '0.003', 'max_q': '5000', 'min_p': '0.01', 'max_p': '300000', 'min_a': '3', 'max_a': '500000' }, + { 'pair': 'BCH/UAH', 'min_q': '0.003', 'max_q': '5000', 'min_p': '0.1', 'max_p': '30000', 'min_a': '10', 'max_a': '15000000' }, + { 'pair': 'BCH/BTC', 'min_q': '0.003', 'max_q': '5000', 'min_p': '0.00000001', 'max_p': '5', 'min_a': '0.0001', 'max_a': '100' }, + { 'pair': 'BCH/ETH', 'min_q': '0.003', 'max_q': '5000', 'min_p': '0.0000001', 'max_p': '200', 'min_a': '0.0001', 'max_a': '5000' }, + { 'pair': 'BCH/USDT', 'min_q': '0.003', 'max_q': '5000', 'min_p': '0.01', 'max_p': '5000', 'min_a': '3', 'max_a': '500000' }, { 'pair': 'BTCZ/BTC', 'min_q': '100', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, - { 'pair': 'BTG/USD', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '3', 'max_a': '500000' }, - { 'pair': 'BTG/BTC', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, - { 'pair': 'BTG/ETH', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.0001', 'max_p': '100', 'min_a': '0.01', 'max_a': '5000' }, - { 'pair': 'BTT/RUB', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '0.000001', 'max_a': '100' }, - { 'pair': 'BTT/UAH', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '0.000001', 'max_a': '100' }, - { 'pair': 'BTT/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '0.1', 'min_a': '0.00001', 'max_a': '100' }, + { 'pair': 'BTG/USD', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '3', 'max_a': '500000' }, + { 'pair': 'BTG/BTC', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, + { 'pair': 'BTG/ETH', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.0001', 'max_p': '100', 'min_a': '0.01', 'max_a': '5000' }, + { 'pair': 'BTT/RUB', 'min_q': '1', 'max_q': '500000000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '0.000001', 'max_a': '100' }, + { 'pair': 'BTT/UAH', 'min_q': '1', 'max_q': '500000000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '0.000001', 'max_a': '100' }, + { 'pair': 'BTT/BTC', 'min_q': '1', 'max_q': '500000000', 'min_p': '0.00000001', 'max_p': '0.1', 'min_a': '0.00001', 'max_a': '100' }, + { 'pair': 'CRON/BTC', 'min_q': '1', 'max_q': '100000', 'min_p': '0.0000001', 'max_p': '1', 'min_a': '0.00001', 'max_a': '100' }, + { 'pair': 'CRON/ETH', 'min_q': '1', 'max_q': '100000', 'min_p': '0.0000001', 'max_p': '10', 'min_a': '0.00001', 'max_a': '5000' }, + { 'pair': 'CRON/USDT', 'min_q': '1', 'max_q': '100000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.001', 'max_a': '500000' }, + { 'pair': 'CRON/EXM', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '100000' }, { 'pair': 'DAI/USD', 'min_q': '1', 'max_q': '500000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000' }, { 'pair': 'DAI/RUB', 'min_q': '1', 'max_q': '500000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '0.5', 'max_a': '30000000' }, { 'pair': 'DAI/BTC', 'min_q': '1', 'max_q': '500000', 'min_p': '0.0000001', 'max_p': '0.1', 'min_a': '0.00001', 'max_a': '100' }, { 'pair': 'DAI/ETH', 'min_q': '1', 'max_q': '500000', 'min_p': '0.000001', 'max_p': '10', 'min_a': '0.0001', 'max_a': '5000' }, - { 'pair': 'DASH/USD', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '3', 'max_a': '500000' }, - { 'pair': 'DASH/RUB', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '150', 'max_a': '50000000' }, - { 'pair': 'DASH/UAH', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.01', 'max_p': '200000', 'min_a': '10', 'max_a': '15000000' }, - { 'pair': 'DASH/BTC', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.0001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, - { 'pair': 'DASH/USDT', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.01', 'max_p': '5000', 'min_a': '3', 'max_a': '500000' }, + { 'pair': 'DASH/USD', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '3', 'max_a': '500000' }, + { 'pair': 'DASH/RUB', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '150', 'max_a': '50000000' }, + { 'pair': 'DASH/UAH', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.01', 'max_p': '200000', 'min_a': '10', 'max_a': '15000000' }, + { 'pair': 'DASH/BTC', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.0001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, + { 'pair': 'DASH/USDT', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.01', 'max_p': '5000', 'min_a': '3', 'max_a': '500000' }, { 'pair': 'DCR/RUB', 'min_q': '0.01', 'max_q': '50000', 'min_p': '0.00001', 'max_p': '100000', 'min_a': '0.5', 'max_a': '3000000' }, { 'pair': 'DCR/UAH', 'min_q': '0.01', 'max_q': '50000', 'min_p': '0.00001', 'max_p': '100000', 'min_a': '0.25', 'max_a': '1000000' }, { 'pair': 'DCR/BTC', 'min_q': '0.01', 'max_q': '50000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, - { 'pair': 'DOGE/USD', 'min_q': '100', 'max_q': '1000000000', 'min_p': '0.0000001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '500000' }, - { 'pair': 'DOGE/BTC', 'min_q': '100', 'max_q': '100000000', 'min_p': '0.0000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '100' }, - { 'pair': 'DXT/USD', 'min_q': '100', 'max_q': '10000000', 'min_p': '0.00001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000' }, - { 'pair': 'DXT/BTC', 'min_q': '100', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '100' }, - { 'pair': 'EOS/USD', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.01', 'max_p': '1000', 'min_a': '0.5', 'max_a': '500000' }, - { 'pair': 'EOS/EUR', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.5', 'max_a': '500000' }, - { 'pair': 'EOS/BTC', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, - { 'pair': 'ETC/USD', 'min_q': '0.2', 'max_q': '1000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '0.01', 'max_a': '500000' }, - { 'pair': 'ETC/RUB', 'min_q': '0.2', 'max_q': '1000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '0.01', 'max_a': '50000000' }, - { 'pair': 'ETC/BTC', 'min_q': '0.2', 'max_q': '1000', 'min_p': '0.0001', 'max_p': '0.5', 'min_a': '0.001', 'max_a': '100' }, + { 'pair': 'DOGE/USD', 'min_q': '100', 'max_q': '500000000', 'min_p': '0.0000001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '500000' }, + { 'pair': 'DOGE/BTC', 'min_q': '100', 'max_q': '500000000', 'min_p': '0.0000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '100' }, + { 'pair': 'DXT/USD', 'min_q': '100', 'max_q': '50000000', 'min_p': '0.00001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000' }, + { 'pair': 'DXT/BTC', 'min_q': '100', 'max_q': '50000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '100' }, + { 'pair': 'EOS/USD', 'min_q': '0.01', 'max_q': '500000', 'min_p': '0.01', 'max_p': '1000', 'min_a': '0.5', 'max_a': '500000' }, + { 'pair': 'EOS/EUR', 'min_q': '0.01', 'max_q': '500000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.5', 'max_a': '500000' }, + { 'pair': 'EOS/BTC', 'min_q': '0.01', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, + { 'pair': 'ETC/USD', 'min_q': '0.2', 'max_q': '100000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '0.01', 'max_a': '500000' }, + { 'pair': 'ETC/RUB', 'min_q': '0.2', 'max_q': '100000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '0.01', 'max_a': '50000000' }, + { 'pair': 'ETC/BTC', 'min_q': '0.2', 'max_q': '100000', 'min_p': '0.0001', 'max_p': '0.5', 'min_a': '0.001', 'max_a': '100' }, { 'pair': 'ETH/EUR', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '3', 'max_a': '500000' }, { 'pair': 'ETH/UAH', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.01', 'max_p': '1000000', 'min_a': '90', 'max_a': '15000000' }, { 'pair': 'ETH/PLN', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '50', 'max_a': '2000000' }, { 'pair': 'ETH/TRY', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.1', 'max_p': '80000', 'min_a': '10', 'max_a': '6000000' }, + { 'pair': 'ETH/KZT', 'min_q': '0.001', 'max_q': '5000', 'min_p': '4', 'max_p': '40000000', 'min_a': '3', 'max_a': '500000' }, { 'pair': 'ETH/USDT', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '3', 'max_a': '500000' }, { 'pair': 'ETH/LTC', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.00000001', 'max_p': '100000', 'min_a': '0.05', 'max_a': '100000' }, - { 'pair': 'ETZ/BTC', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '10' }, - { 'pair': 'ETZ/ETH', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.00000001', 'max_p': '100', 'min_a': '0.001', 'max_a': '100' }, - { 'pair': 'ETZ/USDT', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '1000' }, - { 'pair': 'GAS/USD', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.01', 'max_p': '50000', 'min_a': '0.1', 'max_a': '500000' }, - { 'pair': 'GAS/BTC', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, + { 'pair': 'ETZ/BTC', 'min_q': '1', 'max_q': '50000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '10' }, + { 'pair': 'ETZ/ETH', 'min_q': '1', 'max_q': '50000000', 'min_p': '0.00000001', 'max_p': '100', 'min_a': '0.001', 'max_a': '100' }, + { 'pair': 'ETZ/USDT', 'min_q': '1', 'max_q': '50000000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '1000' }, + { 'pair': 'EXM/USDT', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '100000' }, + { 'pair': 'EXM/ETH', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '5000' }, + { 'pair': 'GAS/USD', 'min_q': '0.01', 'max_q': '500000', 'min_p': '0.01', 'max_p': '50000', 'min_a': '0.1', 'max_a': '500000' }, + { 'pair': 'GAS/BTC', 'min_q': '0.01', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, { 'pair': 'GNT/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, { 'pair': 'GNT/ETH', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.01', 'max_a': '5000' }, { 'pair': 'GUSD/USD', 'min_q': '1', 'max_q': '500000', 'min_p': '0.1', 'max_p': '10', 'min_a': '0.1', 'max_a': '500000' }, @@ -197,84 +219,94 @@ module.exports = class exmo extends Exchange { { 'pair': 'KICK/USDT', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '100000' }, { 'pair': 'KICK/BTC', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '0.1', 'min_a': '0.00001', 'max_a': '100' }, { 'pair': 'KICK/ETH', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '5000' }, - { 'pair': 'LSK/USD', 'min_q': '0.1', 'max_q': '200000', 'min_p': '0.1', 'max_p': '1000', 'min_a': '1', 'max_a': '500000' }, - { 'pair': 'LSK/RUB', 'min_q': '0.1', 'max_q': '200000', 'min_p': '0.001', 'max_p': '100000', 'min_a': '0.5', 'max_a': '50000000' }, - { 'pair': 'LSK/BTC', 'min_q': '1', 'max_q': '200000', 'min_p': '0.0000001', 'max_p': '1', 'min_a': '0.0015', 'max_a': '100' }, - { 'pair': 'LTC/USD', 'min_q': '0.05', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '3', 'max_a': '500000' }, - { 'pair': 'LTC/RUB', 'min_q': '0.05', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '150', 'max_a': '50000000' }, - { 'pair': 'LTC/EUR', 'min_q': '0.05', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '3', 'max_a': '500000' }, - { 'pair': 'LTC/UAH', 'min_q': '0.05', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '300000', 'min_a': '5', 'max_a': '18000000' }, - { 'pair': 'LTC/BTC', 'min_q': '0.05', 'max_q': '1000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, + { 'pair': 'LSK/USD', 'min_q': '0.1', 'max_q': '500000', 'min_p': '0.1', 'max_p': '1000', 'min_a': '1', 'max_a': '500000' }, + { 'pair': 'LSK/RUB', 'min_q': '0.1', 'max_q': '500000', 'min_p': '0.001', 'max_p': '100000', 'min_a': '0.5', 'max_a': '50000000' }, + { 'pair': 'LSK/BTC', 'min_q': '1', 'max_q': '500000', 'min_p': '0.0000001', 'max_p': '1', 'min_a': '0.0015', 'max_a': '100' }, + { 'pair': 'LTC/USD', 'min_q': '0.05', 'max_q': '10000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '3', 'max_a': '500000' }, + { 'pair': 'LTC/RUB', 'min_q': '0.05', 'max_q': '10000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '150', 'max_a': '50000000' }, + { 'pair': 'LTC/EUR', 'min_q': '0.05', 'max_q': '10000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '3', 'max_a': '500000' }, + { 'pair': 'LTC/UAH', 'min_q': '0.05', 'max_q': '10000', 'min_p': '0.01', 'max_p': '300000', 'min_a': '5', 'max_a': '18000000' }, + { 'pair': 'LTC/BTC', 'min_q': '0.05', 'max_q': '10000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, { 'pair': 'MKR/BTC', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '0.0001', 'max_p': '100', 'min_a': '0.000001', 'max_a': '100' }, { 'pair': 'MKR/DAI', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '0.5', 'max_p': '500000', 'min_a': '0.005', 'max_a': '500000' }, - { 'pair': 'MNC/USD', 'min_q': '10', 'max_q': '100000000', 'min_p': '0.000001', 'max_p': '10000', 'min_a': '0.01', 'max_a': '100000' }, - { 'pair': 'MNC/BTC', 'min_q': '10', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.000001', 'max_a': '100' }, - { 'pair': 'MNC/ETH', 'min_q': '10', 'max_q': '100000000', 'min_p': '0.0000001', 'max_p': '10', 'min_a': '0.00001', 'max_a': '1000' }, + { 'pair': 'MNC/USD', 'min_q': '10', 'max_q': '500000000', 'min_p': '0.000001', 'max_p': '10000', 'min_a': '0.01', 'max_a': '100000' }, + { 'pair': 'MNC/BTC', 'min_q': '10', 'max_q': '500000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.000001', 'max_a': '100' }, + { 'pair': 'MNC/ETH', 'min_q': '10', 'max_q': '500000000', 'min_p': '0.0000001', 'max_p': '10', 'min_a': '0.00001', 'max_a': '1000' }, { 'pair': 'MNX/USD', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.5', 'max_a': '500000' }, { 'pair': 'MNX/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, { 'pair': 'MNX/ETH', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.01', 'max_a': '5000' }, - { 'pair': 'NEO/USD', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.01', 'max_p': '50000', 'min_a': '0.1', 'max_a': '500000' }, - { 'pair': 'NEO/RUB', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.001', 'max_p': '1500000', 'min_a': '50', 'max_a': '50000000' }, - { 'pair': 'NEO/BTC', 'min_q': '0.1', 'max_q': '200000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, - { 'pair': 'OMG/USD', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.01', 'max_p': '1000', 'min_a': '0.5', 'max_a': '500000' }, - { 'pair': 'OMG/BTC', 'min_q': '1', 'max_q': '100000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, - { 'pair': 'OMG/ETH', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.01', 'max_a': '5000' }, - { 'pair': 'PTI/RUB', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '600000', 'min_a': '10', 'max_a': '600000' }, - { 'pair': 'PTI/BTC', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.000001', 'max_a': '10' }, - { 'pair': 'PTI/EOS', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.0000001', 'max_p': '5000', 'min_a': '0.01', 'max_a': '20000' }, - { 'pair': 'PTI/USDT', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.000001', 'max_p': '10000', 'min_a': '0.01', 'max_a': '100000' }, - { 'pair': 'QTUM/USD', 'min_q': '0.1', 'max_q': '200000', 'min_p': '0.00000001', 'max_p': '10000', 'min_a': '0.1', 'max_a': '500000' }, - { 'pair': 'QTUM/BTC', 'min_q': '0.1', 'max_q': '200000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '100' }, - { 'pair': 'QTUM/ETH', 'min_q': '0.1', 'max_q': '200000', 'min_p': '0.00000001', 'max_p': '100', 'min_a': '0.001', 'max_a': '5000' }, + { 'pair': 'NEO/USD', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.01', 'max_p': '50000', 'min_a': '0.1', 'max_a': '500000' }, + { 'pair': 'NEO/RUB', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.001', 'max_p': '1500000', 'min_a': '50', 'max_a': '50000000' }, + { 'pair': 'NEO/BTC', 'min_q': '0.1', 'max_q': '100000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, + { 'pair': 'OMG/USD', 'min_q': '0.01', 'max_q': '500000', 'min_p': '0.01', 'max_p': '1000', 'min_a': '0.5', 'max_a': '500000' }, + { 'pair': 'OMG/BTC', 'min_q': '1', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, + { 'pair': 'OMG/ETH', 'min_q': '0.01', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.01', 'max_a': '5000' }, + { 'pair': 'ONG/EXM', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '100', 'max_a': '15000000' }, + { 'pair': 'ONG/BTC', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.00001', 'max_a': '10' }, + { 'pair': 'ONG/RUB', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '100', 'max_a': '250000' }, + { 'pair': 'ONG/UAH', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '50', 'max_a': '6000000' }, + { 'pair': 'ONT/EXM', 'min_q': '1', 'max_q': '500000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '200', 'max_a': '15000000' }, + { 'pair': 'ONT/BTC', 'min_q': '1', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.00001', 'max_a': '10' }, + { 'pair': 'ONT/RUB', 'min_q': '1', 'max_q': '500000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '100', 'max_a': '6000000' }, + { 'pair': 'ONT/UAH', 'min_q': '1', 'max_q': '500000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '200', 'max_a': '250000' }, + { 'pair': 'PTI/RUB', 'min_q': '1', 'max_q': '50000000', 'min_p': '0.00000001', 'max_p': '600000', 'min_a': '10', 'max_a': '600000' }, + { 'pair': 'PTI/BTC', 'min_q': '1', 'max_q': '50000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.000001', 'max_a': '10' }, + { 'pair': 'PTI/EOS', 'min_q': '1', 'max_q': '50000000', 'min_p': '0.0000001', 'max_p': '5000', 'min_a': '0.01', 'max_a': '20000' }, + { 'pair': 'PTI/USDT', 'min_q': '1', 'max_q': '50000000', 'min_p': '0.000001', 'max_p': '10000', 'min_a': '0.01', 'max_a': '100000' }, + { 'pair': 'QTUM/USD', 'min_q': '0.1', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '10000', 'min_a': '0.1', 'max_a': '500000' }, + { 'pair': 'QTUM/BTC', 'min_q': '0.1', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '100' }, + { 'pair': 'QTUM/ETH', 'min_q': '0.1', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '100', 'min_a': '0.001', 'max_a': '5000' }, { 'pair': 'ROOBEE/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '0.1', 'min_a': '0.00001', 'max_a': '100' }, - { 'pair': 'SMART/USD', 'min_q': '10', 'max_q': '10000000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '1', 'max_a': '500000' }, - { 'pair': 'SMART/RUB', 'min_q': '10', 'max_q': '10000000', 'min_p': '0.0001', 'max_p': '100000', 'min_a': '10', 'max_a': '50000000' }, - { 'pair': 'SMART/EUR', 'min_q': '10', 'max_q': '10000000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '1', 'max_a': '500000' }, - { 'pair': 'SMART/BTC', 'min_q': '10', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.00001', 'max_a': '100' }, - { 'pair': 'TRX/USD', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '500000' }, - { 'pair': 'TRX/RUB', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.000001', 'max_p': '100000', 'min_a': '0.1', 'max_a': '50000000' }, - { 'pair': 'TRX/UAH', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.000001', 'max_p': '100000', 'min_a': '0.1', 'max_a': '50000000' }, - { 'pair': 'TRX/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, + { 'pair': 'SMART/USD', 'min_q': '10', 'max_q': '100000000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '1', 'max_a': '500000' }, + { 'pair': 'SMART/RUB', 'min_q': '10', 'max_q': '100000000', 'min_p': '0.0001', 'max_p': '100000', 'min_a': '10', 'max_a': '50000000' }, + { 'pair': 'SMART/EUR', 'min_q': '10', 'max_q': '100000000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '1', 'max_a': '500000' }, + { 'pair': 'SMART/BTC', 'min_q': '10', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.00001', 'max_a': '100' }, + { 'pair': 'TRX/USD', 'min_q': '1', 'max_q': '50000000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '500000' }, + { 'pair': 'TRX/EUR', 'min_q': '0.01', 'max_q': '50000000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '500000' }, + { 'pair': 'TRX/RUB', 'min_q': '1', 'max_q': '50000000', 'min_p': '0.000001', 'max_p': '100000', 'min_a': '0.1', 'max_a': '50000000' }, + { 'pair': 'TRX/UAH', 'min_q': '1', 'max_q': '50000000', 'min_p': '0.000001', 'max_p': '100000', 'min_a': '0.1', 'max_a': '50000000' }, + { 'pair': 'TRX/BTC', 'min_q': '1', 'max_q': '50000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, { 'pair': 'USDC/USD', 'min_q': '1', 'max_q': '500000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '3', 'max_a': '500000' }, { 'pair': 'USDC/BTC', 'min_q': '1', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '100' }, { 'pair': 'USDC/ETH', 'min_q': '1', 'max_q': '500000', 'min_p': '0.0000001', 'max_p': '100', 'min_a': '0.001', 'max_a': '1000' }, { 'pair': 'USDC/USDT', 'min_q': '1', 'max_q': '500000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '3', 'max_a': '500000' }, { 'pair': 'USDT/USD', 'min_q': '1', 'max_q': '500000', 'min_p': '0.5', 'max_p': '10', 'min_a': '0.1', 'max_a': '500000' }, { 'pair': 'USDT/RUB', 'min_q': '1', 'max_q': '500000', 'min_p': '0.01', 'max_p': '1000', 'min_a': '10', 'max_a': '50000000' }, - { 'pair': 'USDT/EUR', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.1', 'max_p': '10', 'min_a': '0.1', 'max_a': '500000' }, - { 'pair': 'USDT/UAH', 'min_q': '0.01', 'max_q': '100000', 'min_p': '1', 'max_p': '3000', 'min_a': '2', 'max_a': '15000000' }, + { 'pair': 'USDT/EUR', 'min_q': '0.01', 'max_q': '500000', 'min_p': '0.1', 'max_p': '10', 'min_a': '0.1', 'max_a': '500000' }, + { 'pair': 'USDT/UAH', 'min_q': '0.01', 'max_q': '500000', 'min_p': '1', 'max_p': '3000', 'min_a': '2', 'max_a': '15000000' }, + { 'pair': 'USDT/KZT', 'min_q': '1', 'max_q': '500000', 'min_p': '200', 'max_p': '4000', 'min_a': '0.1', 'max_a': '500000' }, { 'pair': 'VLX/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '0.1', 'min_a': '0.00001', 'max_a': '100' }, - { 'pair': 'WAVES/USD', 'min_q': '0.5', 'max_q': '10000', 'min_p': '0.001', 'max_p': '3500', 'min_a': '0.5', 'max_a': '500000' }, - { 'pair': 'WAVES/RUB', 'min_q': '0.5', 'max_q': '10000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '1', 'max_a': '50000000' }, - { 'pair': 'WAVES/BTC', 'min_q': '0.5', 'max_q': '10000', 'min_p': '0.000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '100' }, - { 'pair': 'WAVES/ETH', 'min_q': '0.5', 'max_q': '10000', 'min_p': '0.00001', 'max_p': '30', 'min_a': '0.0035', 'max_a': '3500' }, - { 'pair': 'XEM/USD', 'min_q': '10', 'max_q': '5000000', 'min_p': '0.00001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000' }, - { 'pair': 'XEM/EUR', 'min_q': '10', 'max_q': '5000000', 'min_p': '0.00001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000' }, - { 'pair': 'XEM/UAH', 'min_q': '1', 'max_q': '5000000', 'min_p': '0.0001', 'max_p': '30000', 'min_a': '10', 'max_a': '15000000' }, - { 'pair': 'XEM/BTC', 'min_q': '10', 'max_q': '5000000', 'min_p': '0.0000001', 'max_p': '1', 'min_a': '0.00015', 'max_a': '100' }, - { 'pair': 'XLM/USD', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '500000' }, - { 'pair': 'XLM/RUB', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.00001', 'max_p': '100000', 'min_a': '0.1', 'max_a': '50000000' }, - { 'pair': 'XLM/TRY', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.00001', 'max_p': '100000', 'min_a': '0.1', 'max_a': '6000000' }, - { 'pair': 'XLM/BTC', 'min_q': '1', 'max_q': '200000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, - { 'pair': 'XMR/USD', 'min_q': '0.01', 'max_q': '1000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000' }, - { 'pair': 'XMR/RUB', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.001', 'max_p': '600000', 'min_a': '10', 'max_a': '16000000' }, - { 'pair': 'XMR/EUR', 'min_q': '0.01', 'max_q': '1000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000' }, - { 'pair': 'XMR/UAH', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.001', 'max_p': '300000', 'min_a': '5', 'max_a': '16000000' }, - { 'pair': 'XMR/BTC', 'min_q': '0.01', 'max_q': '1000', 'min_p': '0.0001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, - { 'pair': 'XMR/ETH', 'min_q': '0.01', 'max_q': '1000', 'min_p': '0.00000001', 'max_p': '100', 'min_a': '0.001', 'max_a': '5000' }, - { 'pair': 'XRP/EUR', 'min_q': '1', 'max_q': '100000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.001', 'max_a': '500000' }, - { 'pair': 'XRP/TRY', 'min_q': '1', 'max_q': '100000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '6000000' }, - { 'pair': 'XRP/UAH', 'min_q': '1', 'max_q': '100000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '15000000' }, - { 'pair': 'XRP/USDT', 'min_q': '1', 'max_q': '100000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.001', 'max_a': '500000' }, - { 'pair': 'XRP/ETH', 'min_q': '1', 'max_q': '100000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.00001', 'max_a': '5000' }, + { 'pair': 'WAVES/USD', 'min_q': '0.5', 'max_q': '500000', 'min_p': '0.001', 'max_p': '3500', 'min_a': '0.5', 'max_a': '500000' }, + { 'pair': 'WAVES/RUB', 'min_q': '0.5', 'max_q': '500000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '1', 'max_a': '50000000' }, + { 'pair': 'WAVES/BTC', 'min_q': '0.5', 'max_q': '500000', 'min_p': '0.000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '100' }, + { 'pair': 'WAVES/ETH', 'min_q': '0.5', 'max_q': '500000', 'min_p': '0.00001', 'max_p': '30', 'min_a': '0.0035', 'max_a': '3500' }, + { 'pair': 'XEM/USD', 'min_q': '10', 'max_q': '10000000', 'min_p': '0.00001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000' }, + { 'pair': 'XEM/EUR', 'min_q': '10', 'max_q': '10000000', 'min_p': '0.00001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000' }, + { 'pair': 'XEM/UAH', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.0001', 'max_p': '30000', 'min_a': '10', 'max_a': '15000000' }, + { 'pair': 'XEM/BTC', 'min_q': '10', 'max_q': '10000000', 'min_p': '0.0000001', 'max_p': '1', 'min_a': '0.00015', 'max_a': '100' }, + { 'pair': 'XLM/USD', 'min_q': '0.01', 'max_q': '5000000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '500000' }, + { 'pair': 'XLM/RUB', 'min_q': '0.01', 'max_q': '5000000', 'min_p': '0.00001', 'max_p': '100000', 'min_a': '0.1', 'max_a': '50000000' }, + { 'pair': 'XLM/TRY', 'min_q': '0.01', 'max_q': '5000000', 'min_p': '0.00001', 'max_p': '100000', 'min_a': '0.1', 'max_a': '6000000' }, + { 'pair': 'XLM/BTC', 'min_q': '1', 'max_q': '5000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, + { 'pair': 'XMR/USD', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000' }, + { 'pair': 'XMR/RUB', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.001', 'max_p': '600000', 'min_a': '10', 'max_a': '16000000' }, + { 'pair': 'XMR/EUR', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000' }, + { 'pair': 'XMR/UAH', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.001', 'max_p': '300000', 'min_a': '5', 'max_a': '16000000' }, + { 'pair': 'XMR/BTC', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.0001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, + { 'pair': 'XMR/ETH', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.00000001', 'max_p': '100', 'min_a': '0.001', 'max_a': '5000' }, + { 'pair': 'XRP/EUR', 'min_q': '1', 'max_q': '5000000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.001', 'max_a': '500000' }, + { 'pair': 'XRP/TRY', 'min_q': '1', 'max_q': '5000000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '6000000' }, + { 'pair': 'XRP/UAH', 'min_q': '1', 'max_q': '5000000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '15000000' }, + { 'pair': 'XRP/USDT', 'min_q': '1', 'max_q': '5000000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.001', 'max_a': '500000' }, + { 'pair': 'XRP/ETH', 'min_q': '1', 'max_q': '5000000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.00001', 'max_a': '5000' }, { 'pair': 'XTZ/USD', 'min_q': '0.1', 'max_q': '100000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '100000' }, { 'pair': 'XTZ/RUB', 'min_q': '0.1', 'max_q': '100000', 'min_p': '0.00001', 'max_p': '100000', 'min_a': '0.5', 'max_a': '500000' }, { 'pair': 'XTZ/BTC', 'min_q': '0.1', 'max_q': '100000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.00001', 'max_a': '10' }, { 'pair': 'XTZ/ETH', 'min_q': '0.1', 'max_q': '100000', 'min_p': '0.0000001', 'max_p': '10', 'min_a': '0.0001', 'max_a': '1000' }, - { 'pair': 'ZEC/USD', 'min_q': '0.01', 'max_q': '1000', 'min_p': '0.001', 'max_p': '5000', 'min_a': '0.1', 'max_a': '500000' }, - { 'pair': 'ZEC/RUB', 'min_q': '0.01', 'max_q': '1000', 'min_p': '0.001', 'max_p': '100000', 'min_a': '0.1', 'max_a': '50000000' }, - { 'pair': 'ZEC/EUR', 'min_q': '0.01', 'max_q': '1000', 'min_p': '0.001', 'max_p': '5000', 'min_a': '0.1', 'max_a': '500000' }, - { 'pair': 'ZEC/BTC', 'min_q': '0.01', 'max_q': '1000', 'min_p': '0.00001', 'max_p': '10', 'min_a': '0.001', 'max_a': '100' }, + { 'pair': 'ZEC/USD', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.001', 'max_p': '5000', 'min_a': '0.1', 'max_a': '500000' }, + { 'pair': 'ZEC/RUB', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.001', 'max_p': '100000', 'min_a': '0.1', 'max_a': '50000000' }, + { 'pair': 'ZEC/EUR', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.001', 'max_p': '5000', 'min_a': '0.1', 'max_a': '500000' }, + { 'pair': 'ZEC/BTC', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.00001', 'max_p': '10', 'min_a': '0.001', 'max_a': '100' }, { 'pair': 'ZRX/USD', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000' }, { 'pair': 'ZRX/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, { 'pair': 'ZRX/ETH', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.01', 'max_a': '5000' }, @@ -337,6 +369,8 @@ module.exports = class exmo extends Exchange { { 'prov': 'CRON', 'dep': '0%', 'wd': '5 CRON' }, { 'prov': 'ONT', 'dep': '0%', 'wd': '1 ONT' }, { 'prov': 'ONG', 'dep': '0%', 'wd': '5 ONG' }, + { 'prov': 'ALGO', 'dep': '0%', 'wd': '0.01 ALGO' }, + { 'prov': 'ATOM', 'dep': '0%', 'wd': '' }, ], }, { @@ -345,9 +379,10 @@ module.exports = class exmo extends Exchange { 'items': [ { 'prov': 'EX-CODE', 'dep': '', 'wd': '0.2%' }, { 'prov': 'Payeer', 'dep': '3.95%', 'wd': '-' }, - { 'prov': 'AdvCash', 'dep': '0%', 'wd': '3.99%' }, + { 'prov': 'AdvCash', 'dep': '0%', 'wd': '3.49%' }, { 'prov': 'Visa/MasterCard (Simplex)', 'dep': '4.5% + 0.5 USD', 'wd': '-' }, { 'prov': 'Visa', 'dep': '3.45%', 'wd': '-' }, + { 'prov': 'Frick Bank', 'dep': '0 USD', 'wd': '-' }, ], }, { @@ -355,22 +390,24 @@ module.exports = class exmo extends Exchange { 'title': 'EUR', 'items': [ { 'prov': 'EX-CODE', 'dep': '', 'wd': '0.2%' }, - { 'prov': 'Visa/MasterCard (Simplex)', 'dep': '4.5% + 0.5 EUR', 'wd': '-' }, + { 'prov': 'Visa/MasterCard', 'dep': '4.5% + 0.5 EUR', 'wd': '-' }, { 'prov': 'Visa', 'dep': '2.95%', 'wd': '-' }, - { 'prov': 'SEPA', 'dep': '10 EUR', 'wd': '50 EUR' }, + { 'prov': 'Frick Internal Transfer', 'dep': '0 EUR', 'wd': '-' }, + { 'prov': 'SEPA Frick Bank', 'dep': '0 EUR', 'wd': '-' }, + { 'prov': 'WIRE Frick Bank', 'dep': '0%', 'wd': '-' }, + { 'prov': 'SEPA Weg Ag', 'dep': '-', 'wd': '1 EUR' }, ], }, { 'group': 'rub', 'title': 'RUB', 'items': [ - { 'prov': 'Payeer', 'dep': '2.49%', 'wd': '-' }, + { 'prov': 'Payeer', 'dep': '2.49%', 'wd': '3.99%' }, { 'prov': 'EX-CODE', 'dep': '', 'wd': '0.2%' }, - { 'prov': 'Qiwi', 'dep': '0.99%', 'wd': '2%' }, - { 'prov': 'Yandex Money', 'dep': '1.95%', 'wd': '-' }, - { 'prov': 'Enfins', 'dep': '0%', 'wd': '1.49%' }, - { 'prov': 'AdvCash', 'dep': '0%', 'wd': '2.49%' }, - { 'prov': 'Visa/MasterCard', 'dep': '1.99%', 'wd': '4.49% + 60 RUB' }, + { 'prov': 'Qiwi', 'dep': '1.49%', 'wd': '2.49%' }, + { 'prov': 'Yandex Money', 'dep': '1.49%', 'wd': '-' }, + { 'prov': 'AdvCash', 'dep': '0%', 'wd': '3.49%' }, + { 'prov': 'Visa/MasterCard', 'dep': '2.99%', 'wd': '3.99% + 60 RUB' }, ], }, { @@ -378,7 +415,6 @@ module.exports = class exmo extends Exchange { 'title': 'PLN', 'items': [ { 'prov': 'EX-CODE', 'dep': '', 'wd': '0.2%' }, - { 'prov': 'Visa/MasterCard (Simplex)', 'dep': '4.5% + 1 PLN', 'wd': '-' }, ], }, { @@ -388,6 +424,7 @@ module.exports = class exmo extends Exchange { { 'prov': 'EX-CODE', 'dep': '', 'wd': '0.2%' }, { 'prov': 'Visa', 'dep': '3.05%', 'wd': '-' }, { 'prov': 'Visa/MasterCard (Simplex)', 'dep': '4.5% + 2 TRY', 'wd': '-' }, + { 'prov': 'AdvCash', 'dep': '0%', 'wd': '-' }, ], }, { @@ -396,17 +433,18 @@ module.exports = class exmo extends Exchange { 'items': [ { 'prov': 'EX-CODE', 'dep': '', 'wd': '0.2%' }, { 'prov': 'Terminal', 'dep': '2.6%', 'wd': '-' }, - { 'prov': 'Enfins', 'dep': '0%', 'wd': '1.95%' }, - { 'prov': 'Visa/MasterCard', 'dep': '1% + 5 UAH', 'wd': '2.99%' }, + { 'prov': 'Visa/MasterCard', 'dep': '1% + 5 UAH', 'wd': '-' }, + { 'prov': 'Visa/MasterCard EasyTransfer', 'dep': '-', 'wd': '2.99%' }, ], }, { 'group': 'kzt', 'title': 'KZT', 'items': [ + { 'prov': 'EX-CODE', 'dep': '', 'wd': '0.2%' }, { 'prov': 'Visa/MasterCard RoyalPay', 'dep': '-', 'wd': '2.99% + 450 KZT' }, { 'prov': 'Visa/MasterCard', 'dep': '3.5%', 'wd': '-' }, - { 'prov': 'AdvCash', 'dep': '0%', 'wd': '1.49%' }, + { 'prov': 'AdvCash', 'dep': '0%', 'wd': '-' }, ], }, ], @@ -420,6 +458,7 @@ module.exports = class exmo extends Exchange { '40015': ExchangeError, // API function do not exist '40016': OnMaintenance, // {"result":false,"error":"Error 40016: Maintenance work in progress"} '40017': AuthenticationError, // Wrong API Key + '40032': PermissionDenied, // {"result":false,"error":"Error 40032: Access is denied for this API key"} '40034': RateLimitExceeded, // {"result":false,"error":"Error 40034: Access is denied, rate limit is exceeded"} '50052': InsufficientFunds, '50054': InsufficientFunds, @@ -429,6 +468,8 @@ module.exports = class exmo extends Exchange { '50321': InvalidOrder, // Price by order is more than permissible maximum for this pair }, 'broad': { + 'range period is too long': BadRequest, + 'invalid syntax': BadRequest, 'API rate limit exceeded': RateLimitExceeded, // {"result":false,"error":"API rate limit exceeded for 99.33.55.224. Retry after 60 sec.","history":[],"begin":1579392000,"end":1579478400} }, }, @@ -590,8 +631,21 @@ module.exports = class exmo extends Exchange { } async fetchMarkets (params = {}) { - const fees = await this.fetchTradingFees (); const response = await this.publicGetPairSettings (params); + // + // { + // "EXM_ETH": { + // "min_quantity": "1", + // "max_quantity": "1000", + // "min_price": "1", + // "max_price": "1000", + // "max_amount": "1000", + // "min_amount": "1", + // "commission_taker_percent": "0.2", + // "commission_maker_percent": "0.2" + // }, + // } + // const keys = Object.keys (response); const result = []; for (let i = 0; i < keys.length; i++) { @@ -601,6 +655,8 @@ module.exports = class exmo extends Exchange { const [ baseId, quoteId ] = symbol.split ('/'); const base = this.safeCurrencyCode (baseId); const quote = this.safeCurrencyCode (quoteId); + const taker = this.safeFloat (market, 'commission_taker_percent'); + const maker = this.safeFloat (market, 'commission_maker_percent'); result.push ({ 'id': id, 'symbol': symbol, @@ -609,8 +665,8 @@ module.exports = class exmo extends Exchange { 'baseId': baseId, 'quoteId': quoteId, 'active': true, - 'taker': fees['taker'], - 'maker': fees['maker'], + 'taker': taker / 100, + 'maker': maker / 100, 'limits': { 'amount': { 'min': this.safeFloat (market, 'min_quantity'), @@ -635,6 +691,74 @@ module.exports = class exmo extends Exchange { return result; } + async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) { + await this.loadMarkets (); + const market = this.market (symbol); + const request = { + 'symbol': market['id'], + 'resolution': this.timeframes[timeframe], + }; + const options = this.safeValue (this.options, 'fetchOHLCV'); + const maxLimit = this.safeInteger (options, 'maxLimit', 3000); + const duration = this.parseTimeframe (timeframe); + const now = this.milliseconds (); + if (since === undefined) { + if (limit === undefined) { + throw new ArgumentsRequired (this.id + ' fetchOHLCV requires a since argument or a limit argument'); + } else { + if (limit > maxLimit) { + throw new BadRequest (this.id + ' fetchOHLCV will serve ' + maxLimit.toString () + ' candles at most'); + } + request['from'] = parseInt (now / 1000) - limit * duration - 1; + request['to'] = parseInt (now / 1000); + } + } else { + request['from'] = parseInt (since / 1000) - 1; + if (limit === undefined) { + request['to'] = parseInt (now / 1000); + } else { + if (limit > maxLimit) { + throw new BadRequest (this.id + ' fetchOHLCV will serve ' + maxLimit.toString () + ' candles at most'); + } + const to = this.sum (since, limit * duration * 1000); + request['to'] = parseInt (to / 1000); + } + } + const response = await this.publicGetCandlesHistory (this.extend (request, params)); + // + // { + // "candles":[ + // {"t":1584057600000,"o":0.02235144,"c":0.02400233,"h":0.025171,"l":0.02221,"v":5988.34031761}, + // {"t":1584144000000,"o":0.0240373,"c":0.02367413,"h":0.024399,"l":0.0235,"v":2027.82522329}, + // {"t":1584230400000,"o":0.02363458,"c":0.02319242,"h":0.0237948,"l":0.02223196,"v":1707.96944997}, + // ] + // } + // + const candles = this.safeValue (response, 'candles', []); + return this.parseOHLCVs (candles, market, timeframe, since, limit); + } + + parseOHLCV (ohlcv, market = undefined, timeframe = '5m', since = undefined, limit = undefined) { + // + // { + // "t":1584057600000, + // "o":0.02235144, + // "c":0.02400233, + // "h":0.025171, + // "l":0.02221, + // "v":5988.34031761 + // } + // + return [ + this.safeInteger (ohlcv, 't'), + this.safeFloat (ohlcv, 'o'), + this.safeFloat (ohlcv, 'h'), + this.safeFloat (ohlcv, 'l'), + this.safeFloat (ohlcv, 'c'), + this.safeFloat (ohlcv, 'v'), + ]; + } + async fetchBalance (params = {}) { await this.loadMarkets (); const response = await this.privatePostUserInfo (params); @@ -758,8 +882,36 @@ module.exports = class exmo extends Exchange { } parseTrade (trade, market = undefined) { + // + // fetchTrades (public) + // + // { + // "trade_id":165087520, + // "date":1587470005, + // "type":"buy", + // "quantity":"1.004", + // "price":"0.02491461", + // "amount":"0.02501426" + // }, + // + // fetchMyTrades, fetchOrderTrades + // + // { + // "trade_id": 3, + // "date": 1435488248, + // "type": "buy", + // "pair": "BTC_USD", + // "order_id": 12345, + // "quantity": 1, + // "price": 100, + // "amount": 100, + // "exec_type": "taker", + // "commission_amount": "0.02", + // "commission_currency": "BTC", + // "commission_percent": "0.2" + // } + // const timestamp = this.safeTimestamp (trade, 'date'); - let fee = undefined; let symbol = undefined; const id = this.safeString (trade, 'trade_id'); const orderId = this.safeString (trade, 'order_id'); @@ -768,24 +920,35 @@ module.exports = class exmo extends Exchange { const cost = this.safeFloat (trade, 'amount'); const side = this.safeString (trade, 'type'); const type = undefined; - if (market !== undefined) { + const marketId = this.safeString (trade, 'pair'); + if (marketId !== undefined) { + if (marketId in this.markets_by_id) { + market = this.markets_by_id[marketId]; + } else { + const [ baseId, quoteId ] = marketId.split ('_'); + const base = this.safeCurrencyCode (baseId); + const quote = this.safeCurrencyCode (quoteId); + symbol = base + '/' + quote; + } + } + if ((symbol === undefined) && (market !== undefined)) { symbol = market['symbol']; - if (market['taker'] !== market['maker']) { - throw new ExchangeError (this.id + ' parseTrade can not deduce proper fee costs, taker and maker fees now differ'); - } - if ((side === 'buy') && (amount !== undefined)) { - fee = { - 'currency': market['base'], - 'cost': amount * market['taker'], - 'rate': market['taker'], - }; - } else if ((side === 'sell') && (cost !== undefined)) { - fee = { - 'currency': market['quote'], - 'cost': cost * market['taker'], - 'rate': market['taker'], - }; + } + const takerOrMaker = this.safeString (trade, 'exec_type'); + let fee = undefined; + const feeCost = this.safeFloat (trade, 'commission_amount'); + if (feeCost !== undefined) { + const feeCurrencyId = this.safeString (trade, 'commission_currency'); + const feeCurrencyCode = this.safeCurrencyCode (feeCurrencyId); + let feeRate = this.safeFloat (trade, 'commission_percent'); + if (feeRate !== undefined) { + feeRate /= 1000; } + fee = { + 'cost': feeCost, + 'currency': feeCurrencyCode, + 'rate': feeRate, + }; } return { 'id': id, @@ -796,7 +959,7 @@ module.exports = class exmo extends Exchange { 'order': orderId, 'type': type, 'side': side, - 'takerOrMaker': undefined, + 'takerOrMaker': takerOrMaker, 'price': price, 'amount': amount, 'cost': cost, @@ -811,6 +974,28 @@ module.exports = class exmo extends Exchange { 'pair': market['id'], }; const response = await this.publicGetTrades (this.extend (request, params)); + // + // { + // "ETH_BTC":[ + // { + // "trade_id":165087520, + // "date":1587470005, + // "type":"buy", + // "quantity":"1.004", + // "price":"0.02491461", + // "amount":"0.02501426" + // }, + // { + // "trade_id":165087369, + // "date":1587469938, + // "type":"buy", + // "quantity":"0.94", + // "price":"0.02492348", + // "amount":"0.02342807" + // } + // ] + // } + // const data = this.safeValue (response, market['id'], []); return this.parseTrades (data, market, since, limit); } @@ -968,6 +1153,31 @@ module.exports = class exmo extends Exchange { 'order_id': id.toString (), }; const response = await this.privatePostOrderTrades (this.extend (request, params)); + // + // { + // "type": "buy", + // "in_currency": "BTC", + // "in_amount": "1", + // "out_currency": "USD", + // "out_amount": "100", + // "trades": [ + // { + // "trade_id": 3, + // "date": 1435488248, + // "type": "buy", + // "pair": "BTC_USD", + // "order_id": 12345, + // "quantity": 1, + // "price": 100, + // "amount": 100, + // "exec_type": "taker", + // "commission_amount": "0.02", + // "commission_currency": "BTC", + // "commission_percent": "0.2" + // } + // ] + // } + // const trades = this.safeValue (response, 'trades'); return this.parseTrades (trades, market, since, limit); } @@ -1415,9 +1625,10 @@ module.exports = class exmo extends Exchange { if (response === undefined) { return; // fallback to default error handler } - if ('result' in response) { + if (('result' in response) || ('errmsg' in response)) { // // {"result":false,"error":"Error 50052: Insufficient funds"} + // {"s":"error","errmsg":"strconv.ParseInt: parsing \"\": invalid syntax"} // let success = this.safeValue (response, 'result', false); if (typeof success === 'string') { @@ -1429,7 +1640,7 @@ module.exports = class exmo extends Exchange { } if (!success) { let code = undefined; - const message = this.safeString (response, 'error'); + const message = this.safeString2 (response, 'error', 'errmsg'); const errorParts = message.split (':'); const numParts = errorParts.length; if (numParts > 1) { diff --git a/TaskServer/node_modules/ccxt/js/ftx.js b/TaskServer/node_modules/ccxt/js/ftx.js index 8237d20e1..bdfa52251 100644 --- a/TaskServer/node_modules/ccxt/js/ftx.js +++ b/TaskServer/node_modules/ccxt/js/ftx.js @@ -580,6 +580,7 @@ module.exports = class ftx extends Exchange { // { // "fee": 20.1374935, // "feeRate": 0.0005, + // "feeCurrency": "USD", // "future": "EOS-0329", // "id": 11215, // "liquidity": "taker", @@ -626,8 +627,11 @@ module.exports = class ftx extends Exchange { let fee = undefined; const feeCost = this.safeFloat (trade, 'fee'); if (feeCost !== undefined) { + const feeCurrencyId = this.safeString (trade, 'feeCurrency'); + const feeCurrencyCode = this.safeCurrencyCode (feeCurrencyId); fee = { 'cost': feeCost, + 'currency': feeCurrencyCode, 'rate': this.safeFloat (trade, 'feeRate'), }; } diff --git a/TaskServer/node_modules/ccxt/js/gateio.js b/TaskServer/node_modules/ccxt/js/gateio.js index dd9389e9e..6a651080c 100644 --- a/TaskServer/node_modules/ccxt/js/gateio.js +++ b/TaskServer/node_modules/ccxt/js/gateio.js @@ -164,6 +164,26 @@ module.exports = class gateio extends Exchange { async fetchMarkets (params = {}) { const response = await this.publicGetMarketinfo (params); + // + // { + // "result":"true", + // "pairs":[ + // { + // "usdt_cnyx":{ + // "decimal_places":3, + // "amount_decimal_places":3, + // "min_amount":1, + // "min_amount_a":1, + // "min_amount_b":3, + // "fee":0.02, + // "trade_disabled":0, + // "buy_disabled":0, + // "sell_disabled":0 + // } + // }, + // ] + // } + // const markets = this.safeValue (response, 'pairs'); if (!markets) { throw new ExchangeError (this.id + ' fetchMarkets got an unrecognized response'); @@ -190,14 +210,14 @@ module.exports = class gateio extends Exchange { const symbol = base + '/' + quote; const precision = { 'amount': 8, - 'price': details['decimal_places'], + 'price': this.safeInteger (details, 'decimal_places'), }; const amountLimits = { - 'min': details['min_amount'], + 'min': this.safeFloat (details, 'min_amount'), 'max': undefined, }; const priceLimits = { - 'min': Math.pow (10, -details['decimal_places']), + 'min': Math.pow (10, -precision['price']), 'max': undefined, }; const defaultCost = amountLimits['min'] * priceLimits['min']; @@ -211,9 +231,13 @@ module.exports = class gateio extends Exchange { 'price': priceLimits, 'cost': costLimits, }; - const active = true; + const disabled = this.safeValue (details, 'trade_disabled'); + const active = !disabled; + const uppercaseId = id.toUpperCase (); + const fee = this.safeFloat (details, 'fee'); result.push ({ 'id': id, + 'uppercaseId': uppercaseId, 'symbol': symbol, 'base': base, 'quote': quote, @@ -221,8 +245,8 @@ module.exports = class gateio extends Exchange { 'quoteId': quoteId, 'info': market, 'active': active, - 'maker': details['fee'] / 100, - 'taker': details['fee'] / 100, + 'maker': fee / 100, + 'taker': fee / 100, 'precision': precision, 'limits': limits, }); @@ -484,22 +508,64 @@ module.exports = class gateio extends Exchange { parseOrder (order, market = undefined) { // - // {'amount': '0.00000000', - // 'currencyPair': 'xlm_usdt', - // 'fee': '0.0113766632239302 USDT', - // 'feeCurrency': 'USDT', - // 'feePercentage': 0.18, - // 'feeValue': '0.0113766632239302', - // 'filledAmount': '30.14004987', - // 'filledRate': 0.2097, - // 'initialAmount': '30.14004987', - // 'initialRate': '0.2097', - // 'left': 0, - // 'orderNumber': '998307286', - // 'rate': '0.2097', - // 'status': 'closed', - // 'timestamp': 1531158583, - // 'type': 'sell'}, + // createOrder + // + // { + // "fee": "0 ZEC", + // "code": 0, + // "rate": "0.0055", + // "side": 2, + // "type": "buy", + // "ctime": 1586460839.138, + // "market": "ZEC_BTC", + // "result": "true", + // "status": "open", + // "iceberg": "0", + // "message": "Success", + // "feeValue": "0", + // "filledRate": "0.005500000", + // "leftAmount": "0.60607456", + // "feeCurrency": "ZEC", + // "orderNumber": 10755887009, + // "filledAmount": "0", + // "feePercentage": 0.002, + // "initialAmount": "0.60607456" + // } + // + // { + // 'amount': '0.00000000', + // 'currencyPair': 'xlm_usdt', + // 'fee': '0.0113766632239302 USDT', + // 'feeCurrency': 'USDT', + // 'feePercentage': 0.18, + // 'feeValue': '0.0113766632239302', + // 'filledAmount': '30.14004987', + // 'filledRate': 0.2097, + // 'initialAmount': '30.14004987', + // 'initialRate': '0.2097', + // 'left': 0, + // 'orderNumber': '998307286', + // 'rate': '0.2097', + // 'status': 'closed', + // 'timestamp': 1531158583, + // 'type': 'sell' + // } + // + // { + // "orderNumber": 10802237760, + // "orderType": 1, + // "type": "buy", + // "rate": "0.54250000", + // "amount": "45.55638518", + // "total": "24.71433896", + // "initialRate": "0.54250000", + // "initialAmount": "45.55638518", + // "filledRate": "0.54250000", + // "filledAmount": "0", + // "currencyPair": "nano_usdt", + // "timestamp": 1586556143, + // "status": "open" + // } // const id = this.safeString2 (order, 'orderNumber', 'id'); let symbol = undefined; @@ -520,12 +586,15 @@ module.exports = class gateio extends Exchange { } else if (side === '2') { side = 'buy'; } - const price = this.safeFloat2 (order, 'initialRate', 'price'); + const price = this.safeFloat2 (order, 'initialRate', 'rate'); const average = this.safeFloat (order, 'filledRate'); const amount = this.safeFloat2 (order, 'initialAmount', 'amount'); const filled = this.safeFloat (order, 'filledAmount'); // In the order status response, this field has a different name. - const remaining = this.safeFloat2 (order, 'leftAmount', 'left'); + let remaining = this.safeFloat2 (order, 'leftAmount', 'left'); + if (remaining === undefined) { + remaining = amount - filled; + } const feeCost = this.safeFloat (order, 'feeValue'); const feeCurrencyId = this.safeString (order, 'feeCurrency'); const feeCurrencyCode = this.safeCurrencyCode (feeCurrencyId); @@ -651,7 +720,7 @@ module.exports = class gateio extends Exchange { async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) { if (symbol === undefined) { - throw new ArgumentsRequired (this.id + ' fetchMyTrades requires symbol param'); + throw new ArgumentsRequired (this.id + ' fetchMyTrades requires symbol argument'); } await this.loadMarkets (); const market = this.market (symbol); diff --git a/TaskServer/node_modules/ccxt/js/gemini.js b/TaskServer/node_modules/ccxt/js/gemini.js index a4f58b2ca..6e07ab638 100644 --- a/TaskServer/node_modules/ccxt/js/gemini.js +++ b/TaskServer/node_modules/ccxt/js/gemini.js @@ -180,8 +180,7 @@ module.exports = class gemini extends Exchange { if (numTables < 2) { throw new NotSupported (error); } - // tables[1] = tables[1].replace ("\n", ''); // eslint-disable-line quotes - const rows = tables[1].split ("\n"); // eslint-disable-line quotes + const rows = tables[1].split ("\n\n"); // eslint-disable-line quotes const numRows = rows.length; if (numRows < 2) { throw new NotSupported (error); @@ -192,66 +191,73 @@ module.exports = class gemini extends Exchange { const row = rows[i]; const cells = row.split ("\n"); // eslint-disable-line quotes const numCells = cells.length; - if (numCells < 7) { + if (numCells < 9) { throw new NotSupported (error); } - // // [ - // 'btcusd', - // 'USD', // quote - // 'BTC', // base - // '0.00001 BTC (1e-5)', // min amount - // '0.00000001 BTC (1e-8)', // amount min tick size - // '0.01 USD', // price min tick size - // '\n' + // 'BTC', // currency + // '0.00001 BTC (1e-5)', // min order size + // '0.00000001 BTC (1e-8)', // tick size + // '0.01 USD', // usd price increment + // 'N/A', // btc price increment + // '0.0001 ETH (1e-4)', // eth price increment + // '0.0001 BCH (1e-4)', // bch price increment + // '0.001 LTC (1e-3)', // ltc price increment + // '' // ] // - let id = cells[0].replace ('', ''); - id = id.replace ('', ''); - id = id.replace ('', ''); - let baseId = cells[2].replace ('', ''); - let quoteId = cells[1].replace ('', ''); - const minAmountAsString = cells[3].replace ('', ''); - const amountTickSizeAsString = cells[4].replace ('', ''); - const priceTickSizeAsString = cells[5].replace ('', ''); - const minAmount = minAmountAsString.split (' '); - const amountPrecision = amountTickSizeAsString.split (' '); - const pricePrecision = priceTickSizeAsString.split (' '); - baseId = baseId.toLowerCase (); - quoteId = quoteId.toLowerCase (); + const uppercaseBaseId = cells[0].replace ('', ''); + const baseId = uppercaseBaseId.toLowerCase (); const base = this.safeCurrencyCode (baseId); - const quote = this.safeCurrencyCode (quoteId); - const symbol = base + '/' + quote; - const precision = { - 'amount': this.precisionFromString (amountPrecision[0]), - 'price': this.precisionFromString (pricePrecision[0]), - }; - const active = undefined; - result.push ({ - 'id': id, - 'info': row, - 'symbol': symbol, - 'base': base, - 'quote': quote, - 'baseId': baseId, - 'quoteId': quoteId, - 'active': active, - 'precision': precision, - 'limits': { - 'amount': { - 'min': parseFloat (minAmount[0]), - 'max': undefined, + const quoteIds = [ 'usd', 'btc', 'eth', 'bch', 'ltc' ]; + const minAmountString = cells[1].replace ('', ''); + const minAmountParts = minAmountString.split (' '); + const minAmount = this.safeFloat (minAmountParts, 0); + const amountPrecisionString = cells[2].replace ('', ''); + const amountPrecisionParts = amountPrecisionString.split (' '); + const amountPrecision = this.precisionFromString (amountPrecisionParts[0]); + for (let j = 0; j < quoteIds.length; j++) { + const quoteId = quoteIds[j]; + const quote = this.safeCurrencyCode (quoteId); + const pricePrecisionIndex = this.sum (3, j); + const pricePrecisionString = cells[pricePrecisionIndex].replace ('', ''); + if (pricePrecisionString === 'N/A') { + continue; + } + const pricePrecisionParts = pricePrecisionString.split (' '); + const pricePrecision = this.precisionFromString (pricePrecisionParts[0]); + const symbol = base + '/' + quote; + const id = baseId + quoteId; + const active = undefined; + result.push ({ + 'id': id, + 'info': row, + 'symbol': symbol, + 'base': base, + 'quote': quote, + 'baseId': baseId, + 'quoteId': quoteId, + 'active': active, + 'precision': { + 'amount': amountPrecision, + 'price': pricePrecision, }, - 'price': { - 'min': undefined, - 'max': undefined, + 'limits': { + 'amount': { + 'min': minAmount, + 'max': undefined, + }, + 'price': { + 'min': undefined, + 'max': undefined, + }, + 'cost': { + 'min': undefined, + 'max': undefined, + }, }, - 'cost': { - 'min': undefined, - 'max': undefined, - }, - }, - }); + }); + } } return result; } diff --git a/TaskServer/node_modules/ccxt/js/hbtc.js b/TaskServer/node_modules/ccxt/js/hbtc.js new file mode 100644 index 000000000..317dc9d90 --- /dev/null +++ b/TaskServer/node_modules/ccxt/js/hbtc.js @@ -0,0 +1,2019 @@ +'use strict'; + +// --------------------------------------------------------------------------- + +const Exchange = require ('./base/Exchange'); +const { AuthenticationError, ExchangeError, OrderNotFound, ArgumentsRequired, BadSymbol, BadRequest, NullResponse, InvalidOrder, BadResponse, NotSupported, ExchangeNotAvailable, RequestTimeout, RateLimitExceeded, PermissionDenied, InsufficientFunds, InvalidAddress } = require ('./base/errors'); +const { TICK_SIZE, TRUNCATE } = require ('./base/functions/number'); + +// --------------------------------------------------------------------------- + +module.exports = class hbtc extends Exchange { + describe () { + return this.deepExtend (super.describe (), { + 'id': 'hbtc', + 'name': 'HBTC', + 'countries': [ 'CN' ], + 'rateLimit': 2000, + 'version': 'v1', + 'has': { + 'CORS': false, + 'fetchTime': true, + 'fetchBidAsk': true, + 'fetchBidsAsks': true, + 'fetchTickers': true, + 'fetchTicker': true, + 'fetchDepositAddress': false, + 'fetchOHLCV': true, + 'fetchOrder': true, + 'fetchOrders': false, + 'fetchOpenOrders': true, + 'fetchClosedOrders': true, + 'fetchTradingLimits': true, + 'fetchMarkets': true, + 'fetchMyTrades': true, + 'withdraw': true, + 'fetchCurrencies': false, + 'fetchDeposits': true, + 'fetchWithdrawals': true, + 'fetchAccounts': true, + 'fetchLedger': 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/51840849/80134449-70663300-85a7-11ea-8942-e204cdeaab5d.jpg', // 交易所LOGO + 'api': { + 'quote': 'https://api.hbtc.com/openapi/quote', // 市场API数据端点 + 'contract': 'https://api.hbtc.com/openapi/contract', // 合约API数据端点 + 'option': 'https://api.hbtc.com/openapi/option', // 合约API数据端点 + 'public': 'https://api.hbtc.com/openapi', // 公共API数据端点 + 'private': 'https://api.hbtc.com/openapi', // 私有API数据端点 + 'zendesk': 'https://hbtc.zendesk.com/hc/en-us', + }, + 'www': 'https://www.hbtc.com', // 公司主页 + 'referral': 'https://www.hbtc.com/register/O2S8NS', // 邀请链接 + 'doc': 'https://github.com/bhexopen/BHEX-OpenApi/tree/master/doc', // openapi文档地址 + 'fees': 'https://hbtc.zendesk.com/hc/zh-cn/articles/360009274694', // 费率介绍 + }, + 'api': { + 'public': { + 'get': [ + 'ping', + 'time', + 'brokerInfo', // 查询当前broker交易规则和symbol信息 + 'getOptions', + ], + }, + 'quote': { + 'get': [ + 'depth', // 获取深度 + 'depth/merged', + 'trades', // 获取当前最新成交 + 'klines', // 获取K线数据 + 'ticker/24hr', // 获取24小时价格变化数据 + 'ticker/price', + 'ticker/bookTicker', + 'contract/index', // 获取合约标的指数价格 + 'contract/depth', // 获取合约深度 + 'contract/depth/merged', + 'contract/trades', // 获取合约最近成交, + 'contract/klines', // 获取合约的K线数据 + 'contract/ticker/24hr', + 'option/index', + 'option/depth', + 'option/depth/merged', + 'option/trades', + 'option/klines', + 'option/ticker/24hr', + ], + }, + 'contract': { + 'get': [ + // public + 'insurance', + 'fundingRate', // 获取资金费率信息 + // private + 'openOrders', // 查询合约当前委托 + 'historyOrders', // 查询合约历史委托 + 'getOrder', // 查询合约订单详情 + 'myTrades', // 查询合约历史成交 + 'positions', // 查询合约当前持仓 + 'account', // 查询合约账户信息 + ], + 'post': [ + 'order', // 创建合约订单 + 'modifyMargin', // 修改保证金 + ], + 'delete': [ + 'order/cancel', // 取消合约订单 + 'order/batchCancel', + ], + }, + 'option': { + 'get': [ + 'openOrders', + 'positions', + 'historyOrders', + // 'getOrder', + 'myTrades', + 'settlements', + 'account', + ], + 'post': [ + 'order', + ], + 'delete': [ + 'order/cancel', + ], + }, + 'private': { + 'get': [ + 'order', // 查询订单 + 'openOrders', // 查询当前委托 + 'historyOrders', // 查询历史委托 + 'account', // 获取当前账户信息 + 'myTrades', // 查询历史成交 + 'depositOrders', + 'withdrawalOrders', + 'withdraw/detail', + 'balance_flow', + ], + 'post': [ + 'order', // 创建新订单 + 'order/test', + 'userDataStream', + 'subAccount/query', + 'transfer', + 'user/transfer', + 'withdraw', + ], + 'put': [ + 'userDataStream', + ], + 'delete': [ + 'order', // 取消订单 + 'userDataStream', + ], + }, + }, + 'precisionMode': TICK_SIZE, + 'fees': { + 'trading': { + 'tierBased': false, + 'percentage': true, + 'maker': 0.002, // MAKER费率 + 'taker': 0.002, // TAKER费率 + }, + }, + 'exceptions': { + 'exact': { + // general server or network errors + '-1000': ExchangeError, // An unknown error occured while processing the request + '-1001': ExchangeError, // Internal error, unable to process your request. Please try again + '-1002': AuthenticationError, // You are not authorized to execute this request. Request need API Key included in. We suggest that API Key be included in any request + '-1003': RateLimitExceeded, // Too many requests, please use the websocket for live updates + '-1004': BadRequest, + '-1005': PermissionDenied, + '-1006': BadResponse, // An unexpected response was received from the message bus. Execution status unknown. OPEN API server find some exception in execute request.Please report to Customer service + '-1007': RequestTimeout, // Timeout waiting for response from backend server. Send status unknown, execution status unknown + '-1014': InvalidOrder, // Unsupported order combination + '-1015': RateLimitExceeded, // Reach the rate limit.Please slow down your request speed + '-1016': ExchangeNotAvailable, // This service is no longer available + '-1020': NotSupported, // This operation is not supported + '-1021': BadRequest, // Timestamp for this request is outside of the recvWindow + '-1022': AuthenticationError, // Signature for this request is not valid + // request issues + '-1100': BadRequest, // Illegal characters found in a parameter + '-1101': BadRequest, // Too many parameters sent for this endpoint + '-1102': BadRequest, // A mandatory parameter was not sent, was empty/null, or malformed + '-1103': BadRequest, // An unknown parameter was sent + '-1104': BadRequest, // Not all sent parameters were read + '-1105': BadRequest, // A parameter was empty + '-1106': BadRequest, // A parameter was sent when not required + '-1111': BadRequest, // Precision is over the maximum defined for this asset + '-1112': NullResponse, // No orders on book for symbol + '-1114': InvalidOrder, // TimeInForce parameter sent when not required + '-1115': InvalidOrder, // Invalid timeInForce + '-1116': InvalidOrder, // Invalid orderType + '-1117': InvalidOrder, // Invalid side + '-1118': InvalidOrder, // New client order ID was empty + '-1119': InvalidOrder, // Original client order ID was empty + '-1120': BadRequest, // Invalid interval + '-1121': BadSymbol, // Invalid symbol + '-1125': AuthenticationError, // This listenKey does not exist + '-1127': BadRequest, // Lookup interval is too big + '-1128': BadRequest, // Combination of optional parameters invalid + '-1130': BadRequest, // Invalid data sent for a parameter + '-1131': InsufficientFunds, + '-1132': InvalidOrder, // Order price too high + '-1133': InvalidOrder, // Order price lower than the minimum,please check general broker info + '-1134': InvalidOrder, // Order price decimal too long,please check general broker info + '-1135': InvalidOrder, // Order quantity too large + '-1136': InvalidOrder, // Order quantity lower than the minimum + '-1137': InvalidOrder, // Order quantity decimal too long + '-1138': InvalidOrder, // Order price exceeds permissible range + '-1139': InvalidOrder, // Order has been filled + '-1140': InvalidOrder, // Transaction amount lower than the minimum + '-1141': InvalidOrder, // Duplicate clientOrderId + '-1142': InvalidOrder, // Order has been canceled + '-1143': OrderNotFound, // Cannot be found on order book + '-1144': InvalidOrder, // Order has been locked + '-1145': InvalidOrder, // This order type does not support cancellation + '-1146': RequestTimeout, // Order creation timeout + '-1147': RequestTimeout, // Order cancellation timeout + '-1149': InvalidOrder, // Create order failed + '-1187': InvalidAddress, // Withdrawal address not in whitelist + '-2010': InvalidOrder, // NEW_ORDER_REJECTED + '-2011': InvalidOrder, // CANCEL_REJECTED + '-2013': OrderNotFound, // Order does not exist + '-2014': AuthenticationError, // API-key format invalid + '-2015': AuthenticationError, // Invalid API-key, IP, or permissions for action + '-2016': ExchangeError, // No trading window could be found for the symbol. Try ticker/24hrs instead + }, + }, + // exchange-specific options + 'options': { + 'fetchTickers': { + 'method': 'quoteGetTicker24hr', + }, + }, + }); + } + + async fetchTime (params = {}) { + const response = await this.publicGetTime (params); + // + // { + // "serverTime": 1527777538000 + // } + // + return this.safeInteger (response, 'serverTime'); + } + + parseMarket (market, type = 'spot') { + const filters = this.safeValue (market, 'filters', []); + const id = this.safeString (market, 'symbol'); + let baseId = this.safeString (market, 'baseAsset'); + const quoteId = this.safeString (market, 'quoteAsset'); + let base = this.safeCurrencyCode (baseId); + const quote = this.safeCurrencyCode (quoteId); + let symbol = base + '/' + quote; + let spot = true; + let future = false; + let option = false; + let inverse = false; + if (type === 'future') { + symbol = id; + spot = false; + future = true; + inverse = this.safeValue (market, 'inverse', false); + baseId = this.safeString (market, 'underlying'); + base = this.safeCurrencyCode (baseId); + } else if (type === 'option') { + symbol = id; + spot = false; + option = true; + } + let amountMin = undefined; + let amountMax = undefined; + let priceMin = undefined; + let priceMax = undefined; + let costMin = undefined; + for (let j = 0; j < filters.length; j++) { + const filter = filters[j]; + const filterType = this.safeString (filter, 'filterType'); + if (filterType === 'LOT_SIZE') { + amountMin = this.safeFloat (filter, 'minQty'); + amountMax = this.safeFloat (filter, 'maxQty'); + } + if (filterType === 'PRICE_FILTER') { + priceMin = this.safeFloat (filter, 'minPrice'); + priceMax = this.safeFloat (filter, 'maxPrice'); + } + if (filterType === 'MIN_NOTIONAL') { + costMin = this.safeFloat (filter, 'minNotional'); + } + } + if ((costMin === undefined) && (amountMin !== undefined) && (priceMin !== undefined)) { + costMin = amountMin * priceMin; + } + const precision = { + 'price': this.safeFloat2 (market, 'quotePrecision', 'quoteAssetPrecision'), + 'amount': this.safeFloat (market, 'baseAssetPrecision'), + }; + const limits = { + 'amount': { + 'min': amountMin, + 'max': amountMax, + }, + 'price': { + 'min': priceMin, + 'max': priceMax, + }, + 'cost': { + 'min': costMin, + 'max': undefined, + }, + }; + return { + 'id': id, + 'symbol': symbol, + 'base': base, + 'quote': quote, + 'baseId': baseId, + 'quoteId': quoteId, + 'active': true, + 'type': type, + 'spot': spot, + 'future': future, + 'option': option, + 'inverse': inverse, + 'precision': precision, + 'limits': limits, + 'info': market, + }; + } + + async fetchMarkets (params = {}) { + const response = await this.publicGetBrokerInfo (params); + // + // { + // "timezone":"UTC", + // "serverTime":"1588015885118", + // "brokerFilters":[], + // "symbols":[ + // { + // "filters":[ + // {"minPrice":"0.01","maxPrice":"100000.00000000","tickSize":"0.01","filterType":"PRICE_FILTER"}, + // {"minQty":"0.0005","maxQty":"100000.00000000","stepSize":"0.000001","filterType":"LOT_SIZE"}, + // {"minNotional":"5","filterType":"MIN_NOTIONAL"} + // ], + // "exchangeId":"301", + // "symbol":"BTCUSDT", + // "symbolName":"BTCUSDT", + // "status":"TRADING", + // "baseAsset":"BTC", + // "baseAssetPrecision":"0.000001", + // "quoteAsset":"USDT", + // "quotePrecision":"0.01", + // "icebergAllowed":false + // }, + // ], + // "options":[ + // { + // "filters":[ + // {"minPrice":"0.01","maxPrice":"100000.00000000","tickSize":"0.01","filterType":"PRICE_FILTER"}, + // {"minQty":"0.01","maxQty":"100000.00000000","stepSize":"0.001","filterType":"LOT_SIZE"}, + // {"minNotional":"1","filterType":"MIN_NOTIONAL"} + // ], + // "exchangeId":"301", + // "symbol":"BTC0501CS8500", + // "symbolName":"BTC0501CS8500", + // "status":"TRADING", + // "baseAsset":"BTC0501CS8500", + // "baseAssetPrecision":"0.001", + // "quoteAsset":"BUSDT", + // "quotePrecision":"0.01", + // "icebergAllowed":false + // }, + // ], + // "contracts":[ + // { + // "filters":[ + // {"minPrice":"0.1","maxPrice":"100000.00000000","tickSize":"0.1","filterType":"PRICE_FILTER"}, + // {"minQty":"1","maxQty":"100000.00000000","stepSize":"1","filterType":"LOT_SIZE"}, + // {"minNotional":"0.000001","filterType":"MIN_NOTIONAL"} + // ], + // "exchangeId":"301", + // "symbol":"BTC-PERP-REV", + // "symbolName":"BTC-PERP-REV", + // "status":"TRADING", + // "baseAsset":"BTC-PERP-REV", + // "baseAssetPrecision":"1", + // "quoteAsset":"USDT", + // "quoteAssetPrecision":"0.1", + // "icebergAllowed":false, + // "inverse":true, + // "index":"BTCUSDT", + // "marginToken":"TBTC", + // "marginPrecision":"0.00000001", + // "contractMultiplier":"1.0", + // "underlying":"TBTC", + // "riskLimits":[ + // {"riskLimitId":"200000001","quantity":"1000000.0","initialMargin":"0.01","maintMargin":"0.005"}, + // {"riskLimitId":"200000002","quantity":"2000000.0","initialMargin":"0.02","maintMargin":"0.01"}, + // {"riskLimitId":"200000003","quantity":"3000000.0","initialMargin":"0.03","maintMargin":"0.015"}, + // {"riskLimitId":"200000004","quantity":"4000000.0","initialMargin":"0.04","maintMargin":"0.02"} + // ] + // }, + // { + // "filters":[ + // {"minPrice":"0.1","maxPrice":"100000.00000000","tickSize":"0.1","filterType":"PRICE_FILTER"}, + // {"minQty":"1","maxQty":"100000.00000000","stepSize":"1","filterType":"LOT_SIZE"}, + // {"minNotional":"0.000001","filterType":"MIN_NOTIONAL"} + // ], + // "exchangeId":"301", + // "symbol":"BTC-SWAP", + // "symbolName":"BTC-SWAP", + // "status":"TRADING", + // "baseAsset":"BTC-SWAP", + // "baseAssetPrecision":"1", + // "quoteAsset":"USDT", + // "quoteAssetPrecision":"0.1", + // "icebergAllowed":false, + // "inverse":true, + // "index":"BTCUSDT", + // "marginToken":"BTC", + // "marginPrecision":"0.00000001", + // "contractMultiplier":"1.0", + // "underlying":"BTC", + // "riskLimits":[ + // {"riskLimitId":"500000001","quantity":"1000000.0","initialMargin":"0.01","maintMargin":"0.005"}, + // {"riskLimitId":"500000002","quantity":"2000000.0","initialMargin":"0.02","maintMargin":"0.01"}, + // {"riskLimitId":"500000003","quantity":"3000000.0","initialMargin":"0.03","maintMargin":"0.015"}, + // {"riskLimitId":"500000004","quantity":"4000000.0","initialMargin":"0.04","maintMargin":"0.02"} + // ] + // }, + // { + // "filters":[ + // {"minPrice":"0.1","maxPrice":"100000.00000000","tickSize":"0.1","filterType":"PRICE_FILTER"}, + // {"minQty":"1","maxQty":"100000.00000000","stepSize":"1","filterType":"LOT_SIZE"}, + // {"minNotional":"0.000000001","filterType":"MIN_NOTIONAL"} + // ], + // "exchangeId":"301", + // "symbol":"BTC-PERP-BUSDT", + // "symbolName":"BTC-PERP-BUSDT", + // "status":"TRADING", + // "baseAsset":"BTC-PERP-BUSDT", + // "baseAssetPrecision":"1", + // "quoteAsset":"BUSDT", + // "quoteAssetPrecision":"0.1", + // "icebergAllowed":false, + // "inverse":false, + // "index":"BTCUSDT", + // "marginToken":"BUSDT", + // "marginPrecision":"0.0001", + // "contractMultiplier":"0.0001", + // "underlying":"TBTC", + // "riskLimits":[ + // {"riskLimitId":"600000132","quantity":"1000000.0","initialMargin":"0.01","maintMargin":"0.005"}, + // {"riskLimitId":"600000133","quantity":"2000000.0","initialMargin":"0.02","maintMargin":"0.01"}, + // {"riskLimitId":"600000134","quantity":"3000000.0","initialMargin":"0.03","maintMargin":"0.015"}, + // {"riskLimitId":"600000135","quantity":"4000000.0","initialMargin":"0.04","maintMargin":"0.02"} + // ] + // }, + // ] + // } + // + const result = []; + const symbols = this.safeValue (response, 'symbols', []); + for (let i = 0; i < symbols.length; i++) { + const market = this.parseMarket (symbols[i], 'spot'); + result.push (market); + } + const options = this.safeValue (response, 'options', []); + for (let i = 0; i < options.length; i++) { + const market = this.parseMarket (options[i], 'option'); + result.push (market); + } + const contracts = this.safeValue (response, 'contracts', []); + for (let i = 0; i < contracts.length; i++) { + const market = this.parseMarket (contracts[i], 'future'); + result.push (market); + } + return 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 40, max 40 + } + const response = await this.quoteGetDepth (this.extend (request, params)); + // + // { + // "time":1588068913453, + // "bids":[ + // ["0.025278","0.0202"], + // ["0.025277","16.1132"], + // ["0.025276","7.9056"], + // ] + // "asks":[ + // ["0.025302","5.9999"], + // ["0.025303","34.9151"], + // ["0.025304","92.391"], + // ] + // } + // + const timestamp = this.safeInteger (response, 'time'); + return this.parseOrderBook (response, timestamp); + } + + async fetchTicker (symbol, params = {}) { + await this.loadMarkets (); + const market = this.market (symbol); + const request = { + 'symbol': market['id'], + }; + const response = await this.quoteGetTicker24hr (this.extend (request, params)); + // + // { + // "time":1588069860794, + // "symbol":"BNB0501PS16", + // "bestBidPrice":"0.2129", + // "bestAskPrice":"0.3163", + // "volume":"33547", + // "quoteVolume":"10801.987", + // "lastPrice":"0.2625", + // "highPrice":"0.3918", + // "lowPrice":"0.2625", + // "openPrice":"0.362", + // } + // + 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 fetchBidAsk (symbol, params = {}) { + await this.loadMarkets (); + const market = this.market (symbol); + const request = { + 'symbol': market['id'], + }; + const response = await this.quoteGetTickerBookTicker (this.extend (request, params)); + // + // { + // "symbol": "LTCBTC", + // "bidPrice": "4.00000000", + // "bidQty": "431.00000000", + // "askPrice": "4.00000200", + // "askQty": "9.00000000" + // } + // + return this.parseTicker (response, market); + } + + async fetchBidsAsks (symbols = undefined, params = {}) { + await this.loadMarkets (); + const response = await this.quoteGetTickerBookTicker (params); + // + // [ + // { + // "symbol": "LTCBTC", + // "bidPrice": "4.00000000", + // "bidQty": "431.00000000", + // "askPrice": "4.00000200", + // "askQty": "9.00000000" + // }, + // { + // "symbol": "ETHBTC", + // "bidPrice": "0.07946700", + // "bidQty": "9.00000000", + // "askPrice": "100000.00000000", + // "askQty": "1000.00000000" + // }, + // ] + // + return this.parseTickers (response, symbols); + } + + async fetchTickers (symbols = undefined, params = {}) { + await this.loadMarkets (); + const options = this.safeValue (this.options, 'fetchTickers', {}); + const defaultMethod = this.safeString (options, 'method', 'quoteGetTicker24hr'); + const defaultType = this.safeString (options, 'type', 'spot'); + const type = this.safeString (params, 'type', defaultType); + const query = this.omit (params, 'type'); + let method = defaultMethod; + if (type === 'future') { + method = 'quoteGetContractTicker24hr'; + } else if (type === 'option') { + method = 'quoteGetOptionTicker24hr'; + } + const response = await this[method] (query); + // + // [ + // { + // "time": 1538725500422, + // "symbol": "ETHBTC", + // "lastPrice": "4.00000200", + // "openPrice": "99.00000000", + // "highPrice": "100.00000000", + // "lowPrice": "0.10000000", + // "volume": "8913.30000000" + // }, + // ] + // + return this.parseTickers (response, symbols); + } + + async fetchBalance (params = {}) { + await this.loadMarkets (); + const options = this.safeValue (this.options, 'fetchBalance', {}); + const defaultType = this.safeString (options, 'type', 'spot'); + const type = this.safeString (params, 'type', defaultType); + const query = this.omit (params, 'type'); + let method = 'privateGetAccount'; + if (type === 'future') { + method = 'contractGetAccount'; + } else if (type === 'option') { + method = 'optionGetAccount'; + } + const response = await this[method] (query); + // + // spot + // + // { + // 'balances': [ + // { + // 'asset': 'ALGO', + // 'free': '0', + // 'locked': '0' + // }, + // { + // 'asset': 'BHT', + // 'free': '0', + // 'locked': '0' + // } + // ] + // } + // + // contract + // + // { + // "BUSDT":{ + // "total":"1000", + // "availableMargin":"1000", + // "positionMargin":"0", + // "orderMargin":"0", + // "tokenId":"BUSDT" + // }, + // "TBTC":{ + // "total":"0.5", + // "availableMargin":"0.5", + // "positionMargin":"0", + // "orderMargin":"0", + // "tokenId":"TBTC" + // } + // } + // + // option + // + // { + // "optionAsset":"", + // "balances":[ + // { + // "tokenName":"USDT", + // "free":"0.0", + // "locked":"0.0", + // "margin":"0.0" + // }, + // { + // "tokenName":"BUSDT", + // "free":"0.0", + // "locked":"0.0", + // "margin":"0.0" + // } + // ] + // } + // + const balances = this.safeValue (response, 'balances'); + const result = { 'info': response }; + if (balances !== undefined) { + for (let i = 0; i < balances.length; i++) { + const balance = balances[i]; + const currencyId = this.safeString2 (balance, 'asset', 'tokenName'); + 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 { + const currencyIds = Object.keys (response); + for (let i = 0; i < currencyIds.length; i++) { + const currencyId = currencyIds[i]; + const code = this.safeCurrencyCode (currencyId); + const balance = response[currencyId]; + const account = this.account (); + account['free'] = this.safeFloat (balance, 'availableMargin'); + account['total'] = this.safeFloat (balance, 'total'); + result[code] = account; + } + } + return this.parseBalance (result); + } + + async fetchTrades (symbol, since = undefined, limit = 50, params = {}) { + await this.loadMarkets (); + const market = this.market (symbol); + const request = { + 'symbol': market['id'], + }; + if (limit !== undefined) { + request['limit'] = limit; // default 500, max 1000 + } + const response = await this.quoteGetTrades (this.extend (request, params)); + // + // [ + // {"price":"0.025344","time":1588084082060,"qty":"1","isBuyerMaker":false}, + // {"price":"0.02535","time":1588084086021,"qty":"0.553","isBuyerMaker":true}, + // {"price":"0.025348","time":1588084097037,"qty":"1","isBuyerMaker":false}, + // ] + // + return this.parseTrades (response, market, since, limit); + } + + parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) { + // + // [ + // 1587906000000, // open time + // "0.1761", // open + // "0.1761", // high + // "0.1761", // low + // "0.1761", // close + // "0", // base volume + // 0, // close time + // "0", // quote volume + // 0, // number of trades + // "0", // taker buy base asset volume + // "0" // taker buy quote asset volume + // ] + // + 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 500, max 500 + } + const response = await this.quoteGetKlines (this.extend (request, params)); + // + // [ + // [1587906000000,"0.1761","0.1761","0.1761","0.1761","0",0,"0",0,"0","0"], + // [1587906180000,"0.1761","0.1761","0.1761","0.1761","0",0,"0",0,"0","0"], + // [1587906360000,"0.1761","0.1848","0.1761","0.1848","53",0,"9.7944",1,"0","0"], + // ] + // + return this.parseOHLCVs (response, market, timeframe, since, limit); + } + + async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) { + await this.loadMarkets (); + let market = undefined; + const request = { + // if only fromId is set,it will get orders < that fromId in descending order + // if only toId is set, it will get orders > that toId in ascending order + // if fromId is set and toId is set, it will get orders < that fromId and > that toId in descending order + // if fromId is not set and toId it not set, most recent order are returned in descending order + // 'fromId': '43287482374', + // 'toId': '43287482374', + // 'endTime': this.milliseconds (), // optional, spot only + }; + const defaultType = this.safeString (this.options, 'type', 'spot'); + const options = this.safeValue (this.options, 'fetchMyTrades', {}); + const fetchMyTradesType = this.safeString (options, 'type', defaultType); + let type = this.safeString (params, 'type', fetchMyTradesType); + if (symbol !== undefined) { + market = this.market (symbol); + request['symbol'] = market['id']; + type = market['type']; + } + const query = this.omit (params, 'type'); + if (limit !== undefined) { + // spot default 500, max 1000 + // futures and options default 20, max 1000 + request['limit'] = limit; + } + let method = 'privateGetMyTrades'; + if (type === 'future') { + method = 'contractGetMyTrades'; + } else { + if (type === 'option') { + method = 'optionGetMyTrades'; + } else { + if (symbol === undefined) { + throw new ArgumentsRequired (this.id + ' fetchMyTrades requires a `symbol` argument for ' + type + ' markets'); + } + const market = this.market (symbol); + request['symbol'] = market['id']; + // spot only? + if (since !== undefined) { + request['startTime'] = since; + } + } + } + if (since !== undefined) { + request['startTime'] = since; + } + const response = await this[method] (this.extend (request, query)); + // + // spot + // + // [ + // { + // "id":"616384027512920576", + // "symbol":"TBTCBUSDT", + // "orderId":"616384027202542080", + // "matchOrderId":"605124954767266560", + // "price":"6826.06", + // "qty":"0.1", + // "commission":"0.682606", + // "commissionAsset":"BUSDT", + // "time":"1588214701982", + // "isBuyer":false, + // "isMaker":false, + // "fee":{ + // "feeTokenId":"BUSDT", + // "feeTokenName":"BUSDT", + // "fee":"0.682606" + // } + // } + // ] + // + return this.parseTrades (response, market, since, limit); + } + + async createOrder (symbol, type, side, amount, price = undefined, params = {}) { + await this.loadMarkets (); + const market = this.market (symbol); + const orderSide = side.toUpperCase (); + const orderType = type.toUpperCase (); + const request = { + 'symbol': market['id'], + // BUY or SELL for spot and options + 'side': orderSide, + // GTC, FOK, IOC for spot and options + // GTC, FOK, IOC, LIMIT_MAKER for futures + // 'timeInForce': 'GTC', + }; + let query = params; + let method = 'privatePostOrder'; + if (market['type'] === 'future') { + if ((orderSide !== 'BUY_OPEN') && (orderSide !== 'SELL_OPEN') && (orderSide !== 'BUY_CLOSE') && (orderSide !== 'SELL_CLOSE')) { + throw new NotSupported (this.id + ' createOrder() does not support order side ' + side + ' for ' + market['type'] + ' markets, only BUY_OPEN, SELL_OPEN, BUY_CLOSE and SELL_CLOSE are supported'); + } + if ((orderType !== 'LIMIT') && (orderType !== 'STOP')) { + throw new NotSupported (this.id + ' createOrder() does not support order type ' + type + ' for ' + market['type'] + ' markets, only LIMIT and STOP are supported'); + } + const clientOrderId = this.safeValue (params, 'clientOrderId'); + if (clientOrderId === undefined) { + throw new ArgumentsRequired (this.id + ' createOrder() requires a clientOrderId parameter for ' + market['type'] + ' markets, supply clientOrderId in the params argument'); + } + const leverage = this.safeValue (params, 'leverage'); + if (leverage === undefined && (orderSide === 'BUY_OPEN' || orderSide === 'SELL_OPEN')) { + throw new NotSupported (this.id + ' createOrder() requires a leverage parameter for ' + market['type'] + ' markets if orderSide is BUY_OPEN or SELL_OPEN'); + } + method = 'contractPostOrder'; + const priceType = this.safeString (params, 'priceType'); + if (priceType === undefined) { + request['price'] = this.priceToPrecision (symbol, price); + } else { + request['priceType'] = priceType; + if (priceType === 'INPUT') { + request['price'] = this.priceToPrecision (symbol, price); + } + } + request['orderType'] = type.toUpperCase (); // LIMIT, STOP + request['quantity'] = this.amountToPrecision (symbol, amount); + // request['leverage'] = 1; // not required for closing orders + request['leverage'] = leverage; + request['clientOrderId'] = clientOrderId; + // optional + // request['priceType'] = 'INPUT', // INPUT, OPPONENT, QUEUE, OVER, MARKET + // request['triggerPrice'] = 123.45; + } else { + if (market['type'] === 'option') { + method = 'optionPostOrder'; + } + const newClientOrderId = this.safeValue2 (params, 'clientOrderId', 'newClientOrderId'); + if (newClientOrderId !== undefined) { + request['newClientOrderId'] = newClientOrderId; + } + request['type'] = orderType; + if (type === 'limit') { + request['price'] = this.priceToPrecision (symbol, price); + request['quantity'] = this.amountToPrecision (symbol, amount); + } else if (type === 'market') { + // for market buy it requires the amount of quote currency to spend + if (side === 'buy') { + const createMarketBuyOrderRequiresPrice = this.safeValue (this.options, 'createMarketBuyOrderRequiresPrice', true); + if (createMarketBuyOrderRequiresPrice) { + if (price !== undefined) { + amount = amount * price; + } else { + throw new InvalidOrder (this.id + " createOrder() requires the price argument with market buy orders to calculate total order cost (amount to spend), where cost = amount * price. Supply a price argument to createOrder() call if you want the cost to be calculated for you from price and amount, or, alternatively, add .options['createMarketBuyOrderRequiresPrice'] = false and supply the total cost value in the 'amount' argument (the exchange-specific behaviour)"); + } + } + const precision = market['precision']['price']; + request['quantity'] = this.decimalToPrecision (amount, TRUNCATE, precision, this.precisionMode); + } else { + request['quantity'] = this.amountToPrecision (symbol, amount); + } + } + } + query = this.omit (query, [ 'clientOrderId', 'newClientOrderId' ]); + const response = await this[method] (this.extend (request, query)); + // + // spot + // + // { + // "symbol":"TBTCBUSDT", + // "orderId":"616376654496877056", + // "clientOrderId":"158821382304516955", + // "transactTime":"1588213823080", + // "price":"0", + // "origQty":"1000", + // "executedQty":"0", + // "status":"NEW", + // "timeInForce":"GTC", + // "type":"MARKET", + // "side":"BUY" + // } + // + // contract + // + // { + // 'time': '1570759718825', + // 'updateTime': '0', + // 'orderId': '469961015902208000', + // 'clientOrderId': '6423344174', + // 'symbol': 'BTC-PERP-REV', + // 'price': '8200', + // 'leverage': '12.08', + // 'origQty': '5', + // 'executedQty': '0', + // 'avgPrice': '0', + // 'marginLocked': '0.00005047', + // 'orderType': 'LIMIT', + // 'side': 'BUY_OPEN', + // 'fees': [], + // 'timeInForce': 'GTC', + // 'status': 'NEW', + // 'priceType': 'INPUT' + // } + // + return this.parseOrder (response, market); + } + + async cancelOrder (id, symbol = undefined, params = {}) { + await this.loadMarkets (); + const clientOrderId = this.safeValue2 (params, 'origClientOrderId', 'clientOrderId'); + const request = {}; + const defaultType = this.safeString (this.options, 'type', 'spot'); + const options = this.safeValue (this.options, 'cancelOrder', {}); + const cancelOrderType = this.safeString (options, 'type', defaultType); + let type = this.safeString (params, 'type', cancelOrderType); + let query = this.omit (params, 'type'); + if (clientOrderId !== undefined) { + request['origClientOrderId'] = clientOrderId; + query = this.omit (query, [ 'origClientOrderId', 'clientOrderId' ]); + } else { + request['orderId'] = id; + } + let method = 'privateDeleteOrder'; + const orderType = this.safeString (query, 'orderType'); + if (orderType !== undefined) { + type = 'future'; + } + if (type === 'future') { + method = 'contractDeleteOrderCancel'; + if (orderType === undefined) { + throw new ArgumentsRequired (this.id + " cancelOrder() requires an orderType parameter, pass the { 'orderType': 'LIMIT' } or { 'orderType': 'STOP' } in params argument"); + } + request['orderType'] = orderType; + } else { + if (type === 'option') { + method = 'optionDeleteOrderCancel'; + } + } + const response = await this[method] (this.extend (request, query)); + // + // spot + // + // { + // 'exchangeId': '301', + // 'symbol': 'BHTUSDT', + // 'clientOrderId': '0', + // 'orderId': '499890200602846976', + // 'status': 'CANCELED' + // } + // + // futures + // + // { + // "time":"1588353669383", + // "updateTime":"0", + // "orderId":"617549770304599296", + // "clientOrderId":"test-001", + // "symbol":"BTC-PERP-REV", + // "price":"10000", + // "leverage":"1", + // "origQty":"100", + // "executedQty":"0", + // "avgPrice":"0", + // "marginLocked":"0", + // "orderType":"LIMIT", + // "side":"SELL_OPEN", + // "fees":[], + // "timeInForce":"GTC", + // "status":"CANCELED", + // "priceType":"INPUT", + // } + // + return this.parseOrder (response); + } + + async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) { + await this.loadMarkets (); + let market = undefined; + const request = { + // if orderId is set, it will get orders < that orderId otherwise most recent orders are returned + // 'orderId': '43287482374', + }; + const defaultType = this.safeString (this.options, 'type', 'spot'); + const options = this.safeValue (this.options, 'fetchOpenOrders', {}); + const fetchOpenOrdersType = this.safeString (options, 'type', defaultType); + let type = this.safeString (params, 'type', fetchOpenOrdersType); + if (symbol !== undefined) { + market = this.market (symbol); + request['symbol'] = market['id']; + type = market['type']; + } + const query = this.omit (params, 'type'); + if (limit !== undefined) { + request['limit'] = limit; // default 500, max 1000 + } + let method = 'privateGetOpenOrders'; + if (type === 'future') { + method = 'contractGetOpenOrders'; + } else if (type === 'option') { + method = 'optionGetOpenOrders'; + } + const response = await this[method] (this.extend (request, query)); + // + // spot + // + // [ + // { + // 'orderId': '499902955766523648', + // 'clientOrderId': '157432907618453', + // 'exchangeId': '301', + // 'symbol': 'BHTUSDT', + // 'price': '0.01', + // 'origQty': '50', + // 'executedQty': '0', + // 'cummulativeQuoteQty': '0', + // 'avgPrice': '0', + // 'status': 'NEW', + // 'timeInForce': 'GTC', + // 'type': 'LIMIT', + // 'side': 'BUY', + // 'stopPrice': '0.0', + // 'icebergQty': '0.0', + // 'time': '1574329076202', + // 'updateTime': '0', + // 'isWorking': true + // } + // ] + // + // futures + // + // [ + // { + // "time":"1588353669383", + // "updateTime":"0", + // "orderId":"617549770304599296", + // "clientOrderId":"test-001", + // "symbol":"BTC-PERP-REV", + // "price":"10000", + // "leverage":"1", + // "origQty":"100", + // "executedQty":"0", + // "avgPrice":"0", + // "marginLocked":"0.01", + // "orderType":"LIMIT", + // "side":"SELL_OPEN", + // "fees":[], + // "timeInForce":"GTC", + // "status":"NEW", + // "priceType":"INPUT" + // } + // ] + // + return this.parseOrders (response, market, since, limit); + } + + async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) { + await this.loadMarkets (); + let market = undefined; + const request = { + // if orderId is set, it will get orders < that orderId otherwise most recent orders are returned + // 'orderId': '43287482374', + // 'endTime': this.milliseconds (), // optional + }; + const defaultType = this.safeString (this.options, 'type', 'spot'); + const options = this.safeValue (this.options, 'fetchClosedOrders', {}); + const fetchClosedOrdersType = this.safeString (options, 'type', defaultType); + let type = this.safeString (params, 'type', fetchClosedOrdersType); + if (symbol !== undefined) { + market = this.market (symbol); + request['symbol'] = market['id']; + type = market['type']; + } + const query = this.omit (params, 'type'); + if (limit !== undefined) { + request['limit'] = limit; // default 500, max 1000 + } + if (since !== undefined) { + request['startTime'] = since; + } + let method = 'privateGetHistoryOrders'; + if (type === 'future') { + method = 'contractGetHistoryOrders'; + } else if (type === 'option') { + method = 'optionGetHistoryOrders'; + } + const response = await this[method] (this.extend (request, query)); + // + // spot + // + // [ + // { + // "orderId":"616384027202542080", + // "clientOrderId":"158821470194414688", + // "exchangeId":"301", + // "symbol":"TBTCBUSDT", + // "price":"0", + // "origQty":"0.1", + // "executedQty":"0.1", + // "cummulativeQuoteQty":"682.606", + // "avgPrice":"6826.06", + // "status":"FILLED", + // "timeInForce":"GTC", + // "type":"MARKET", + // "side":"SELL", + // "stopPrice":"0.0", + // "icebergQty":"0.0", + // "time":"1588214701974", + // "updateTime":"0", + // "isWorking":true + // } + // ] + // + return this.parseOrders (response, market, since, limit); + } + + async fetchOrder (id, symbol = undefined, params = {}) { + await this.loadMarkets (); + const clientOrderId = this.safeValue2 (params, 'origClientOrderId', 'clientOrderId'); + const request = {}; + const defaultType = this.safeString (this.options, 'type', 'spot'); + const options = this.safeValue (this.options, 'fetchOrder', {}); + const fetchOrderType = this.safeString (options, 'type', defaultType); + const type = this.safeString (params, 'type', fetchOrderType); + let query = this.omit (params, 'type'); + if (clientOrderId !== undefined) { + request['origClientOrderId'] = clientOrderId; + query = this.omit (query, [ 'origClientOrderId', 'clientOrderId' ]); + } else { + request['orderId'] = id; + } + let method = 'privateGetOrder'; + if (type === 'future') { + method = 'contractGetGetOrder'; + } else if (type === 'option') { + method = 'optionGetGetOrder'; + } + const response = await this[method] (this.extend (request, query)); + return this.parseOrder (response); + } + + async fetchDeposits (code = undefined, since = undefined, limit = undefined, params = {}) { + await this.loadMarkets (); + let currency = undefined; + const request = { + // 'fromId': 'string', // if fromId is set, it will get deposits > that fromId, otherwise most recent deposits are returned + }; + if (code !== undefined) { + currency = this.currency (code); + } + if (since !== undefined) { + request['startTime'] = since; + } + if (limit !== undefined) { + request['limit'] = limit; + } + const response = await this.privateGetDepositOrders (this.extend (request, params)); + // + // [ + // { + // 'time': '1565769575929', + // 'orderId': '428100569859739648', + // 'token': 'USDT', + // 'address': '', + // 'addressTag': '', + // 'fromAddress': '', + // 'fromAddressTag': '', + // 'quantity': '1100', + // }, + // ] + // + return this.parseTransactions (response, currency, since, limit); + } + + async fetchWithdrawals (code = undefined, since = undefined, limit = undefined, params = {}) { + await this.loadMarkets (); + let currency = undefined; + const request = { + // 'fromId': 'string', // if fromId is set, it will get deposits > that fromId, otherwise most recent deposits are returned + }; + if (code !== undefined) { + currency = this.currency (code); + request['token'] = currency['id']; + } + if (since !== undefined) { + request['startTime'] = since; + } + if (limit !== undefined) { + request['limit'] = limit; // default 500, max 1000 + } + const response = await this.privateGetWithdrawalOrders (this.extend (request, params)); + // + // [ + // { + // "time":"1536232111669", + // "orderId":"90161227158286336", + // "accountId":"517256161325920", + // "tokenId":"BHC", + // "tokenName":"BHC", + // "address":"0x815bF1c3cc0f49b8FC66B21A7e48fCb476051209", + // "addressExt":"address tag", + // "quantity":"14", // Withdrawal qty + // "arriveQuantity":"14", // Arrived qty + // "statusCode":"PROCESSING_STATUS", + // "status":3, + // "txid":"", + // "txidUrl":"", + // "walletHandleTime":"1536232111669", + // "feeTokenId":"BHC", + // "feeTokenName":"BHC", + // "fee":"0.1", + // "requiredConfirmNum":0, // Required confirmations + // "confirmNum":0, // Confirmations + // "kernelId":"", // BEAM and GRIN only + // "isInternalTransfer": false // True if this transfer is internal + // } + // ] + // + return this.parseTransactions (response, currency, since, limit); + } + + async withdraw (code, amount, address, tag = undefined, params = {}) { + this.checkAddress (address); + await this.loadMarkets (); + const currency = this.currency (code); + const clientOrderId = this.safeString (params, 'clientOrderId', this.uuid ()); + const request = { + 'clientOrderId': clientOrderId, + 'tokenId': currency['id'], + 'address': address, // the withdrawal address must be in current tag list in your PC/APP client + 'withdrawQuantity': amount, + // 'chainType': 'OMNI', // OMNI, ERC20, TRC20 + }; + if (tag !== undefined) { + request['addressExt'] = tag; + } + const response = await this.privatePostWithdraw (this.extend (request, params)); + // + // { + // "status": 0, + // "success": true, + // "needBrokerAudit": false, // Whether this request needs broker auit + // "orderId": "423885103582776064" // Id for successful withdrawal + // } + // + return { + 'info': response, + 'id': this.safeString (response, 'orderId'), + }; + } + + async fetchAccounts (params = {}) { + const response = await this.privatePostSubAccountQuery (params); + // + // [ + // { + // "accountId": "122216245228131", + // "accountName": "createSubAccountByCurl", // sub-account name + // "accountType": 1, // 1 token trading, 2 options, 3 futures + // "accountIndex": 1, // 0 main account, 1 sub-account + // }, + // ] + // + const result = []; + for (let i = 0; i < response.length; i++) { + const account = response[i]; + const accountId = this.safeString (account, 'accountId'); + const accountType = this.safeString (account, 'accountType'); + let type = accountType; + if (accountType === '1') { + type = 'spot'; + } else if (accountType === '2') { + type = 'option'; + } else if (accountType === '3') { + type = 'future'; + } + result.push ({ + 'id': accountId, + 'type': type, + 'currency': undefined, + 'info': account, + }); + } + return result; + } + + async fetchLedger (code = undefined, since = undefined, limit = undefined, params = {}) { + await this.loadMarkets (); + const request = { + 'accountType': 1, // spot 1, options 2, futures 3 + 'accountIndex': 0, // main 0, sub-account 1 + 'fromFlowId': '', // flowId to start from + 'endFlowId': '', // flowId to end with + 'endTime': 1588450533040, + }; + let currency = undefined; + if (code !== undefined) { + currency = this.currency (code); + request['tokenId'] = currency['id']; + } + if (since !== undefined) { + request['startTime'] = since; + } + if (limit !== undefined) { + request['limit'] = limit; // default 500, max 500 + } + const response = await this.privateGetBalanceFlow (this.extend (request, params)); + // + // [ + // { + // "id": "539870570957903104", + // "accountId": "122216245228131", + // "tokenId": "BTC", + // "tokenName": "BTC", + // "flowTypeValue": 51, + // "flowType": "USER_ACCOUNT_TRANSFER", + // "flowName": "Transfer", + // "change": "-12.5", + // "total": "379.624059937852365", // after change + // "created": "1579093587214" + // }, + // { + // "id": "536072393645448960", + // "accountId": "122216245228131", + // "tokenId": "USDT", + // "tokenName": "USDT", + // "flowTypeValue": 7, + // "flowType": "AIRDROP", + // "flowName": "Airdrop", + // "change": "-2000", + // "total": "918662.0917630848", + // "created": "1578640809195" + // } + // ] + // + return this.parseLedger (response, currency, since, limit); + } + + parseLedgerEntry (item, currency = undefined) { + // + // { + // "id": "539870570957903104", + // "accountId": "122216245228131", + // "tokenId": "BTC", + // "tokenName": "BTC", + // "flowTypeValue": 51, + // "flowType": "USER_ACCOUNT_TRANSFER", + // "flowName": "Transfer", + // "change": "-12.5", + // "total": "379.624059937852365", // after change + // "created": "1579093587214" + // } + // + // { + // "id": "536072393645448960", + // "accountId": "122216245228131", + // "tokenId": "USDT", + // "tokenName": "USDT", + // "flowTypeValue": 7, + // "flowType": "AIRDROP", + // "flowName": "Airdrop", + // "change": "-2000", + // "total": "918662.0917630848", + // "created": "1578640809195" + // } + // + const currencyId = this.safeString (item, 'tokenId'); + const code = this.safeCurrencyCode (currencyId, currency); + const amount = this.safeFloat (item, 'change'); + const after = this.safeFloat (item, 'total'); + const direction = (amount < 0) ? 'out' : 'in'; + let before = undefined; + if (after !== undefined && amount !== undefined) { + const difference = (direction === 'out') ? amount : -amount; + before = this.sum (after, difference); + } + const timestamp = this.safeInteger (item, 'created'); + const type = this.parseLedgerEntryType (this.safeString (item, 'flowType')); + const id = this.safeString (item, 'id'); + const account = this.safeString (item, 'accountId'); + return { + 'id': id, + 'currency': code, + 'account': account, + 'referenceAccount': undefined, + 'referenceId': undefined, + 'status': undefined, + 'amount': amount, + 'before': before, + 'after': after, + 'fee': undefined, + 'direction': direction, + 'timestamp': timestamp, + 'datetime': this.iso8601 (timestamp), + 'type': type, + 'info': item, + }; + } + + parseLedgerEntryType (type) { + const types = { + 'TRADE': 'trade', + 'FEE': 'fee', + 'TRANSFER': 'transfer', + 'DEPOSIT': 'transaction', + 'MAKER_REWARD': 'rebate', + 'PNL': 'pnl', + 'SETTLEMENT': 'settlement', + 'LIQUIDATION': 'liquidation', + 'FUNDING_SETTLEMENT': 'settlement', + 'USER_ACCOUNT_TRANSFER': 'transfer', + 'OTC_BUY_COIN': 'trade', + 'OTC_SELL_COIN': 'trade', + 'OTC_FEE': 'fee', + 'OTC_TRADE': 'trade', + 'ACTIVITY_AWARD': 'referral', + 'INVITATION_REFERRAL_BONUS': 'referral', + 'REGISTER_BONUS': 'referral', + 'AIRDROP': 'airdrop', + 'MINE_REWARD': 'reward', + }; + return this.safeString (types, type, type); + } + + parseTransactionStatus (status) { + const statuses = { + 'BROKER_AUDITING_STATUS': 'pending', + 'BROKER_REJECT_STATUS': 'failed', + 'AUDITING_STATUS': 'pending', + 'AUDIT_REJECT_STATUS': 'failed', + 'PROCESSING_STATUS': 'pending', + 'WITHDRAWAL_SUCCESS_STATUS': 'ok', + 'WITHDRAWAL_FAILURE_STATUS': 'failed', + 'BLOCK_MINING_STATUS': 'ok', + }; + return this.safeString (statuses, status, status); + } + + parseTransaction (transaction, currency = undefined) { + // + // fetchDeposits + // + // { + // 'time': '1565769575929', + // 'orderId': '428100569859739648', + // 'token': 'USDT', + // 'address': '', + // 'addressTag': '', + // 'fromAddress': '', + // 'fromAddressTag': '', + // 'quantity': '1100', + // } + // + // fetchWithdrawals + // + // { + // "time":"1536232111669", + // "orderId":"90161227158286336", + // "accountId":"517256161325920", + // "tokenId":"BHC", + // "tokenName":"BHC", + // "address":"0x815bF1c3cc0f49b8FC66B21A7e48fCb476051209", + // "addressExt":"address tag", + // "quantity":"14", // Withdrawal qty + // "arriveQuantity":"14", // Arrived qty + // "statusCode":"PROCESSING_STATUS", + // "status":3, + // "txid":"", + // "txidUrl":"", + // "walletHandleTime":"1536232111669", + // "feeTokenId":"BHC", + // "feeTokenName":"BHC", + // "fee":"0.1", + // "requiredConfirmNum":0, // Required confirmations + // "confirmNum":0, // Confirmations + // "kernelId":"", // BEAM and GRIN only + // "isInternalTransfer": false // True if this transfer is internal + // } + // + const id = this.safeString (transaction, 'orderId'); + const address = this.safeString (transaction, 'address'); + let tag = this.safeString2 (transaction, 'addressExt', 'addressTag'); + if (tag !== undefined) { + if (tag.length < 1) { + tag = undefined; + } + } + const addressFrom = this.safeString (transaction, 'fromAddress'); + let tagFrom = this.safeString (transaction, 'fromAddressTag'); + if (tagFrom !== undefined) { + if (tagFrom.length < 1) { + tagFrom = undefined; + } + } + const currencyId = this.safeString (transaction, 'tokenId'); + const code = this.safeCurrencyCode (currencyId, currency); + const timestamp = this.safeInteger (transaction, 'time'); + let txid = this.safeString (transaction, 'txid'); + if (txid === '') { + txid = undefined; + } + let type = undefined; + let status = this.parseTransactionStatus (this.safeString (transaction, 'statusCode')); + if (status === undefined) { + type = 'deposit'; + status = 'ok'; + } else { + type = 'withdrawal'; + } + const amount = this.safeFloat (transaction, 'quantity'); + const feeCost = this.safeFloat (transaction, 'fee'); + let fee = undefined; + if (feeCost !== undefined) { + const feeCurrencyId = this.safeString (transaction, 'feeTokenId'); + const feeCurrencyCode = this.safeCurrencyCode (feeCurrencyId); + fee = { + 'currency': feeCurrencyCode, + 'cost': feeCost, + }; + } + return { + 'info': transaction, + 'id': id, + 'txid': txid, + 'timestamp': timestamp, + 'datetime': this.iso8601 (timestamp), + 'addressFrom': addressFrom, + 'address': address, + 'addressTo': address, + 'tagFrom': tagFrom, + 'tag': tag, + 'tagTo': tag, + 'type': type, + 'amount': amount, + 'currency': code, + 'status': status, + 'updated': undefined, + 'fee': fee, + }; + } + + parseTicker (ticker, market = undefined) { + // + // fetchTicker, fetchTickers + // + // { + // "time":1588069860794, + // "symbol":"BNB0501PS16", + // "bestBidPrice":"0.2129", + // "bestAskPrice":"0.3163", + // "volume":"33547", + // "quoteVolume":"10801.987", + // "lastPrice":"0.2625", + // "highPrice":"0.3918", + // "lowPrice":"0.2625", + // "openPrice":"0.362", + // } + // + // fetchBidAsk, fetchBidAsks + // + // { + // "symbol": "LTCBTC", + // "bidPrice": "4.00000000", + // "bidQty": "431.00000000", + // "askPrice": "4.00000200", + // "askQty": "9.00000000" + // } + // + 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 timestamp = this.safeInteger (ticker, 'time'); + const open = this.safeFloat (ticker, 'openPrice'); + const close = this.safeFloat (ticker, 'lastPrice'); + let change = undefined; + let percentage = undefined; + let average = undefined; + if ((open !== undefined) && (close !== undefined)) { + change = close - open; + average = this.sum (open, close) / 2; + if ((close !== undefined) && (close > 0)) { + percentage = (change / open) * 100; + } + } + const quoteVolume = this.safeFloat (ticker, 'quoteVolume'); + const baseVolume = this.safeFloat (ticker, 'volume'); + let vwap = undefined; + if (baseVolume !== undefined && quoteVolume !== undefined && baseVolume > 0) { + vwap = quoteVolume / baseVolume; + } + return { + 'symbol': symbol, + 'timestamp': timestamp, + 'datetime': this.iso8601 (timestamp), + 'high': this.safeFloat (ticker, 'highPrice'), + 'low': this.safeFloat (ticker, 'lowPrice'), + 'bid': this.safeFloat2 (ticker, 'bestBidPrice', 'bidPrice'), + 'bidVolume': this.safeFloat (ticker, 'bidQty'), + 'ask': this.safeFloat2 (ticker, 'bestAskPrice', 'askPrice'), + 'askVolume': this.safeFloat (ticker, 'askQty'), + 'vwap': vwap, + 'open': open, + 'close': close, + 'last': close, + 'previousClose': undefined, + 'change': change, + 'percentage': percentage, + 'average': average, + 'baseVolume': baseVolume, + 'quoteVolume': quoteVolume, + 'info': ticker, + }; + } + + parseTrade (trade, market) { + // + // fetchTrades (public) + // + // { + // "price":"0.025344", + // "time":1588084082060, + // "qty":"1", + // "isBuyerMaker":false + // } + // + // fetchMyTrades (private) + // + // spot + // + // { + // "id":"616384027512920576", + // "symbol":"TBTCBUSDT", + // "orderId":"616384027202542080", + // "matchOrderId":"605124954767266560", + // "price":"6826.06", + // "qty":"0.1", + // "commission":"0.682606", + // "commissionAsset":"BUSDT", + // "time":"1588214701982", + // "isBuyer":false, + // "isMaker":false, + // "fee":{ + // "feeTokenId":"BUSDT", + // "feeTokenName":"BUSDT", + // "fee":"0.682606" + // } + // } + // + const id = this.safeString (trade, 'id'); + const timestamp = this.safeFloat (trade, 'time'); + const type = undefined; + const orderId = this.safeString (trade, 'orderId'); + const price = this.safeFloat (trade, 'price'); + const amount = this.safeFloat (trade, 'qty'); + let cost = undefined; + if (price !== undefined) { + if (amount !== undefined) { + cost = price * amount; + } + } + let side = undefined; + let takerOrMaker = undefined; + if ('isBuyerMaker' in trade) { + side = trade['isBuyerMaker'] ? 'sell' : 'buy'; + } else { + const isMaker = this.safeValue (trade, 'isMaker'); + if (isMaker !== undefined) { + takerOrMaker = isMaker ? 'maker' : 'taker'; + } + const isBuyer = this.safeValue (trade, 'isBuyer'); + side = isBuyer ? 'buy' : 'sell'; + } + let fee = undefined; + const feeCost = this.safeFloat (trade, 'commission'); + if (feeCost !== undefined) { + const feeCurrencyId = this.safeString (trade, 'commissionAsset'); + const feeCurrencyCode = this.safeCurrencyCode (feeCurrencyId); + fee = { + 'cost': feeCost, + 'currency': feeCurrencyCode, + }; + } + let symbol = undefined; + if ((symbol === undefined) && (market !== undefined)) { + symbol = market['symbol']; + } + return { + 'id': id, + 'info': trade, + 'timestamp': timestamp, + 'datetime': this.iso8601 (timestamp), + 'symbol': symbol, + 'type': type, + 'order': orderId, + 'side': side, + 'takerOrMaker': takerOrMaker, + 'price': price, + 'amount': amount, + 'cost': cost, + 'fee': fee, + }; + } + + parseOrder (order, market = undefined) { + // + // createOrder + // + // { + // "symbol":"TBTCBUSDT", + // "orderId":"616376654496877056", + // "clientOrderId":"158821382304516955", + // "transactTime":"1588213823080", + // "price":"0", + // "origQty":"1000", + // "executedQty":"0", + // "status":"NEW", + // "timeInForce":"GTC", + // "type":"MARKET", + // "side":"BUY" + // } + // + // fetchOrder, fetchOpenOrders, fetchClosedOrders + // + // spot + // + // { + // "orderId":"616384027202542080", + // "clientOrderId":"158821470194414688", + // "exchangeId":"301", + // "symbol":"TBTCBUSDT", + // "price":"0", + // "origQty":"0.1", + // "executedQty":"0.1", + // "cummulativeQuoteQty":"682.606", + // "avgPrice":"6826.06", + // "status":"FILLED", + // "timeInForce":"GTC", + // "type":"MARKET", + // "side":"SELL", + // "stopPrice":"0.0", + // "icebergQty":"0.0", + // "time":"1588214701974", + // "updateTime":"0", + // "isWorking":true + // } + // + // future + // + // { + // time: "1588353669383", + // updateTime: "0", + // orderId: "617549770304599296", + // clientOrderId: "test-001", + // symbol: "BTC-PERP-REV", + // price: "10000", + // leverage: "1", + // origQty: "100", + // executedQty: "0", + // avgPrice: "0", + // marginLocked: "0", + // orderType: "LIMIT", + // side: "SELL_OPEN", + // fees: [], + // timeInForce: "GTC", + // status: "CANCELED", + // priceType: "INPUT" + // } + // + // + const id = this.safeString (order, 'orderId'); + const clientOrderId = this.safeString (order, 'clientOrderId'); + let timestamp = this.safeInteger (order, 'time'); + if (timestamp === undefined) { + timestamp = this.safeInteger (order, 'transactTime'); + } + let symbol = undefined; + if (market === undefined) { + let marketId = this.safeString (order, 'symbol'); + if (marketId !== undefined) { + marketId = marketId.toUpperCase (); + if (marketId in this.markets_by_id) { + market = this.markets_by_id[marketId]; + } + } + } + let type = this.safeStringLower (order, 'type'); + const side = this.safeStringLower (order, 'side'); + let price = this.safeFloat (order, 'price'); + let average = this.safeFloat (order, 'avgPrice'); + let amount = undefined; + let cost = this.safeFloat (order, 'cummulativeQuoteQty'); + let filled = undefined; + let remaining = undefined; + if (type === undefined) { + type = this.safeStringLower (order, 'orderType'); + if ((market !== undefined) && market['inverse']) { + cost = this.safeFloat (order, 'executedQty'); + amount = undefined; + } + if (cost === 0.0) { + filled = 0; + } + } else { + amount = this.safeFloat (order, 'origQty'); + if (type === 'market') { + price = undefined; + if (side === 'buy') { + amount = undefined; + } + } + filled = this.safeFloat (order, 'executedQty'); + if (filled !== undefined) { + if (amount !== undefined) { + remaining = amount - filled; + } + } + } + if (average === 0.0) { + average = undefined; + } + const status = this.parseOrderStatus (this.safeString (order, 'status')); + if (market !== undefined) { + symbol = market['symbol']; + } + const result = { + 'info': order, + 'id': id, + 'clientOrderId': clientOrderId, + 'timestamp': timestamp, + 'datetime': this.iso8601 (timestamp), + 'lastTradeTimestamp': undefined, + 'symbol': symbol, + 'type': type, + 'side': side, + 'price': price, + 'average': average, + 'cost': cost, + 'amount': amount, + 'filled': filled, + 'remaining': remaining, + 'status': status, + 'trades': undefined, + 'fee': undefined, + 'fees': undefined, + }; + const fees = this.safeValue (order, 'fees', []); + const numFees = fees.length; + if (numFees > 0) { + result['fees'] = []; + for (let i = 0; i < fees.length; i++) { + const feeCost = this.safeFloat (fees[i], 'fee'); + if (feeCost !== undefined) { + const feeCurrencyId = this.safeString (fees[i], 'feeToken'); + const feeCurrencyCode = this.safeCurrencyCode (feeCurrencyId); + result['fees'].push ({ + 'cost': feeCost, + 'currency': feeCurrencyCode, + }); + } + } + } + return result; + } + + parseOrderStatus (status) { + const statuses = { + 'NEW': 'open', + 'CANCELED': 'canceled', + 'FILLED': 'closed', + 'PENDING_CANCEL': 'canceled', + }; + return this.safeString (statuses, status, status); + } + + sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) { + let url = this.urls['api'][api] + '/' + this.version + '/' + this.implodeParams (path, params); + const query = this.omit (params, this.extractParams (path)); + const isPublicContract = (api === 'contract') && ((path === 'insurance') || (path === 'fundingRate')); + if ((api === 'public') || (api === 'quote') || isPublicContract) { + if (Object.keys (params).length) { + url += '?' + this.urlencode (params); + } + } else { + const timestamp = this.milliseconds (); + this.checkRequiredCredentials (); + const request = this.extend ({ + 'timestamp': timestamp, + }, query); + // 准备待签名数据 + const auth = this.urlencode (request); + const signature = this.hmac (this.encode (auth), this.encode (this.secret), 'sha256'); + request['signature'] = signature; + headers = { + 'X-BH-APIKEY': this.apiKey, + }; + if (method === 'POST') { + body = this.urlencode (request); + headers = this.extend ({ + 'Content-Type': 'application/x-www-form-urlencoded', + }, headers); + } else { + url += '?' + this.urlencode (request); + } + } + return { 'url': url, 'method': method, 'body': body, 'headers': headers }; + } + + handleErrors (httpCode, reason, url, method, headers, body, response, requestHeaders, requestBody) { + if (response === undefined) { + return; // fallback to default error handler + } + if ('code' in response) { + const code = this.safeString (response, 'code'); + if (code !== '0') { + const feedback = this.id + ' ' + body; + this.throwExactlyMatchedException (this.exceptions['exact'], code, feedback); + throw new ExchangeError (feedback); + } + } + } +}; diff --git a/TaskServer/node_modules/ccxt/js/hitbtc.js b/TaskServer/node_modules/ccxt/js/hitbtc.js index 6cc535b07..14b6e46a0 100644 --- a/TaskServer/node_modules/ccxt/js/hitbtc.js +++ b/TaskServer/node_modules/ccxt/js/hitbtc.js @@ -730,14 +730,13 @@ module.exports = class hitbtc extends Exchange { } parseOHLCV (ohlcv, market = undefined, timeframe = '1d', since = undefined, limit = undefined) { - const timestamp = this.parse8601 (ohlcv['timestamp']); return [ - timestamp, - parseFloat (ohlcv['open']), - parseFloat (ohlcv['max']), - parseFloat (ohlcv['min']), - parseFloat (ohlcv['close']), - parseFloat (ohlcv['volume']), + this.parse8601 (this.safeString (ohlcv, 'timestamp')), + this.safeFloat (ohlcv, 'open'), + this.safeFloat (ohlcv, 'max'), + this.safeFloat (ohlcv, 'min'), + this.safeFloat (ohlcv, 'close'), + this.safeFloat (ohlcv, 'volume'), ]; } diff --git a/TaskServer/node_modules/ccxt/js/hitbtc2.js b/TaskServer/node_modules/ccxt/js/hitbtc2.js deleted file mode 100644 index 145d70a92..000000000 --- a/TaskServer/node_modules/ccxt/js/hitbtc2.js +++ /dev/null @@ -1,17 +0,0 @@ -'use strict'; - -// --------------------------------------------------------------------------- - -const hitbtc = require ('./hitbtc'); - -// --------------------------------------------------------------------------- - -module.exports = class hitbtc2 extends hitbtc { - describe () { - // this is a temporary stub for backward compatibility - // https://github.com/ccxt/ccxt/issues/6678 - return this.deepExtend (super.describe (), { - 'id': 'hitbtc2', - }); - } -}; diff --git a/TaskServer/node_modules/ccxt/js/huobipro.js b/TaskServer/node_modules/ccxt/js/huobipro.js index b3b298c49..497cdf9bf 100644 --- a/TaskServer/node_modules/ccxt/js/huobipro.js +++ b/TaskServer/node_modules/ccxt/js/huobipro.js @@ -163,12 +163,14 @@ module.exports = class huobipro extends Exchange { 'exceptions': { 'exact': { // err-code + 'bad-request': BadRequest, 'api-not-support-temp-addr': PermissionDenied, // {"status":"error","err-code":"api-not-support-temp-addr","err-msg":"API withdrawal does not support temporary addresses","data":null} 'timeout': RequestTimeout, // {"ts":1571653730865,"status":"error","err-code":"timeout","err-msg":"Request Timeout"} 'gateway-internal-error': ExchangeNotAvailable, // {"status":"error","err-code":"gateway-internal-error","err-msg":"Failed to load data. Try again later.","data":null} 'account-frozen-balance-insufficient-error': InsufficientFunds, // {"status":"error","err-code":"account-frozen-balance-insufficient-error","err-msg":"trade account balance is not enough, left: `0.0027`","data":null} 'invalid-amount': InvalidOrder, // eg "Paramemter `amount` is invalid." 'order-limitorder-amount-min-error': InvalidOrder, // limit order amount error, min: `0.001` + 'order-limitorder-amount-max-error': InvalidOrder, // market order amount error, max: `1000000` 'order-marketorder-amount-min-error': InvalidOrder, // market order amount error, min: `0.01` 'order-limitorder-price-min-error': InvalidOrder, // limit order price error 'order-limitorder-price-max-error': InvalidOrder, // limit order price error @@ -331,6 +333,8 @@ module.exports = class huobipro extends Exchange { } parseTicker (ticker, market = undefined) { + // + // fetchTicker // // { // "amount": 26228.672978342216, @@ -346,25 +350,47 @@ module.exports = class huobipro extends Exchange { // "bid": [ 9146.86, 0.080758 ], // } // + // fetchTickers + // { + // symbol: "bhdht", + // open: 2.3938, + // high: 2.4151, + // low: 2.3323, + // close: 2.3909, + // amount: 628.992, + // vol: 1493.71841095, + // count: 2088, + // bid: 2.3643, + // bidSize: 0.7136, + // ask: 2.4061, + // askSize: 0.4156 + // } + // let symbol = undefined; if (market !== undefined) { symbol = market['symbol']; } const timestamp = this.safeInteger (ticker, 'ts'); let bid = undefined; - let ask = undefined; let bidVolume = undefined; + let ask = undefined; let askVolume = undefined; if ('bid' in ticker) { if (Array.isArray (ticker['bid'])) { bid = this.safeFloat (ticker['bid'], 0); bidVolume = this.safeFloat (ticker['bid'], 1); + } else { + bid = this.safeFloat (ticker, 'bid'); + bidVolume = this.safeValue (ticker, 'bidSize'); } } if ('ask' in ticker) { if (Array.isArray (ticker['ask'])) { ask = this.safeFloat (ticker['ask'], 0); askVolume = this.safeFloat (ticker['ask'], 1); + } else { + ask = this.safeFloat (ticker, 'ask'); + askVolume = this.safeValue (ticker, 'askSize'); } } const open = this.safeFloat (ticker, 'open'); diff --git a/TaskServer/node_modules/ccxt/js/ice3x.js b/TaskServer/node_modules/ccxt/js/ice3x.js index 1f660df72..73230a5b1 100644 --- a/TaskServer/node_modules/ccxt/js/ice3x.js +++ b/TaskServer/node_modules/ccxt/js/ice3x.js @@ -3,7 +3,7 @@ // --------------------------------------------------------------------------- const Exchange = require ('./base/Exchange'); -const { ExchangeError, AuthenticationError } = require ('./base/errors'); +const { ExchangeError, AuthenticationError, ArgumentsRequired } = require ('./base/errors'); // --------------------------------------------------------------------------- @@ -221,7 +221,7 @@ module.exports = class ice3x extends Exchange { const type = this.safeString (params, 'type'); if ((type !== 'ask') && (type !== 'bid')) { // eslint-disable-next-line quotes - throw new ExchangeError (this.id + " fetchOrderBook requires an exchange-specific extra 'type' param ('bid' or 'ask') when used with a limit"); + throw new ArgumentsRequired (this.id + " fetchOrderBook requires an exchange-specific extra 'type' param ('bid' or 'ask') when used with a limit"); } else { request['items_per_page'] = limit; } diff --git a/TaskServer/node_modules/ccxt/js/indodax.js b/TaskServer/node_modules/ccxt/js/indodax.js index 83f7b4e2c..42ee4051e 100644 --- a/TaskServer/node_modules/ccxt/js/indodax.js +++ b/TaskServer/node_modules/ccxt/js/indodax.js @@ -362,7 +362,7 @@ module.exports = class indodax extends Exchange { async fetchOrder (id, symbol = undefined, params = {}) { if (symbol === undefined) { - throw new ExchangeError (this.id + ' fetchOrder requires a symbol'); + throw new ArgumentsRequired (this.id + ' fetchOrder requires a symbol'); } await this.loadMarkets (); const market = this.market (symbol); @@ -409,7 +409,7 @@ module.exports = class indodax extends Exchange { async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) { if (symbol === undefined) { - throw new ExchangeError (this.id + ' fetchOrders requires a symbol'); + throw new ArgumentsRequired (this.id + ' fetchOrders requires a symbol argument'); } await this.loadMarkets (); const request = {}; @@ -458,7 +458,7 @@ module.exports = class indodax extends Exchange { } const side = this.safeValue (params, 'side'); if (side === undefined) { - throw new ExchangeError (this.id + ' cancelOrder requires an extra "side" param'); + throw new ArgumentsRequired (this.id + ' cancelOrder requires an extra "side" param'); } await this.loadMarkets (); const market = this.market (symbol); diff --git a/TaskServer/node_modules/ccxt/js/itbit.js b/TaskServer/node_modules/ccxt/js/itbit.js index f146ae46c..dacb3199f 100644 --- a/TaskServer/node_modules/ccxt/js/itbit.js +++ b/TaskServer/node_modules/ccxt/js/itbit.js @@ -3,7 +3,7 @@ // --------------------------------------------------------------------------- const Exchange = require ('./base/Exchange'); -const { ExchangeError, AuthenticationError } = require ('./base/errors'); +const { ExchangeError, AuthenticationError, ArgumentsRequired } = require ('./base/errors'); // --------------------------------------------------------------------------- @@ -254,7 +254,7 @@ module.exports = class itbit extends Exchange { await this.loadMarkets (); const walletId = this.safeString (params, 'walletId'); if (walletId === undefined) { - throw new ExchangeError (this.id + ' fetchMyTrades requires a walletId parameter'); + throw new ArgumentsRequired (this.id + ' fetchMyTrades requires a walletId parameter'); } const request = { 'walletId': walletId, diff --git a/TaskServer/node_modules/ccxt/js/kraken.js b/TaskServer/node_modules/ccxt/js/kraken.js index 7063d9d37..20c36d198 100644 --- a/TaskServer/node_modules/ccxt/js/kraken.js +++ b/TaskServer/node_modules/ccxt/js/kraken.js @@ -36,6 +36,7 @@ module.exports = class kraken extends Exchange { 'withdraw': true, 'fetchLedgerEntry': true, 'fetchLedger': true, + 'fetchOrderTrades': 'emulated', }, 'marketsByAltname': {}, 'timeframes': { @@ -54,7 +55,7 @@ module.exports = class kraken extends Exchange { 'api': { 'public': 'https://api.kraken.com', 'private': 'https://api.kraken.com', - 'zendesk': 'https://support.kraken.com/hc/en-us/articles', + 'zendesk': 'https://kraken.zendesk.com/api/v2/help_center/en-us/articles', // use the public zendesk api to receive article bodies and bypass new anti-spam protections }, 'www': 'https://www.kraken.com', 'doc': 'https://www.kraken.com/features/api', @@ -149,9 +150,9 @@ module.exports = class kraken extends Exchange { 'get': [ // we should really refrain from putting fixed fee numbers and stop hardcoding // we will be using their web APIs to scrape all numbers from these articles - '205893708-What-is-the-minimum-order-size-', - '201396777-What-are-the-deposit-fees-', - '201893608-What-are-the-withdrawal-fees-', + '205893708', // -What-is-the-minimum-order-size- + '360000292886', // -What-are-the-deposit-fees- + '201893608', // -What-are-the-withdrawal-fees- ], }, 'public': { @@ -234,12 +235,14 @@ module.exports = class kraken extends Exchange { return this.decimalToPrecision (fee, TRUNCATE, this.markets[symbol]['precision']['amount'], DECIMAL_PLACES); } - async fetchMinOrderAmounts () { - const html = await this.zendeskGet205893708WhatIsTheMinimumOrderSize (); + async fetchMinOrderAmounts (params = {}) { + const response = await this.zendeskGet205893708 (params); + const article = this.safeValue (response, 'article'); + const html = this.safeString (article, 'body'); const parts = html.split (''); const numParts = parts.length; if (numParts < 3) { - throw new NotSupported (this.id + ' fetchMinOrderAmounts HTML page markup has changed: https://support.kraken.com/hc/en-us/articles/205893708-What-is-the-minimum-order-size-'); + throw new NotSupported (this.id + ' fetchMinOrderAmounts HTML page markup has changed: https://kraken.zendesk.com/api/v2/help_center/en-us/articles/205893708'); } const result = {}; // skip the part before the header and the header itself @@ -262,6 +265,52 @@ module.exports = class kraken extends Exchange { async fetchMarkets (params = {}) { const response = await this.publicGetAssetPairs (params); + // + // { + // "error":[], + // "result":{ + // "ADAETH":{ + // "altname":"ADAETH", + // "wsname":"ADA\/ETH", + // "aclass_base":"currency", + // "base":"ADA", + // "aclass_quote":"currency", + // "quote":"XETH", + // "lot":"unit", + // "pair_decimals":7, + // "lot_decimals":8, + // "lot_multiplier":1, + // "leverage_buy":[], + // "leverage_sell":[], + // "fees":[ + // [0,0.26], + // [50000,0.24], + // [100000,0.22], + // [250000,0.2], + // [500000,0.18], + // [1000000,0.16], + // [2500000,0.14], + // [5000000,0.12], + // [10000000,0.1] + // ], + // "fees_maker":[ + // [0,0.16], + // [50000,0.14], + // [100000,0.12], + // [250000,0.1], + // [500000,0.08], + // [1000000,0.06], + // [2500000,0.04], + // [5000000,0.02], + // [10000000,0] + // ], + // "fee_volume_currency":"ZUSD", + // "margin_call":80, + // "margin_stop":40 + // }, + // } + // } + // const fetchMinOrderAmounts = this.safeValue (this.options, 'fetchMinOrderAmounts', false); let limits = {}; if (fetchMinOrderAmounts) { @@ -441,6 +490,13 @@ module.exports = class kraken extends Exchange { }; } + parseBidAsk (bidask, priceKey = 0, amountKey = 1) { + const price = this.safeFloat (bidask, priceKey); + const amount = this.safeFloat (bidask, amountKey); + const timestamp = this.safeInteger (bidask, 2); + return [ price, amount, timestamp ]; + } + async fetchOrderBook (symbol, limit = undefined, params = {}) { await this.loadMarkets (); const market = this.market (symbol); @@ -454,7 +510,27 @@ module.exports = class kraken extends Exchange { request['count'] = limit; // 100 } const response = await this.publicGetDepth (this.extend (request, params)); - const orderbook = response['result'][market['id']]; + // + // { + // "error":[], + // "result":{ + // "XETHXXBT":{ + // "asks":[ + // ["0.023480","4.000",1586321307], + // ["0.023490","50.095",1586321306], + // ["0.023500","28.535",1586321302], + // ], + // "bids":[ + // ["0.023470","59.580",1586321307], + // ["0.023460","20.000",1586321301], + // ["0.023440","67.832",1586321306], + // ] + // } + // } + // } + // + const result = this.safeValue (response, 'result', {}); + const orderbook = this.safeValue (result, market['id']); return this.parseOrderBook (orderbook); } @@ -708,26 +784,46 @@ module.exports = class kraken extends Exchange { } parseTrade (trade, market = undefined) { + // + // fetchTrades (public) + // + // [ + // "0.032310", // price + // "4.28169434", // amount + // 1541390792.763, // timestamp + // "s", // sell or buy + // "l", // limit or market + // "" + // ] + // + // fetchOrderTrades (private) + // + // { + // id: 'TIMIRG-WUNNE-RRJ6GT', // injected from outside + // ordertxid: 'OQRPN2-LRHFY-HIFA7D', + // postxid: 'TKH2SE-M7IF5-CFI7LT', + // pair: 'USDCUSDT', + // time: 1586340086.457, + // type: 'sell', + // ordertype: 'market', + // price: '0.99860000', + // cost: '22.16892001', + // fee: '0.04433784', + // vol: '22.20000000', + // margin: '0.00000000', + // misc: '' + // } + // let timestamp = undefined; let side = undefined; let type = undefined; let price = undefined; let amount = undefined; + let cost = undefined; let id = undefined; let order = undefined; let fee = undefined; - const marketId = this.safeString (trade, 'pair'); - const foundMarket = this.findMarketByAltnameOrId (marketId); let symbol = undefined; - if (foundMarket !== undefined) { - market = foundMarket; - } else if (marketId !== undefined) { - // delisted market ids go here - market = this.getDelistedMarketById (marketId); - } - if (market !== undefined) { - symbol = market['symbol']; - } if (Array.isArray (trade)) { timestamp = this.safeTimestamp (trade, 2); side = (trade[3] === 's') ? 'sell' : 'buy'; @@ -738,17 +834,27 @@ module.exports = class kraken extends Exchange { if (tradeLength > 6) { id = this.safeString (trade, 6); // artificially added as per #1794 } + } else if (typeof trade === 'string') { + id = trade; } else if ('ordertxid' in trade) { + const marketId = this.safeString (trade, 'pair'); + const foundMarket = this.findMarketByAltnameOrId (marketId); + if (foundMarket !== undefined) { + market = foundMarket; + } else if (marketId !== undefined) { + // delisted market ids go here + market = this.getDelistedMarketById (marketId); + } order = trade['ordertxid']; id = this.safeString2 (trade, 'id', 'postxid'); timestamp = this.safeTimestamp (trade, 'time'); - side = trade['type']; - type = trade['ordertype']; + side = this.safeString (trade, 'type'); + type = this.safeString (trade, 'ordertype'); price = this.safeFloat (trade, 'price'); amount = this.safeFloat (trade, 'vol'); if ('fee' in trade) { let currency = undefined; - if (market) { + if (market !== undefined) { currency = market['quote']; } fee = { @@ -757,6 +863,14 @@ module.exports = class kraken extends Exchange { }; } } + if (market !== undefined) { + symbol = market['symbol']; + } + if (price !== undefined) { + if (amount !== undefined) { + cost = price * amount; + } + } return { 'id': id, 'order': order, @@ -769,7 +883,7 @@ module.exports = class kraken extends Exchange { 'takerOrMaker': undefined, 'price': price, 'amount': amount, - 'cost': price * amount, + 'cost': cost, 'fee': fee, }; } @@ -986,6 +1100,11 @@ module.exports = class kraken extends Exchange { const status = this.parseOrderStatus (this.safeString (order, 'status')); const id = this.safeString (order, 'id'); const clientOrderId = this.safeString (order, 'userref'); + const rawTrades = this.safeValue (order, 'trades'); + let trades = undefined; + if (rawTrades !== undefined) { + trades = this.parseTrades (rawTrades, market, undefined, undefined, { 'order': id }); + } return { 'id': id, 'clientOrderId': clientOrderId, @@ -1004,8 +1123,7 @@ module.exports = class kraken extends Exchange { 'average': average, 'remaining': remaining, 'fee': fee, - // 'trades': this.parseTrades (order['trades'], market), - 'trades': undefined, + 'trades': trades, }; } @@ -1026,16 +1144,129 @@ module.exports = class kraken extends Exchange { async fetchOrder (id, symbol = undefined, params = {}) { await this.loadMarkets (); - const response = await this.privatePostQueryOrders (this.extend ({ + const clientOrderId = this.safeValue2 (params, 'userref', 'clientOrderId'); + const request = { 'trades': true, // whether or not to include trades in output (optional, default false) - 'txid': id, // do not comma separate a list of ids - use fetchOrdersByIds instead + // 'txid': id, // do not comma separate a list of ids - use fetchOrdersByIds instead // 'userref': 'optional', // restrict results to given user reference id (optional) - }, params)); - const orders = response['result']; + }; + let query = params; + if (clientOrderId !== undefined) { + request['userref'] = clientOrderId; + query = this.omit (params, [ 'userref', 'clientOrderId' ]); + } else { + request['txid'] = id; + } + const response = await this.privatePostQueryOrders (this.extend (request, query)); + // + // { + // "error":[], + // "result":{ + // "OTLAS3-RRHUF-NDWH5A":{ + // "refid":null, + // "userref":null, + // "status":"closed", + // "reason":null, + // "opentm":1586822919.3342, + // "closetm":1586822919.365, + // "starttm":0, + // "expiretm":0, + // "descr":{ + // "pair":"XBTUSDT", + // "type":"sell", + // "ordertype":"market", + // "price":"0", + // "price2":"0", + // "leverage":"none", + // "order":"sell 0.21804000 XBTUSDT @ market", + // "close":"" + // }, + // "vol":"0.21804000", + // "vol_exec":"0.21804000", + // "cost":"1493.9", + // "fee":"3.8", + // "price":"6851.5", + // "stopprice":"0.00000", + // "limitprice":"0.00000", + // "misc":"", + // "oflags":"fciq", + // "trades":["TT5UC3-GOIRW-6AZZ6R"] + // } + // } + // } + // + const orders = this.safeValue (response, 'result', []); const order = this.parseOrder (this.extend ({ 'id': id }, orders[id])); return this.extend ({ 'info': response }, order); } + async fetchOrderTrades (id, symbol = undefined, since = undefined, limit = undefined, params = {}) { + const orderTrades = this.safeValue (params, 'trades'); + const tradeIds = []; + if (orderTrades === undefined) { + throw new ArgumentsRequired (this.id + " fetchOrderTrades requires a unified order structure in the params argument or a 'trades' param (an array of trade id strings)"); + } else { + for (let i = 0; i < orderTrades.length; i++) { + const orderTrade = orderTrades[i]; + if (typeof orderTrade === 'string') { + tradeIds.push (orderTrade); + } else { + tradeIds.push (orderTrade['id']); + } + } + } + await this.loadMarkets (); + const options = this.safeValue (this.options, 'fetchOrderTrades', {}); + const batchSize = this.safeInteger (options, 'batchSize', 20); + let numBatches = parseInt (tradeIds / batchSize); + numBatches = this.sum (numBatches, 1); + const numTradeIds = tradeIds.length; + let result = []; + for (let j = 0; j < numBatches; j++) { + const requestIds = []; + for (let k = 0; k < batchSize; k++) { + const index = this.sum (j * batchSize, k); + if (index < numTradeIds) { + requestIds.push (tradeIds[index]); + } + } + const request = { + 'txid': requestIds.join (','), + }; + const response = await this.privatePostQueryTrades (request); + // + // { + // error: [], + // result: { + // 'TIMIRG-WUNNE-RRJ6GT': { + // ordertxid: 'OQRPN2-LRHFY-HIFA7D', + // postxid: 'TKH2SE-M7IF5-CFI7LT', + // pair: 'USDCUSDT', + // time: 1586340086.457, + // type: 'sell', + // ordertype: 'market', + // price: '0.99860000', + // cost: '22.16892001', + // fee: '0.04433784', + // vol: '22.20000000', + // margin: '0.00000000', + // misc: '' + // } + // } + // } + // + const rawTrades = this.safeValue (response, 'result'); + const ids = Object.keys (rawTrades); + for (let i = 0; i < ids.length; i++) { + rawTrades[ids[i]]['id'] = ids[i]; + } + const trades = this.parseTrades (rawTrades, undefined, since, limit); + const tradesFilteredBySymbol = this.filterBySymbol (trades, symbol); + result = this.arrayConcat (result, tradesFilteredBySymbol); + } + return result; + } + async fetchOrdersByIds (ids, symbol = undefined, params = {}) { await this.loadMarkets (); const response = await this.privatePostQueryOrders (this.extend ({ @@ -1248,11 +1479,11 @@ module.exports = class kraken extends Exchange { } async fetchDeposits (code = undefined, since = undefined, limit = undefined, params = {}) { - await this.loadMarkets (); // https://www.kraken.com/en-us/help/api#deposit-status if (code === undefined) { throw new ArgumentsRequired (this.id + ' fetchDeposits requires a currency code argument'); } + await this.loadMarkets (); const currency = this.currency (code); const request = { 'asset': currency['id'], @@ -1275,11 +1506,11 @@ module.exports = class kraken extends Exchange { } async fetchWithdrawals (code = undefined, since = undefined, limit = undefined, params = {}) { - await this.loadMarkets (); // https://www.kraken.com/en-us/help/api#withdraw-status if (code === undefined) { throw new ArgumentsRequired (this.id + ' fetchWithdrawals requires a currency code argument'); } + await this.loadMarkets (); const currency = this.currency (code); const request = { 'asset': currency['id'], @@ -1328,7 +1559,7 @@ module.exports = class kraken extends Exchange { } method = this.options['depositMethods'][code][0]['method']; } else { - throw new ExchangeError (this.id + ' fetchDepositAddress() requires an extra `method` parameter. Use fetchDepositMethods ("' + code + '") to get a list of available deposit methods or enable the exchange property .options["cacheDepositMethodsOnFetchDepositAddress"] = true'); + throw new ArgumentsRequired (this.id + ' fetchDepositAddress() requires an extra `method` parameter. Use fetchDepositMethods ("' + code + '") to get a list of available deposit methods or enable the exchange property .options["cacheDepositMethodsOnFetchDepositAddress"] = true'); } } const request = { diff --git a/TaskServer/node_modules/ccxt/js/kucoin.js b/TaskServer/node_modules/ccxt/js/kucoin.js index 3afaaba98..025d0dc1e 100644 --- a/TaskServer/node_modules/ccxt/js/kucoin.js +++ b/TaskServer/node_modules/ccxt/js/kucoin.js @@ -69,7 +69,9 @@ module.exports = class kucoin extends Exchange { 'public': { 'get': [ 'timestamp', + 'status', 'symbols', + 'markets', 'market/allTickers', 'market/orderbook/level{level}', 'market/orderbook/level2', @@ -81,6 +83,9 @@ module.exports = class kucoin extends Exchange { 'market/stats', 'currencies', 'currencies/{currency}', + 'prices', + 'mark-price/{symbol}/current', + 'margin/config', ], 'post': [ 'bullet-public', @@ -92,6 +97,10 @@ module.exports = class kucoin extends Exchange { 'accounts/{accountId}', 'accounts/{accountId}/ledgers', 'accounts/{accountId}/holds', + 'accounts/transferable', + 'sub/user', + 'sub-accounts', + 'sub-accounts/{subUserId}', 'deposit-addresses', 'deposits', 'hist-deposits', @@ -101,8 +110,20 @@ module.exports = class kucoin extends Exchange { 'withdrawals/quotas', 'orders', 'orders/{orderId}', + 'limit/orders', 'fills', 'limit/fills', + 'margin/account', + 'margin/borrow', + 'margin/borrow/outstanding', + 'margin/borrow/borrow/repaid', + 'margin/lend/active', + 'margin/lend/done', + 'margin/lend/trade/unsettled', + 'margin/lend/trade/settled', + 'margin/lend/assets', + 'margin/market', + 'margin/margin/trade/last', ], 'post': [ 'accounts', @@ -111,11 +132,19 @@ module.exports = class kucoin extends Exchange { 'deposit-addresses', 'withdrawals', 'orders', + 'orders/multi', + 'margin/borrow', + 'margin/repay/all', + 'margin/repay/single', + 'margin/lend', + 'margin/toggle-auto-lend', 'bullet-private', ], 'delete': [ 'withdrawals/{withdrawalId}', + 'orders', 'orders/{orderId}', + 'margin/lend/{orderId}', ], }, }, @@ -247,18 +276,20 @@ module.exports = class kucoin extends Exchange { async fetchMarkets (params = {}) { const response = await this.publicGetSymbols (params); // - // { quoteCurrency: 'BTC', - // symbol: 'KCS-BTC', - // quoteMaxSize: '9999999', - // quoteIncrement: '0.000001', - // baseMinSize: '0.01', - // quoteMinSize: '0.00001', - // enableTrading: true, - // priceIncrement: '0.00000001', - // name: 'KCS-BTC', - // baseIncrement: '0.01', - // baseMaxSize: '9999999', - // baseCurrency: 'KCS' } + // { + // quoteCurrency: 'BTC', + // symbol: 'KCS-BTC', + // quoteMaxSize: '9999999', + // quoteIncrement: '0.000001', + // baseMinSize: '0.01', + // quoteMinSize: '0.00001', + // enableTrading: true, + // priceIncrement: '0.00000001', + // name: 'KCS-BTC', + // baseIncrement: '0.01', + // baseMaxSize: '9999999', + // baseCurrency: 'KCS' + // } // const data = response['data']; const result = []; @@ -344,20 +375,27 @@ module.exports = class kucoin extends Exchange { async fetchAccounts (params = {}) { const response = await this.privateGetAccounts (params); // - // { code: "200000", - // data: [ { balance: "0.00009788", + // { + // code: "200000", + // data: [ + // { + // balance: "0.00009788", // available: "0.00009788", - // holds: "0", - // currency: "BTC", - // id: "5c6a4fd399a1d81c4f9cc4d0", - // type: "trade" }, - // ..., - // { balance: "0.00000001", + // holds: "0", + // currency: "BTC", + // id: "5c6a4fd399a1d81c4f9cc4d0", + // type: "trade" + // }, + // { + // balance: "0.00000001", // available: "0.00000001", - // holds: "0", - // currency: "ETH", - // id: "5c6a49ec99a1d819392e8e9f", - // type: "trade" } ] } + // holds: "0", + // currency: "ETH", + // id: "5c6a49ec99a1d819392e8e9f", + // type: "trade" + // } + // ] + // } // const data = this.safeValue (response, 'data'); const result = []; @@ -641,30 +679,72 @@ module.exports = class kucoin extends Exchange { }; } + async fetchL3OrderBook (symbol, limit = undefined, params = {}) { + return await this.fetchOrderBook (symbol, limit, { 'level': 3 }); + } + async fetchOrderBook (symbol, limit = undefined, params = {}) { - let level = '2'; - if (limit !== undefined) { - if ((limit !== 20) && (limit !== 100)) { - throw new ExchangeError (this.id + ' fetchOrderBook limit argument must be undefined, 20 or 100'); + const level = this.safeInteger (params, 'level', 2); + let levelLimit = level.toString (); + if (level === '2') { + if (limit !== undefined) { + if ((limit !== 20) && (limit !== 100)) { + throw new ExchangeError (this.id + ' fetchOrderBook limit argument must be undefined, 20 or 100'); + } + levelLimit += '_' + limit.toString (); } - level += '_' + limit.toString (); } await this.loadMarkets (); const marketId = this.marketId (symbol); - const request = this.extend ({ 'symbol': marketId, 'level': level }, params); - const response = await this.publicGetMarketOrderbookLevelLevel (request); + const request = { 'symbol': marketId, 'level': levelLimit }; + const response = await this.publicGetMarketOrderbookLevelLevel (this.extend (request, params)); // - // { sequence: '1547731421688', - // asks: [ [ '5c419328ef83c75456bd615c', '0.9', '0.09' ], ... ], - // bids: [ [ '5c419328ef83c75456bd615c', '0.9', '0.09' ], ... ], } + // 'market/orderbook/level2' + // 'market/orderbook/level2_20' + // 'market/orderbook/level2_100' // - const data = response['data']; + // { + // "code":"200000", + // "data":{ + // "sequence":"1583235112106", + // "asks":[ + // // ... + // ["0.023197","12.5067468"], + // ["0.023194","1.8"], + // ["0.023191","8.1069672"] + // ], + // "bids":[ + // ["0.02319","1.6000002"], + // ["0.023189","2.2842325"], + // ], + // "time":1586584067274 + // } + // } + // + // 'market/orderbook/level3' + // + // { + // "code":"200000", + // "data":{ + // "sequence":"1583731857120", + // "asks":[ + // // id, price, size, timestamp in nanoseconds + // ["5e915f8acd26670009675300","6925.7","0.2","1586585482194286069"], + // ["5e915f8ace35a200090bba48","6925.7","0.001","1586585482229569826"], + // ["5e915f8a8857740009ca7d33","6926","0.00001819","1586585482149148621"], + // ], + // "bids":[ + // ["5e915f8acca406000ac88194","6925.6","0.05","1586585482384384842"], + // ["5e915f93cd26670009676075","6925.6","0.08","1586585491334914600"], + // ["5e915f906aa6e200099b49f6","6925.4","0.2","1586585488941126340"], + // ], + // "time":1586585492487 + // } + // } + // + const data = this.safeValue (response, 'data', {}); const timestamp = this.safeInteger (data, 'time'); - // level can be a string such as 2_20 or 2_100 - const levelString = this.safeString (request, 'level'); - const levelParts = levelString.split ('_'); - const offset = parseInt (levelParts[0]); - const orderbook = this.parseOrderBook (data, timestamp, 'bids', 'asks', offset - 2, offset - 1); + const orderbook = this.parseOrderBook (data, timestamp, 'bids', 'asks', level - 2, level - 1); orderbook['nonce'] = this.safeInteger (data, 'sequence'); return orderbook; } @@ -715,7 +795,7 @@ module.exports = class kucoin extends Exchange { 'datetime': this.iso8601 (timestamp), 'fee': undefined, 'status': 'open', - 'clientOid': clientOid, + 'clientOrderId': clientOid, 'info': data, }; if (!this.safeValue (params, 'quoteAmount')) { diff --git a/TaskServer/node_modules/ccxt/js/kuna.js b/TaskServer/node_modules/ccxt/js/kuna.js index 08651fad2..d688a838c 100644 --- a/TaskServer/node_modules/ccxt/js/kuna.js +++ b/TaskServer/node_modules/ccxt/js/kuna.js @@ -18,11 +18,12 @@ module.exports = class kuna extends acx { 'has': { 'CORS': false, 'fetchTickers': true, - 'fetchOHLCV': false, + 'fetchOHLCV': 'emulated', 'fetchOpenOrders': true, 'fetchMyTrades': true, 'withdraw': false, }, + 'timeframes': undefined, 'urls': { 'referral': 'https://kuna.io?r=kunaid-gvfihe8az7o4', 'logo': 'https://user-images.githubusercontent.com/1294454/31697638-912824fa-b3c1-11e7-8c36-cf9606eb94ac.jpg', @@ -191,4 +192,23 @@ module.exports = class kuna extends acx { const response = await this.privateGetTradesMy (this.extend (request, params)); return this.parseTrades (response, market, since, limit); } + + async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limits = undefined, params = {}) { + await this.loadMarkets (); + const trades = await this.fetchTrades (symbol, since, limits, params); + const ohlcvc = this.buildOHLCVC (trades, timeframe, since, limits); + const result = []; + for (let i = 0; i < ohlcvc.length; i++) { + const ohlcv = ohlcvc[i]; + result.push ([ + ohlcv[0], + ohlcv[1], + ohlcv[2], + ohlcv[3], + ohlcv[4], + ohlcv[5], + ]); + } + return result; + } }; diff --git a/TaskServer/node_modules/ccxt/js/lakebtc.js b/TaskServer/node_modules/ccxt/js/lakebtc.js index 396bf0b69..4f62ae834 100644 --- a/TaskServer/node_modules/ccxt/js/lakebtc.js +++ b/TaskServer/node_modules/ccxt/js/lakebtc.js @@ -3,7 +3,7 @@ // --------------------------------------------------------------------------- const Exchange = require ('./base/Exchange'); -const { ExchangeError } = require ('./base/errors'); +const { ExchangeError, AuthenticationError, BadSymbol, InvalidOrder, InsufficientFunds } = require ('./base/errors'); // --------------------------------------------------------------------------- @@ -14,6 +14,7 @@ module.exports = class lakebtc extends Exchange { 'name': 'LakeBTC', 'countries': [ 'US' ], 'version': 'api_v2', + 'rateLimit': 1000, 'has': { 'CORS': true, 'createMarketOrder': false, @@ -55,6 +56,14 @@ module.exports = class lakebtc extends Exchange { 'taker': 0.2 / 100, }, }, + 'exceptions': { + 'broad': { + 'Signature': AuthenticationError, + 'invalid symbol': BadSymbol, + 'Volume doit': InvalidOrder, + 'insufficient_balance': InsufficientFunds, + }, + }, }); } @@ -248,40 +257,68 @@ module.exports = class lakebtc extends Exchange { } else { this.checkRequiredCredentials (); const nonce = this.nonce (); + const nonceAsString = nonce.toString (); + const requestId = this.seconds (); let queryParams = ''; if ('params' in params) { const paramsList = params['params']; - queryParams = paramsList.join (','); + const stringParams = []; + for (let i = 0; i < paramsList.length; i++) { + let param = paramsList[i]; + if (typeof paramsList !== 'string') { + param = param.toString (); + } + stringParams.push (param); + } + queryParams = stringParams.join (','); + body = { + 'method': path, + 'params': params['params'], + 'id': requestId, + }; + } else { + body = { + 'method': path, + 'params': '', + 'id': requestId, + }; } - const query = this.urlencode ({ - 'tonce': nonce, - 'accesskey': this.apiKey, - 'requestmethod': method.toLowerCase (), - 'id': nonce, - 'method': path, - 'params': queryParams, - }); - body = this.json ({ - 'method': path, - 'params': queryParams, - 'id': nonce, - }); + body = this.json (body); + let query = [ + 'tonce=' + nonceAsString, + 'accesskey=' + this.apiKey, + 'requestmethod=' + method.toLowerCase (), + 'id=' + requestId.toString (), + 'method=' + path, + 'params=' + queryParams, + ]; + query = query.join ('&'); const signature = this.hmac (this.encode (query), this.encode (this.secret), 'sha1'); const auth = this.encode (this.apiKey + ':' + signature); + const signature64 = this.decode (this.stringToBase64 (auth)); headers = { - 'Json-Rpc-Tonce': nonce.toString (), - 'Authorization': 'Basic ' + this.decode (this.stringToBase64 (auth)), + 'Json-Rpc-Tonce': nonceAsString, + 'Authorization': 'Basic ' + signature64, 'Content-Type': 'application/json', }; } return { 'url': url, 'method': method, 'body': body, 'headers': headers }; } - async request (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) { - const response = await this.fetch2 (path, api, method, params, headers, body); - if ('error' in response) { - throw new ExchangeError (this.id + ' ' + this.json (response)); + handleErrors (code, reason, url, method, headers, body, response, requestHeaders, requestBody) { + if (response === undefined) { + return; // fallback to the default error handler + } + // + // {"error":"Failed to submit order: invalid symbol"} + // {"error":"Failed to submit order: La validation a échoué : Volume doit être supérieur ou égal à 1.0"} + // {"error":"Failed to submit order: insufficient_balance"} + // + const feedback = this.id + ' ' + body; + const error = this.safeString (response, 'error'); + if (error !== undefined) { + this.throwBroadlyMatchedException (this.exceptions['broad'], error, feedback); + throw new ExchangeError (feedback); // unknown message } - return response; } }; diff --git a/TaskServer/node_modules/ccxt/js/lbank.js b/TaskServer/node_modules/ccxt/js/lbank.js index de0464dab..41df417f7 100644 --- a/TaskServer/node_modules/ccxt/js/lbank.js +++ b/TaskServer/node_modules/ccxt/js/lbank.js @@ -3,7 +3,7 @@ // --------------------------------------------------------------------------- const Exchange = require ('./base/Exchange'); -const { ExchangeError, DDoSProtection, AuthenticationError, InvalidOrder } = require ('./base/errors'); +const { ExchangeError, DDoSProtection, AuthenticationError, InvalidOrder, ArgumentsRequired } = require ('./base/errors'); // --------------------------------------------------------------------------- @@ -339,10 +339,10 @@ module.exports = class lbank extends Exchange { await this.loadMarkets (); const market = this.market (symbol); if (since === undefined) { - throw new ExchangeError (this.id + ' fetchOHLCV requires a `since` argument'); + throw new ArgumentsRequired (this.id + ' fetchOHLCV requires a `since` argument'); } if (limit === undefined) { - throw new ExchangeError (this.id + ' fetchOHLCV requires a `limit` argument'); + throw new ArgumentsRequired (this.id + ' fetchOHLCV requires a `limit` argument'); } const request = { 'symbol': market['id'], diff --git a/TaskServer/node_modules/ccxt/js/liquid.js b/TaskServer/node_modules/ccxt/js/liquid.js index cd1337126..83e930a23 100644 --- a/TaskServer/node_modules/ccxt/js/liquid.js +++ b/TaskServer/node_modules/ccxt/js/liquid.js @@ -177,7 +177,7 @@ module.exports = class liquid extends Exchange { } async fetchMarkets (params = {}) { - const markets = await this.publicGetProducts (); + const spot = await this.publicGetProducts (params); // // [ // { @@ -208,20 +208,69 @@ module.exports = class liquid extends Exchange { // }, // ] // + const perpetual = await this.publicGetProducts ({ 'perpetual': '1' }); + // + // [ + // { + // "id": "603", + // "product_type": "Perpetual", + // "code": "CASH", + // "name": null, + // "market_ask": "1143900", + // "market_bid": "1143250", + // "currency": "JPY", + // "currency_pair_code": "P-BTCJPY", + // "pusher_channel": "product_cash_p-btcjpy_603", + // "taker_fee": "0.0", + // "maker_fee": "0.0", + // "low_market_bid": "1124450.0", + // "high_market_ask": "1151750.0", + // "volume_24h": "0.1756", + // "last_price_24h": "1129850.0", + // "last_traded_price": "1144700.0", + // "last_traded_quantity": "0.014", + // "quoted_currency": "JPY", + // "base_currency": "P-BTC", + // "tick_size": "50.0", + // "perpetual_enabled": true, + // "index_price": "1142636.03935", + // "mark_price": "1143522.18417", + // "funding_rate": "0.00033", + // "fair_price": "1143609.31009", + // "timestamp": "1581558659.195353100", + // }, + // ] + // const currencies = await this.fetchCurrencies (); const currenciesByCode = this.indexBy (currencies, 'code'); const result = []; + const markets = this.arrayConcat (spot, perpetual); for (let i = 0; i < markets.length; i++) { const market = markets[i]; - const id = market['id'].toString (); - const baseId = market['base_currency']; - const quoteId = market['quoted_currency']; + const id = this.safeString (market, 'id'); + const baseId = this.safeString (market, 'base_currency'); + const quoteId = this.safeString (market, 'quoted_currency'); + const productType = this.safeString (market, 'product_type'); + let type = 'spot'; + let spot = true; + let swap = false; + if (productType === 'Perpetual') { + spot = false; + swap = true; + type = 'swap'; + } const base = this.safeCurrencyCode (baseId); const quote = this.safeCurrencyCode (quoteId); - const symbol = base + '/' + quote; + let symbol = undefined; + if (swap) { + symbol = this.safeString (market, 'currency_pair_code'); + } else { + symbol = base + '/' + quote; + } const maker = this.safeFloat (market, 'maker_fee'); const taker = this.safeFloat (market, 'taker_fee'); - const active = !market['disabled']; + const disabled = this.safeValue (market, 'disabled', false); + const active = !disabled; const baseCurrency = this.safeValue (currenciesByCode, base); const quoteCurrency = this.safeValue (currenciesByCode, quote); const precision = { @@ -265,6 +314,9 @@ module.exports = class liquid extends Exchange { 'quote': quote, 'baseId': baseId, 'quoteId': quoteId, + 'type': type, + 'spot': spot, + 'swap': swap, 'maker': maker, 'taker': taker, 'limits': limits, @@ -393,7 +445,7 @@ module.exports = class liquid extends Exchange { return this.parseTicker (response, market); } - parseTrade (trade, market) { + parseTrade (trade, market = undefined) { // { id: 12345, // quantity: "6.789", // price: "98765.4321", @@ -420,13 +472,17 @@ module.exports = class liquid extends Exchange { } } const id = this.safeString (trade, 'id'); + let symbol = undefined; + if (market !== undefined) { + symbol = market['symbol']; + } return { 'info': trade, 'id': id, 'order': orderId, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), - 'symbol': market['symbol'], + 'symbol': symbol, 'type': undefined, 'side': side, 'takerOrMaker': takerOrMaker, diff --git a/TaskServer/node_modules/ccxt/js/livecoin.js b/TaskServer/node_modules/ccxt/js/livecoin.js index 9f8395531..eee90a7e2 100644 --- a/TaskServer/node_modules/ccxt/js/livecoin.js +++ b/TaskServer/node_modules/ccxt/js/livecoin.js @@ -439,7 +439,18 @@ module.exports = class livecoin extends Exchange { } } let symbol = undefined; - if (market !== undefined) { + const marketId = this.safeString (trade, 'symbol'); + if (marketId !== undefined) { + if (marketId in this.markets_by_id) { + market = this.markets_by_id[marketId]; + } else { + const [ baseId, quoteId ] = marketId.split ('/'); + const base = this.safeCurrencyCode (baseId); + const quote = this.safeCurrencyCode (quoteId); + symbol = base + '/' + quote; + } + } + if ((symbol === undefined) && (market !== undefined)) { symbol = market['symbol']; } return { @@ -460,16 +471,17 @@ module.exports = class livecoin extends Exchange { } async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) { - if (symbol === undefined) { - throw new ArgumentsRequired (this.id + ' fetchMyTrades requires a symbol argument'); - } await this.loadMarkets (); - const market = this.market (symbol); const request = { - 'currencyPair': market['id'], - // orderDesc': 'true', // or 'false', if true then new orders will be first, otherwise old orders will be first. + // 'currencyPair': market['id'], + // 'orderDesc': 'true', // or 'false', if true then new orders will be first, otherwise old orders will be first. // 'offset': 0, // page offset, position of the first item on the page }; + let market = undefined; + if (symbol !== undefined) { + market = this.market (symbol); + request['currencyPair'] = market['id']; + } if (limit !== undefined) { request['limit'] = limit; } diff --git a/TaskServer/node_modules/ccxt/js/mercado.js b/TaskServer/node_modules/ccxt/js/mercado.js index 661b51b66..6be269e14 100644 --- a/TaskServer/node_modules/ccxt/js/mercado.js +++ b/TaskServer/node_modules/ccxt/js/mercado.js @@ -399,17 +399,17 @@ module.exports = class mercado extends Exchange { if (code === 'BRL') { const account_ref = ('account_ref' in params); if (!account_ref) { - throw new ExchangeError (this.id + ' requires account_ref parameter to withdraw ' + code); + throw new ArgumentsRequired (this.id + ' requires account_ref parameter to withdraw ' + code); } } else if (code !== 'LTC') { const tx_fee = ('tx_fee' in params); if (!tx_fee) { - throw new ExchangeError (this.id + ' requires tx_fee parameter to withdraw ' + code); + throw new ArgumentsRequired (this.id + ' requires tx_fee parameter to withdraw ' + code); } if (code === 'XRP') { if (tag === undefined) { if (!('destination_tag' in params)) { - throw new ExchangeError (this.id + ' requires a tag argument or destination_tag parameter to withdraw ' + code); + throw new ArgumentsRequired (this.id + ' requires a tag argument or destination_tag parameter to withdraw ' + code); } } else { request['destination_tag'] = tag; diff --git a/TaskServer/node_modules/ccxt/js/okex.js b/TaskServer/node_modules/ccxt/js/okex.js index d7e5c73cd..c05baf41b 100644 --- a/TaskServer/node_modules/ccxt/js/okex.js +++ b/TaskServer/node_modules/ccxt/js/okex.js @@ -3,7 +3,7 @@ // --------------------------------------------------------------------------- const Exchange = require ('./base/Exchange'); -const { ExchangeError, ExchangeNotAvailable, ArgumentsRequired, BadRequest, AccountSuspended, InvalidAddress, PermissionDenied, DDoSProtection, InsufficientFunds, InvalidNonce, CancelPending, InvalidOrder, OrderNotFound, AuthenticationError, RequestTimeout, NotSupported, BadSymbol } = require ('./base/errors'); +const { ExchangeError, ExchangeNotAvailable, OnMaintenance, ArgumentsRequired, BadRequest, AccountSuspended, InvalidAddress, PermissionDenied, DDoSProtection, InsufficientFunds, InvalidNonce, CancelPending, InvalidOrder, OrderNotFound, AuthenticationError, RequestTimeout, NotSupported, BadSymbol } = require ('./base/errors'); const { TICK_SIZE, TRUNCATE } = require ('./base/functions/number'); // --------------------------------------------------------------------------- @@ -61,6 +61,9 @@ module.exports = class okex extends Exchange { 'doc': 'https://www.okex.com/docs/en/', 'fees': 'https://www.okex.com/pages/products/fees.html', 'referral': 'https://www.okex.com/join/1888677', + 'test': { + 'rest': 'https://testnet.okex.com', + }, }, 'api': { 'general': { @@ -348,8 +351,9 @@ module.exports = class okex extends Exchange { '30034': ExchangeError, // { "code": 30034, "message": "exchange ID does not exist" } '30035': ExchangeError, // { "code": 30035, "message": "trading is not supported in this website" } '30036': ExchangeError, // { "code": 30036, "message": "no relevant data" } - '30038': AuthenticationError, // { "code": 30038, "message": "user does not exist" } '30037': ExchangeNotAvailable, // { "code": 30037, "message": "endpoint is offline or unavailable" } + // '30038': AuthenticationError, // { "code": 30038, "message": "user does not exist" } + '30038': OnMaintenance, // {"client_oid":"","code":"30038","error_code":"30038","error_message":"Matching engine is being upgraded. Please try in about 1 minute.","message":"Matching engine is being upgraded. Please try in about 1 minute.","order_id":"-1","result":false} // futures '32001': AccountSuspended, // { "code": 32001, "message": "futures account suspended" } '32002': PermissionDenied, // { "code": 32002, "message": "futures account does not exist" } @@ -792,14 +796,6 @@ module.exports = class okex extends Exchange { 'price': this.safeFloat (market, 'tick_size'), }; const minAmount = this.safeFloat2 (market, 'min_size', 'base_min_size'); - let minPrice = this.safeFloat (market, 'tick_size'); - if (precision['price'] !== undefined) { - minPrice = Math.pow (10, -precision['price']); - } - let minCost = undefined; - if (minAmount !== undefined && minPrice !== undefined) { - minCost = minAmount * minPrice; - } const active = true; const fees = this.safeValue2 (this.fees, marketType, 'trading', {}); return this.extend (fees, { @@ -823,11 +819,11 @@ module.exports = class okex extends Exchange { 'max': undefined, }, 'price': { - 'min': minPrice, + 'min': precision['price'], 'max': undefined, }, 'cost': { - 'min': minCost, + 'min': precision['price'], 'max': undefined, }, }, @@ -1360,8 +1356,18 @@ module.exports = class okex extends Exchange { 'instrument_id': market['id'], 'granularity': this.timeframes[timeframe], }; + const duration = this.parseTimeframe (timeframe); if (since !== undefined) { + if (limit !== undefined) { + request['end'] = this.iso8601 (this.sum (since, limit * duration * 1000)); + } request['start'] = this.iso8601 (since); + } else { + const now = this.milliseconds (); + if (limit !== undefined) { + request['start'] = this.iso8601 (now - limit * duration * 1000); + request['end'] = this.iso8601 (now); + } } const response = await this[method] (this.extend (request, params)); // @@ -1841,28 +1847,7 @@ module.exports = class okex extends Exchange { // "result":true // } // - const timestamp = this.milliseconds (); - const id = this.safeString (response, 'order_id'); - return { - 'info': response, - 'id': id, - 'timestamp': timestamp, - 'datetime': this.iso8601 (timestamp), - 'lastTradeTimestamp': undefined, - 'status': undefined, - 'symbol': symbol, - 'type': type, - 'side': side, - 'price': price, - 'amount': amount, - 'filled': undefined, - 'remaining': undefined, - 'cost': undefined, - 'trades': undefined, - 'fee': undefined, - 'clientOrderId': undefined, - 'average': undefined, - }; + return this.parseOrder (response, market); } async cancelOrder (id, symbol = undefined, params = {}) { @@ -2302,9 +2287,11 @@ module.exports = class okex extends Exchange { } parseDepositAddresses (addresses) { - const result = []; + const result = {}; for (let i = 0; i < addresses.length; i++) { - result.push (this.parseDepositAddress (addresses[i])); + const address = this.parseDepositAddress (addresses[i]); + const code = address['currency']; + result[code] = address; } return result; } @@ -2350,11 +2337,11 @@ module.exports = class okex extends Exchange { // ] // const addresses = this.parseDepositAddresses (response); - const numAddresses = addresses.length; - if (numAddresses < 1) { + const address = this.safeValue (addresses, code); + if (address === undefined) { throw new InvalidAddress (this.id + ' fetchDepositAddress cannot return nonexistent addresses, you should create withdrawal addresses with the exchange website first'); } - return addresses[0]; + return address; } async withdraw (code, amount, address, tag = undefined, params = {}) { @@ -2366,7 +2353,7 @@ module.exports = class okex extends Exchange { } const fee = this.safeString (params, 'fee'); if (fee === undefined) { - throw new ExchangeError (this.id + " withdraw() requires a `fee` string parameter, network transaction fee must be ≥ 0. Withdrawals to OKCoin or OKEx are fee-free, please set '0'. Withdrawing to external digital asset address requires network transaction fee."); + throw new ArgumentsRequired (this.id + " withdraw() requires a `fee` string parameter, network transaction fee must be ≥ 0. Withdrawals to OKCoin or OKEx are fee-free, please set '0'. Withdrawing to external digital asset address requires network transaction fee."); } const request = { 'currency': currency['id'], diff --git a/TaskServer/node_modules/ccxt/js/paymium.js b/TaskServer/node_modules/ccxt/js/paymium.js index 16e50e717..b46b2c369 100644 --- a/TaskServer/node_modules/ccxt/js/paymium.js +++ b/TaskServer/node_modules/ccxt/js/paymium.js @@ -27,6 +27,7 @@ module.exports = class paymium extends Exchange { 'https://github.com/Paymium/api-documentation', 'https://www.paymium.com/page/developers', ], + 'referral': 'https://www.paymium.com/page/sign-up?referral=eDAzPoRQFMvaAB8sf-qj', }, 'api': { 'public': { @@ -41,12 +42,12 @@ module.exports = class paymium extends Exchange { }, 'private': { 'get': [ - 'merchant/get_payment/{UUID}', + 'merchant/get_payment/{uuid}', 'user', 'user/addresses', 'user/addresses/{btc_address}', 'user/orders', - 'user/orders/{UUID}', + 'user/orders/{uuid}', 'user/price_alerts', ], 'post': [ @@ -57,7 +58,7 @@ module.exports = class paymium extends Exchange { 'merchant/create_payment', ], 'delete': [ - 'user/orders/{UUID}/cancel', + 'user/orders/{uuid}/cancel', 'user/price_alerts/{id}', ], }, @@ -204,9 +205,9 @@ module.exports = class paymium extends Exchange { async cancelOrder (id, symbol = undefined, params = {}) { const request = { - 'UUID': id, + 'uuid': id, }; - return await this.privateDeleteUserOrdersUUIDCancel (this.extend (request, params)); + return await this.privateDeleteUserOrdersUuidCancel (this.extend (request, params)); } sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) { @@ -220,18 +221,24 @@ module.exports = class paymium extends Exchange { this.checkRequiredCredentials (); const nonce = this.nonce ().toString (); let auth = nonce + url; + headers = { + 'Api-Key': this.apiKey, + 'Api-Nonce': nonce, + }; if (method === 'POST') { if (Object.keys (query).length) { body = this.json (query); auth += body; + headers['Content-Type'] = 'application/json'; + } + } else { + if (Object.keys (query).length) { + const queryString = this.urlencode (query); + auth += queryString; + url += '?' + queryString; } } - headers = { - 'Api-Key': this.apiKey, - 'Api-Signature': this.hmac (this.encode (auth), this.encode (this.secret)), - 'Api-Nonce': nonce, - 'Content-Type': 'application/json', - }; + headers['Api-Signature'] = this.hmac (this.encode (auth), this.encode (this.secret)); } return { 'url': url, 'method': method, 'body': body, 'headers': headers }; } diff --git a/TaskServer/node_modules/ccxt/js/poloniex.js b/TaskServer/node_modules/ccxt/js/poloniex.js index fc389cd5e..ca6b4e842 100644 --- a/TaskServer/node_modules/ccxt/js/poloniex.js +++ b/TaskServer/node_modules/ccxt/js/poloniex.js @@ -3,7 +3,7 @@ // --------------------------------------------------------------------------- const Exchange = require ('./base/Exchange'); -const { ExchangeError, ExchangeNotAvailable, RequestTimeout, AuthenticationError, PermissionDenied, DDoSProtection, InsufficientFunds, OrderNotFound, OrderNotCached, InvalidOrder, AccountSuspended, CancelPending, InvalidNonce } = require ('./base/errors'); +const { ExchangeError, ExchangeNotAvailable, RequestTimeout, AuthenticationError, PermissionDenied, DDoSProtection, InsufficientFunds, OrderNotFound, OrderNotCached, InvalidOrder, AccountSuspended, CancelPending, InvalidNonce, OnMaintenance } = require ('./base/errors'); // --------------------------------------------------------------------------- @@ -170,6 +170,7 @@ module.exports = class poloniex extends Exchange { 'Permission denied': PermissionDenied, 'Connection timed out. Please try again.': RequestTimeout, 'Internal error. Please try again.': ExchangeNotAvailable, + 'Currently in maintenance mode.': OnMaintenance, 'Order not found, or you are not the person who placed it.': OrderNotFound, 'Invalid API key/secret pair.': AuthenticationError, 'Please do not make more than 8 API calls per second.': DDoSProtection, diff --git a/TaskServer/node_modules/ccxt/js/test/Exchange/test.fetchOHLCV.js b/TaskServer/node_modules/ccxt/js/test/Exchange/test.fetchOHLCV.js index a526fd72f..0ce38e977 100644 --- a/TaskServer/node_modules/ccxt/js/test/Exchange/test.fetchOHLCV.js +++ b/TaskServer/node_modules/ccxt/js/test/Exchange/test.fetchOHLCV.js @@ -17,7 +17,6 @@ module.exports = async (exchange, symbol) => { 'btcalpha', // issue with 404 on a documented endpoint https://travis-ci.org/ccxt/ccxt/builds/643930431#L2213 'bitmex', // an issue with null values,to be resolved later 'cex', - 'mandala', ] if (skippedExchanges.includes (exchange.id)) { diff --git a/TaskServer/node_modules/ccxt/js/test/Exchange/test.fetchOrderBooks.js b/TaskServer/node_modules/ccxt/js/test/Exchange/test.fetchOrderBooks.js index 718df81b3..871efde2c 100644 --- a/TaskServer/node_modules/ccxt/js/test/Exchange/test.fetchOrderBooks.js +++ b/TaskServer/node_modules/ccxt/js/test/Exchange/test.fetchOrderBooks.js @@ -13,7 +13,7 @@ const log = require ('ololog') module.exports = async (exchange) => { - const randomSymbols = exchange.symbols.sort (() => 0.5 - Math.random ()).slice (0, 2) + const randomSymbols = exchange.symbols.slice ().sort (() => 0.5 - Math.random ()).slice (0, 2) const customExchangeParams = ([ 'yobit', 'tidex', diff --git a/TaskServer/node_modules/ccxt/js/test/Exchange/test.fetchOrders.js b/TaskServer/node_modules/ccxt/js/test/Exchange/test.fetchOrders.js index aba8a1696..dd157c41f 100644 --- a/TaskServer/node_modules/ccxt/js/test/Exchange/test.fetchOrders.js +++ b/TaskServer/node_modules/ccxt/js/test/Exchange/test.fetchOrders.js @@ -14,7 +14,6 @@ const log = require ('ololog') module.exports = async (exchange, symbol) => { const skippedExchanges = [ - 'mandala', 'rightbtc', ] diff --git a/TaskServer/node_modules/ccxt/js/test/Exchange/test.ticker.js b/TaskServer/node_modules/ccxt/js/test/Exchange/test.ticker.js index 9601714f6..960794026 100644 --- a/TaskServer/node_modules/ccxt/js/test/Exchange/test.ticker.js +++ b/TaskServer/node_modules/ccxt/js/test/Exchange/test.ticker.js @@ -76,7 +76,6 @@ module.exports = (exchange, ticker, method, symbol) => { 'xbtce', 'coss', 'idex', - 'mandala', 'mercado', 'okex', 'southxchange', // https://user-images.githubusercontent.com/1294454/59953532-314bea80-9489-11e9-85b3-2a711ca49aa7.png diff --git a/TaskServer/node_modules/ccxt/js/test/base/functions/test.number.js b/TaskServer/node_modules/ccxt/js/test/base/functions/test.number.js index e4b9a6b00..1d5adce06 100644 --- a/TaskServer/node_modules/ccxt/js/test/base/functions/test.number.js +++ b/TaskServer/node_modules/ccxt/js/test/base/functions/test.number.js @@ -25,6 +25,8 @@ assert (toWei ('0.001', 18) === '1000000000000000'); assert (toWei (0.1, 18) === '100000000000000000'); assert (toWei (0.01, 18) === '10000000000000000'); assert (toWei (0.001, 18) === '1000000000000000'); +assert (toWei ('0.3323340739', 18) === '332334073900000000'); +assert (toWei (0.3323340739, 18) === '332334073900000000'); // let us test that we get the inverse for all these test assert (fromWei ('1000000000000000000', 18) === 1.0); @@ -43,6 +45,8 @@ assert (fromWei ('1000000000000000', 18) === 0.001); assert (fromWei (100000000000000000, 18) === 0.1); assert (fromWei (10000000000000000, 18) === 0.01); assert (fromWei (1000000000000000, 18) === 0.001); +assert (fromWei ('332334073900000000', 18) === 0.3323340739); +assert (fromWei (332334073900000000, 18) === 0.3323340739); // ---------------------------------------------------------------------------- // numberToString @@ -58,6 +62,7 @@ assert (numberToString (7.9e27) === '7900000000000000000000000000'); assert (numberToString (-12.345) === '-12.345'); assert (numberToString (12.345) === '12.345'); assert (numberToString (0) === '0'); +assert (numberToString (7.35946e21) === '7359460000000000000000'); // the following line breaks the test // see https://github.com/ccxt/ccxt/issues/5744 // assert (numberToString (0.00000001) === '0.00000001'); diff --git a/TaskServer/node_modules/ccxt/js/test/test.js b/TaskServer/node_modules/ccxt/js/test/test.js index 665e1a228..322deed58 100644 --- a/TaskServer/node_modules/ccxt/js/test/test.js +++ b/TaskServer/node_modules/ccxt/js/test/test.js @@ -370,9 +370,12 @@ let tryAllProxies = async function (exchange, proxies) { ;(async function test () { if (exchangeSymbol) { + await loadExchange (exchange) await testSymbol (exchange, exchangeSymbol) + } else { + await tryAllProxies (exchange, proxies) } diff --git a/TaskServer/node_modules/ccxt/js/theocean.js b/TaskServer/node_modules/ccxt/js/theocean.js index 2fd3e1bd6..502aaedd5 100644 --- a/TaskServer/node_modules/ccxt/js/theocean.js +++ b/TaskServer/node_modules/ccxt/js/theocean.js @@ -180,6 +180,9 @@ module.exports = class theocean extends Exchange { } async fetchOHLCV (symbol, timeframe = '5m', since = undefined, limit = undefined, params = {}) { + if (since === undefined) { + throw new ArgumentsRequired (this.id + ' fetchOHLCV requires a since argument'); + } await this.loadMarkets (); const market = this.market (symbol); const request = { @@ -187,9 +190,6 @@ module.exports = class theocean extends Exchange { 'quoteTokenAddress': market['quoteId'], 'interval': this.timeframes[timeframe], }; - if (since === undefined) { - throw new ExchangeError (this.id + ' fetchOHLCV requires a since argument'); - } since = parseInt (since); request['startTime'] = since; const response = await this.publicGetCandlesticks (this.extend (request, params)); diff --git a/TaskServer/node_modules/ccxt/js/tidebit.js b/TaskServer/node_modules/ccxt/js/tidebit.js index 5d0f63e6b..7f3fe2605 100644 --- a/TaskServer/node_modules/ccxt/js/tidebit.js +++ b/TaskServer/node_modules/ccxt/js/tidebit.js @@ -3,7 +3,7 @@ // --------------------------------------------------------------------------- const Exchange = require ('./base/Exchange'); -const { ExchangeError, InsufficientFunds, OrderNotFound } = require ('./base/errors'); +const { ExchangeError, InsufficientFunds, OrderNotFound, ArgumentsRequired } = require ('./base/errors'); // --------------------------------------------------------------------------- @@ -460,7 +460,7 @@ module.exports = class tidebit extends Exchange { const currency = this.currency (code); const id = this.safeString (params, 'id'); if (id === undefined) { - throw new ExchangeError (this.id + ' withdraw() requires an extra `id` param (withdraw account id according to withdraws/bind_account_list endpoint'); + throw new ArgumentsRequired (this.id + ' withdraw() requires an extra `id` param (withdraw account id according to withdraws/bind_account_list endpoint'); } const request = { 'id': id, diff --git a/TaskServer/node_modules/ccxt/js/timex.js b/TaskServer/node_modules/ccxt/js/timex.js index 1c381f7cb..d772f12c3 100644 --- a/TaskServer/node_modules/ccxt/js/timex.js +++ b/TaskServer/node_modules/ccxt/js/timex.js @@ -42,6 +42,7 @@ module.exports = class timex extends Exchange { 'api': 'https://plasma-relay-backend.timex.io', 'www': 'https://timex.io', 'doc': 'https://docs.timex.io', + 'referral': 'https://timex.io/?refcode=1x27vNkTbP1uwkCck', }, 'api': { 'custody': { @@ -892,7 +893,21 @@ module.exports = class timex extends Exchange { // "active": true, // "withdrawalFee": "50000000000000000", // "purchaseCommissions": [] - // }, + // } + // + // https://github.com/ccxt/ccxt/issues/6878 + // + // { + // "symbol":"XRP", + // "name":"Ripple", + // "address":"0x0dc8882914f3ddeebf4cec6dc20edb99df3def6c", + // "decimals":6, + // "tradeDecimals":16, + // "depositEnabled":true, + // "withdrawalEnabled":true, + // "transferEnabled":true, + // "active":true + // } // const id = this.safeString (currency, 'symbol'); const code = this.safeCurrencyCode (id); @@ -901,20 +916,22 @@ module.exports = class timex extends Exchange { const active = this.safeValue (currency, 'active'); // const fee = this.safeFloat (currency, 'withdrawalFee'); const feeString = this.safeString (currency, 'withdrawalFee'); - const feeStringLen = feeString.length; const tradeDecimals = this.safeInteger (currency, 'tradeDecimals'); let fee = undefined; - const dotIndex = feeStringLen - tradeDecimals; - if (dotIndex > 0) { - const whole = feeString.slice (0, dotIndex); - const fraction = feeString.slice (-dotIndex); - fee = parseFloat (whole + '.' + fraction); - } else { - let fraction = '.'; - for (let i = 0; i < -dotIndex; i++) { - fraction += '0'; + if ((feeString !== undefined) && (tradeDecimals !== undefined)) { + const feeStringLen = feeString.length; + const dotIndex = feeStringLen - tradeDecimals; + if (dotIndex > 0) { + const whole = feeString.slice (0, dotIndex); + const fraction = feeString.slice (-dotIndex); + fee = parseFloat (whole + '.' + fraction); + } else { + let fraction = '.'; + for (let i = 0; i < -dotIndex; i++) { + fraction += '0'; + } + fee = parseFloat (fraction + feeString); } - fee = parseFloat (fraction + feeString); } return { 'id': code, @@ -1105,7 +1122,7 @@ module.exports = class timex extends Exchange { this.safeFloat (ohlcv, 'high'), this.safeFloat (ohlcv, 'low'), this.safeFloat (ohlcv, 'close'), - this.safeFloat (ohlcv, 'volumeQuote'), + this.safeFloat (ohlcv, 'volume'), ]; } diff --git a/TaskServer/node_modules/ccxt/js/upbit.js b/TaskServer/node_modules/ccxt/js/upbit.js index e34f8e651..8018766c0 100644 --- a/TaskServer/node_modules/ccxt/js/upbit.js +++ b/TaskServer/node_modules/ccxt/js/upbit.js @@ -1324,9 +1324,11 @@ module.exports = class upbit extends Exchange { } parseDepositAddresses (addresses) { - const result = []; + const result = {}; for (let i = 0; i < addresses.length; i++) { - result.push (this.parseDepositAddress (addresses[i])); + const address = this.parseDepositAddress (addresses[i]); + const code = address['currency']; + result[code] = address; } return result; } diff --git a/TaskServer/node_modules/ccxt/js/yobit.js b/TaskServer/node_modules/ccxt/js/yobit.js index 58e452423..58bc08f89 100644 --- a/TaskServer/node_modules/ccxt/js/yobit.js +++ b/TaskServer/node_modules/ccxt/js/yobit.js @@ -167,11 +167,12 @@ module.exports = class yobit extends Exchange { 'api key dont have trade permission': AuthenticationError, 'invalid parameter': InvalidOrder, 'invalid order': InvalidOrder, + 'The given order has already been cancelled': InvalidOrder, 'Requests too often': DDoSProtection, 'not available': ExchangeNotAvailable, 'data unavailable': ExchangeNotAvailable, 'external service unavailable': ExchangeNotAvailable, - 'Total transaction amount': ExchangeError, // { "success": 0, "error": "Total transaction amount is less than minimal total: 0.00010000"} + 'Total transaction amount': InvalidOrder, // { "success": 0, "error": "Total transaction amount is less than minimal total: 0.00010000"} 'Insufficient funds': InsufficientFunds, 'invalid key': AuthenticationError, 'invalid nonce': InvalidNonce, // {"success":0,"error":"invalid nonce (has already been used)"}' diff --git a/TaskServer/node_modules/ccxt/js/zb.js b/TaskServer/node_modules/ccxt/js/zb.js index f4807b607..f3cc69084 100644 --- a/TaskServer/node_modules/ccxt/js/zb.js +++ b/TaskServer/node_modules/ccxt/js/zb.js @@ -453,7 +453,7 @@ module.exports = class zb extends Exchange { async fetchOrders (symbol = undefined, since = undefined, limit = 50, params = {}) { if (symbol === undefined) { - throw new ExchangeError (this.id + 'fetchOrders requires a symbol parameter'); + throw new ArgumentsRequired (this.id + 'fetchOrders requires a symbol argument'); } await this.loadMarkets (); const market = this.market (symbol); @@ -481,7 +481,7 @@ module.exports = class zb extends Exchange { async fetchOpenOrders (symbol = undefined, since = undefined, limit = 10, params = {}) { if (symbol === undefined) { - throw new ExchangeError (this.id + 'fetchOpenOrders requires a symbol parameter'); + throw new ArgumentsRequired (this.id + 'fetchOpenOrders requires a symbol argument'); } await this.loadMarkets (); const market = this.market (symbol); diff --git a/TaskServer/node_modules/ccxt/package.json b/TaskServer/node_modules/ccxt/package.json index 953f8eb8b..01c9960d1 100644 --- a/TaskServer/node_modules/ccxt/package.json +++ b/TaskServer/node_modules/ccxt/package.json @@ -1,27 +1,26 @@ { - "_from": "ccxt@1.25.80", - "_id": "ccxt@1.25.80", + "_from": "ccxt@^1.25.80", + "_id": "ccxt@1.27.45", "_inBundle": false, - "_integrity": "sha512-AUWagxMa8PMexRabbktWezlmVacj6L2Ep4844ebIXUOyME2Ommg7O/9/pq0F2Ne1IHcJnNJzHrMYQvkh2gBtlw==", + "_integrity": "sha512-4ADlbcIWDzIWjtLvsrtux5jMFj7pU4kVuiqtI2Btq6NEhQ4r/4+LirXdEFlCF6/wIU3XSHabxMd/8nu8HC1KJw==", "_location": "/ccxt", "_phantomChildren": {}, "_requested": { - "type": "version", + "type": "range", "registry": true, - "raw": "ccxt@1.25.80", + "raw": "ccxt@^1.25.80", "name": "ccxt", "escapedName": "ccxt", - "rawSpec": "1.25.80", + "rawSpec": "^1.25.80", "saveSpec": null, - "fetchSpec": "1.25.80" + "fetchSpec": "^1.25.80" }, "_requiredBy": [ - "#USER", "/" ], - "_resolved": "https://registry.npmjs.org/ccxt/-/ccxt-1.25.80.tgz", - "_shasum": "aee14637402aecc53d8a7d78af78bb7d730c84d5", - "_spec": "ccxt@1.25.80", + "_resolved": "https://registry.npmjs.org/ccxt/-/ccxt-1.27.45.tgz", + "_shasum": "d4470a16dbff881da7fcccd38b0efa277f5a9c37", + "_spec": "ccxt@^1.25.80", "_where": "C:\\Users\\Luis\\source\\repos\\AAMasters\\TaskServer", "author": { "name": "Igor Kroitor", @@ -447,8 +446,6 @@ "Binance Jersey", "bequant.io", "Bequant", - "mandalaex.com", - "Mandala", "dx.exchange", "DX.Exchange", "oceanex.pro.com", @@ -491,7 +488,9 @@ "Bybit", "aofex.com", "AOFEX", - "byte-trade.com" + "byte-trade.com", + "hbtc.com", + "HBTC" ], "license": "MIT", "main": "./ccxt.js", @@ -539,5 +538,5 @@ }, "types": "./ccxt.d.ts", "unpkg": "dist/ccxt.browser.js", - "version": "1.25.80" + "version": "1.27.45" } diff --git a/TaskServer/node_modules/dotenv/package.json b/TaskServer/node_modules/dotenv/package.json index 40e1c3ed6..eeecadeb1 100644 --- a/TaskServer/node_modules/dotenv/package.json +++ b/TaskServer/node_modules/dotenv/package.json @@ -1,27 +1,26 @@ { - "_from": "dotenv@8.2.0", + "_from": "dotenv@^8.2.0", "_id": "dotenv@8.2.0", "_inBundle": false, "_integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==", "_location": "/dotenv", "_phantomChildren": {}, "_requested": { - "type": "version", + "type": "range", "registry": true, - "raw": "dotenv@8.2.0", + "raw": "dotenv@^8.2.0", "name": "dotenv", "escapedName": "dotenv", - "rawSpec": "8.2.0", + "rawSpec": "^8.2.0", "saveSpec": null, - "fetchSpec": "8.2.0" + "fetchSpec": "^8.2.0" }, "_requiredBy": [ - "#USER", "/" ], "_resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz", "_shasum": "97e619259ada750eea3e4ea3e26bceea5424b16a", - "_spec": "dotenv@8.2.0", + "_spec": "dotenv@^8.2.0", "_where": "C:\\Users\\Luis\\source\\repos\\AAMasters\\TaskServer", "bugs": { "url": "https://github.com/motdotla/dotenv/issues" diff --git a/TaskServer/node_modules/telegraf/context.js b/TaskServer/node_modules/telegraf/context.js index 9302d21b8..02f421079 100644 --- a/TaskServer/node_modules/telegraf/context.js +++ b/TaskServer/node_modules/telegraf/context.js @@ -330,6 +330,11 @@ class TelegrafContext { return this.telegram.kickChatMember(this.chat.id, ...args) } + unbanChatMember (...args) { + this.assert(this.chat, 'unbanChatMember') + return this.telegram.unbanChatMember(this.chat.id, ...args) + } + restrictChatMember (...args) { this.assert(this.chat, 'restrictChatMember') return this.telegram.restrictChatMember(this.chat.id, ...args) diff --git a/TaskServer/node_modules/telegraf/markup.js b/TaskServer/node_modules/telegraf/markup.js index 192d31fb9..ca0683c0c 100644 --- a/TaskServer/node_modules/telegraf/markup.js +++ b/TaskServer/node_modules/telegraf/markup.js @@ -164,15 +164,91 @@ class Markup { } static formatHTML (text = '', entities = []) { - const chars = ['', ...text.split(''), ''].map(escapeHTMLChar) - entities.forEach(entity => { - const tag = getHTMLTag(entity) - const openPos = entity.offset - const closePos = entity.offset + entity.length + 1 - chars[openPos] += tag.open - chars[closePos] = tag.close + chars[closePos] - }) - return chars.join('') + const chars = [...text] + const available = [...entities] + const opened = [] + const result = [] + for (let offset = 0; offset < chars.length; offset++) { + while (true) { + const index = available.findIndex((entity) => entity.offset === offset) + if (index === -1) { + break + } + const entity = available[index] + switch (entity.type) { + case 'bold': + result.push('') + break + case 'italic': + result.push('') + break + case 'code': + result.push('') + break + case 'pre': + if (entity.language) { + result.push(`
`)
+            } else {
+              result.push('
')
+            }
+            break
+          case 'strikethrough':
+            result.push('')
+            break
+          case 'underline':
+            result.push('')
+            break
+          case 'text_mention':
+            result.push(``)
+            break
+          case 'text_link':
+            result.push(``)
+            break
+        }
+        opened.unshift(entity)
+        available.splice(index, 1)
+      }
+
+      result.push(chars[offset])
+
+      while (true) {
+        const index = opened.findIndex((entity) => entity.offset + entity.length - 1 === offset)
+        if (index === -1) {
+          break
+        }
+        const entity = opened[index]
+        switch (entity.type) {
+          case 'bold':
+            result.push('')
+            break
+          case 'italic':
+            result.push('')
+            break
+          case 'code':
+            result.push('')
+            break
+          case 'pre':
+            if (entity.language) {
+              result.push('
') + } else { + result.push('
') + } + break + case 'strikethrough': + result.push('') + break + case 'underline': + result.push('') + break + case 'text_mention': + case 'text_link': + result.push('') + break + } + opened.splice(index, 1) + } + } + return result.join('') } } @@ -203,40 +279,4 @@ function buildKeyboard (buttons, options) { return result } -function escapeHTMLChar (c) { - switch (c) { - case '&': return '&' - case '"': return '"' - case '\'': return ''' - case '<': return '<' - default : return c - } -} - -function tag (name, params) { - return { - open: params - ? `<${name} ${Object.entries(params).map(([key, value]) => `${key}="${value.replace(/[<&"]/g, escapeHTMLChar)}"`).join(' ')}>` - : `<${name}>`, - close: `` - } -} - -const HTMLTags = new Map([ - ['bold', tag('b')], - ['italic', tag('i')], - ['code', tag('code')], - ['pre', tag('pre')], - ['strikethrough', tag('s')], - ['underline', tag('u')], - ['text_link', ({ url }) => tag('a', { href: url })], - ['text_mention', ({ user }) => tag('a', { href: `tg://user?id=${user.id}` })] -]) - -function getHTMLTag (entity) { - const tag = HTMLTags.get(entity.type || 'unknown') - if (!tag) return { open: '', close: '' } - return typeof tag === 'function' ? tag(entity) : tag -} - module.exports = Markup diff --git a/TaskServer/node_modules/telegraf/package.json b/TaskServer/node_modules/telegraf/package.json index 040c02569..ee36d765c 100644 --- a/TaskServer/node_modules/telegraf/package.json +++ b/TaskServer/node_modules/telegraf/package.json @@ -1,34 +1,33 @@ { - "_from": "telegraf@3.37.0", - "_id": "telegraf@3.37.0", + "_from": "telegraf@^3.37.0", + "_id": "telegraf@3.38.0", "_inBundle": false, - "_integrity": "sha512-V3448qwfOolBqkIc87yxjW4zMvR2P6AIF24pPTlX9WhZPwA1TF/x3nQhnWPRLtGh2SJuvDcr83iTkXPXT7Opnw==", + "_integrity": "sha512-va4VlrKWp64JrowFoZX/NPzzA6q38kvaIukVXOWFO1V+jR1G8+hCfgJy4TX8Z3rwLJzwaBEet1QhikHDRZWl3A==", "_location": "/telegraf", "_phantomChildren": {}, "_requested": { - "type": "version", + "type": "range", "registry": true, - "raw": "telegraf@3.37.0", + "raw": "telegraf@^3.37.0", "name": "telegraf", "escapedName": "telegraf", - "rawSpec": "3.37.0", + "rawSpec": "^3.37.0", "saveSpec": null, - "fetchSpec": "3.37.0" + "fetchSpec": "^3.37.0" }, "_requiredBy": [ - "#USER", "/" ], - "_resolved": "https://registry.npmjs.org/telegraf/-/telegraf-3.37.0.tgz", - "_shasum": "f88ae3d4bddac6f479137d4c867489acf3f57b66", - "_spec": "telegraf@3.37.0", + "_resolved": "https://registry.npmjs.org/telegraf/-/telegraf-3.38.0.tgz", + "_shasum": "745b447547a8e6cdb626055e4d616058aaae0759", + "_spec": "telegraf@^3.37.0", "_where": "C:\\Users\\Luis\\source\\repos\\AAMasters\\TaskServer", "author": { "name": "Vitaly Domnikov", "email": "oss@vitaly.codes" }, "bin": { - "telegraf": "bin/telegraf" + "telegraf": "./bin/telegraf" }, "bugs": { "url": "https://github.com/telegraf/telegraf/issues" @@ -55,6 +54,7 @@ "eslint-plugin-promise": "^4.0.0", "eslint-plugin-standard": "^4.0.0", "husky": "^4.2.0", + "prettier": "^2.0.5", "typescript": "^3.0.1" }, "engines": { @@ -91,5 +91,5 @@ }, "type": "commonjs", "types": "./typings/index.d.ts", - "version": "3.37.0" + "version": "3.38.0" } diff --git a/TaskServer/node_modules/telegraf/telegraf.js b/TaskServer/node_modules/telegraf/telegraf.js index 15c3b0fb6..23e228eea 100644 --- a/TaskServer/node_modules/telegraf/telegraf.js +++ b/TaskServer/node_modules/telegraf/telegraf.js @@ -213,6 +213,7 @@ module.exports = Object.assign(Telegraf, { Extra, Markup, Router, + Telegraf, Telegram, Stage, BaseScene, diff --git a/TaskServer/node_modules/ws/lib/buffer-util.js b/TaskServer/node_modules/ws/lib/buffer-util.js index 3648638b0..6fd84c311 100644 --- a/TaskServer/node_modules/ws/lib/buffer-util.js +++ b/TaskServer/node_modules/ws/lib/buffer-util.js @@ -92,7 +92,7 @@ function toBuffer(data) { if (data instanceof ArrayBuffer) { buf = Buffer.from(data); } else if (ArrayBuffer.isView(data)) { - buf = viewToBuffer(data); + buf = Buffer.from(data.buffer, data.byteOffset, data.byteLength); } else { buf = Buffer.from(data); toBuffer.readOnly = false; @@ -101,23 +101,6 @@ function toBuffer(data) { return buf; } -/** - * Converts an `ArrayBuffer` view into a buffer. - * - * @param {(DataView|TypedArray)} view The view to convert - * @return {Buffer} Converted view - * @private - */ -function viewToBuffer(view) { - const buf = Buffer.from(view.buffer); - - if (view.byteLength !== view.buffer.byteLength) { - return buf.slice(view.byteOffset, view.byteOffset + view.byteLength); - } - - return buf; -} - try { const bufferUtil = require('bufferutil'); const bu = bufferUtil.BufferUtil || bufferUtil; diff --git a/TaskServer/node_modules/ws/lib/event-target.js b/TaskServer/node_modules/ws/lib/event-target.js index c060d63a8..d38e1f2d7 100644 --- a/TaskServer/node_modules/ws/lib/event-target.js +++ b/TaskServer/node_modules/ws/lib/event-target.js @@ -109,11 +109,16 @@ const EventTarget = { /** * Register an event listener. * - * @param {String} method A string representing the event type to listen for + * @param {String} type A string representing the event type to listen for * @param {Function} listener The listener to add + * @param {Object} options An options object specifies characteristics about + * the event listener + * @param {Boolean} options.once A `Boolean`` indicating that the listener + * should be invoked at most once after being added. If `true`, the + * listener would be automatically removed when invoked. * @public */ - addEventListener(method, listener) { + addEventListener(type, listener, options) { if (typeof listener !== 'function') return; function onMessage(data) { @@ -132,36 +137,38 @@ const EventTarget = { listener.call(this, new OpenEvent(this)); } - if (method === 'message') { + const method = options && options.once ? 'once' : 'on'; + + if (type === 'message') { onMessage._listener = listener; - this.on(method, onMessage); - } else if (method === 'close') { + this[method](type, onMessage); + } else if (type === 'close') { onClose._listener = listener; - this.on(method, onClose); - } else if (method === 'error') { + this[method](type, onClose); + } else if (type === 'error') { onError._listener = listener; - this.on(method, onError); - } else if (method === 'open') { + this[method](type, onError); + } else if (type === 'open') { onOpen._listener = listener; - this.on(method, onOpen); + this[method](type, onOpen); } else { - this.on(method, listener); + this[method](type, listener); } }, /** * Remove an event listener. * - * @param {String} method A string representing the event type to remove + * @param {String} type A string representing the event type to remove * @param {Function} listener The listener to remove * @public */ - removeEventListener(method, listener) { - const listeners = this.listeners(method); + removeEventListener(type, listener) { + const listeners = this.listeners(type); for (let i = 0; i < listeners.length; i++) { if (listeners[i] === listener || listeners[i]._listener === listener) { - this.removeListener(method, listeners[i]); + this.removeListener(type, listeners[i]); } } } diff --git a/TaskServer/node_modules/ws/lib/stream.js b/TaskServer/node_modules/ws/lib/stream.js index c6811afb1..f8d410eba 100644 --- a/TaskServer/node_modules/ws/lib/stream.js +++ b/TaskServer/node_modules/ws/lib/stream.js @@ -125,8 +125,8 @@ function createWebSocketStream(ws, options) { if (ws._socket === null) return; if (ws._socket._writableState.finished) { - if (duplex._readableState.endEmitted) duplex.destroy(); callback(); + if (duplex._readableState.endEmitted) duplex.destroy(); } else { ws._socket.once('finish', function finish() { // `duplex` is not destroyed here because the `'end'` event will be diff --git a/TaskServer/node_modules/ws/lib/websocket-server.js b/TaskServer/node_modules/ws/lib/websocket-server.js index 057a12be5..0d3f39592 100644 --- a/TaskServer/node_modules/ws/lib/websocket-server.js +++ b/TaskServer/node_modules/ws/lib/websocket-server.js @@ -7,10 +7,9 @@ const { createServer, STATUS_CODES } = require('http'); const PerMessageDeflate = require('./permessage-deflate'); const WebSocket = require('./websocket'); const { format, parse } = require('./extension'); -const { GUID } = require('./constants'); +const { GUID, kWebSocket } = require('./constants'); const keyRegex = /^[+/0-9A-Za-z]{22}==$/; -const kUsedByWebSocketServer = Symbol('kUsedByWebSocketServer'); /** * Class representing a WebSocket server. @@ -79,13 +78,6 @@ class WebSocketServer extends EventEmitter { callback ); } else if (options.server) { - if (options.server[kUsedByWebSocketServer]) { - throw new Error( - 'The HTTP/S server is already being used by another WebSocket server' - ); - } - - options.server[kUsedByWebSocketServer] = true; this._server = options.server; } @@ -153,8 +145,6 @@ class WebSocketServer extends EventEmitter { server.close(() => this.emit('close')); return; } - - delete server[kUsedByWebSocketServer]; } process.nextTick(emitClose, this); @@ -264,6 +254,7 @@ class WebSocketServer extends EventEmitter { * @param {net.Socket} socket The network socket between the server and client * @param {Buffer} head The first packet of the upgraded stream * @param {Function} cb Callback + * @throws {Error} If called more than once with the same socket * @private */ completeUpgrade(key, extensions, req, socket, head, cb) { @@ -272,6 +263,13 @@ class WebSocketServer extends EventEmitter { // if (!socket.readable || !socket.writable) return socket.destroy(); + if (socket[kWebSocket]) { + throw new Error( + 'server.handleUpgrade() was called more than once with the same ' + + 'socket, possibly due to a misconfiguration' + ); + } + const digest = createHash('sha1') .update(key + GUID) .digest('base64'); @@ -386,7 +384,7 @@ function abortHandshake(socket, code, message, headers) { message = message || STATUS_CODES[code]; headers = { Connection: 'close', - 'Content-type': 'text/html', + 'Content-Type': 'text/html', 'Content-Length': Buffer.byteLength(message), ...headers }; diff --git a/TaskServer/node_modules/ws/lib/websocket.js b/TaskServer/node_modules/ws/lib/websocket.js index ca72ad76d..3e8e4afd7 100644 --- a/TaskServer/node_modules/ws/lib/websocket.js +++ b/TaskServer/node_modules/ws/lib/websocket.js @@ -456,7 +456,6 @@ function initAsClient(websocket, address, protocols, options) { protocol: undefined, timeout: undefined, method: undefined, - auth: undefined, host: undefined, path: undefined, port: undefined diff --git a/TaskServer/node_modules/ws/package.json b/TaskServer/node_modules/ws/package.json index a6a75bdf9..df2515568 100644 --- a/TaskServer/node_modules/ws/package.json +++ b/TaskServer/node_modules/ws/package.json @@ -1,52 +1,38 @@ { - "_args": [ - [ - "ws@^7.1.2", - "C:\\Users\\Luis\\source\\repos\\AAMasters\\TaskServer" - ] - ], - "_from": "ws@>=7.1.2-0 <8.0.0-0", - "_hasShrinkwrap": false, - "_id": "ws@7.2.3", - "_inCache": true, + "_from": "ws@^7.1.2", + "_id": "ws@7.3.0", + "_inBundle": false, + "_integrity": "sha512-iFtXzngZVXPGgpTlP1rBqsUK82p9tKqsWRPg5L56egiljujJT3vGAYnHANvFxBieXrTFavhzhxW52jnaWV+w2w==", "_location": "/ws", - "_nodeVersion": "13.10.1", - "_npmOperationalInternal": { - "host": "s3://npm-registry-packages", - "tmp": "tmp/ws_7.2.3_1583774852485_0.5683086237203219" - }, - "_npmUser": { - "email": "luigipinca@gmail.com", - "name": "lpinca" - }, - "_npmVersion": "6.13.7", "_phantomChildren": {}, "_requested": { - "name": "ws", + "type": "range", + "registry": true, "raw": "ws@^7.1.2", + "name": "ws", + "escapedName": "ws", "rawSpec": "^7.1.2", - "scope": null, - "spec": ">=7.1.2-0 <8.0.0-0", - "type": "range" + "saveSpec": null, + "fetchSpec": "^7.1.2" }, "_requiredBy": [ "/" ], - "_resolved": "https://registry.npmjs.org/ws/-/ws-7.2.3.tgz", - "_shasum": "a5411e1fb04d5ed0efee76d26d5c46d830c39b46", - "_shrinkwrap": null, + "_resolved": "https://registry.npmjs.org/ws/-/ws-7.3.0.tgz", + "_shasum": "4b2f7f219b3d3737bc1a2fbf145d825b94d38ffd", "_spec": "ws@^7.1.2", "_where": "C:\\Users\\Luis\\source\\repos\\AAMasters\\TaskServer", "author": { - "email": "einaros@gmail.com", "name": "Einar Otto Stangvik", + "email": "einaros@gmail.com", "url": "http://2x.io" }, "browser": "browser.js", "bugs": { "url": "https://github.com/websockets/ws/issues" }, - "dependencies": {}, + "bundleDependencies": false, + "deprecated": false, "description": "Simple to use, blazing fast and thoroughly tested websocket client and server for Node.js", "devDependencies": { "benchmark": "^2.1.4", @@ -60,19 +46,14 @@ "prettier": "^1.17.0", "utf-8-validate": "^5.0.2" }, - "directories": {}, - "dist": { - "fileCount": 17, - "integrity": "sha512-HTDl9G9hbkNDk98naoR/cHDws7+EyYMOdL1BmjsZXRUjf7d+MficC4B7HLUPlSiho0vg+CWKrGIt/VJBd1xunQ==", - "npm-signature": "-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeZnyFCRA9TVsSAnZWagAAUvwP/jAz5ASUvvHJjDMOS+r/\npDkuV2MoMwz6ccV+qfbVRWUKq9DqnK7bZBApyNlzV2I+APDqLOVU+2BazNKh\nqoTcVHYcBYe5oBIYUvEeSK2qyBCNJUcz2f79lVxWagdcax5nl5tOcW3B8v4X\n9T2hSvSuDNz8vg0uhCnLboZ+F4SPXd3lHwwfcZFkNSjTcRog4W4QNQTEaPbi\noqPawUw/NXDJMFILS2m/rerFnEyrDl4VpoAS9GyitCE31g22N03bCbsmaUMo\nHmFmefATEhmtIExXMDW9JGLL9FtTwVEIAJEfAWqjLt3JeAuWHvYKKd7rU/y1\nwPUQJxwGM1HDYaxbDLXRBVYkOja3YHB5txB8d2lHLt98c5DQ/lZCz1XQIRao\nPv48dpOX2Qg69IpMzSHktoRUJpt+0KkLWUhb7XGVY79kCgqt6ZqYxBs7coae\nOeReUBaKc+yuM3k45sHxyqiKCsw/qejgzScPnmU/BaC32vEdjqpysRNDtfZj\nNmizo+cLoiO8stLVCHGBwpIxegM8aGj3/C8emNEsSFi4rXT6LGHaWvNfv3FR\nVY2/4QZFL/ddUQ3yAOKF4znsHBY2qfbpPJVnW7IyxZ2h39HX3PpITCcYDPzu\nj4LV/wXFESBSre9RANqfPfkJC+A3k0V8eAB0bYQJKImeUAiqkOkYMyrX+2Ea\nHUeL\r\n=aUaH\r\n-----END PGP SIGNATURE-----\r\n", - "shasum": "a5411e1fb04d5ed0efee76d26d5c46d830c39b46", - "tarball": "https://registry.npmjs.org/ws/-/ws-7.2.3.tgz", - "unpackedSize": 109814 - }, "engines": { "node": ">=8.3.0" }, - "gitHead": "5fcdc42ef76d2d0ab920aa37631468e6f1066bcd", + "files": [ + "browser.js", + "index.js", + "lib/*.js" + ], "greenkeeper": { "commitMessages": { "dependencyUpdate": "[pkg] Update ${dependency} to version ${version}", @@ -80,7 +61,6 @@ } }, "homepage": "https://github.com/websockets/ws", - "installable": true, "keywords": [ "HyBi", "Push", @@ -91,26 +71,7 @@ ], "license": "MIT", "main": "index.js", - "maintainers": [ - { - "email": "npm@3rd-Eden.com", - "name": "3rdeden" - }, - { - "email": "einaros@gmail.com", - "name": "einaros" - }, - { - "email": "luigipinca@gmail.com", - "name": "lpinca" - }, - { - "email": "npm@3rd-Eden.com", - "name": "v1" - } - ], "name": "ws", - "optionalDependencies": {}, "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": "^5.0.2" @@ -132,5 +93,5 @@ "lint": "eslint --ignore-path .gitignore . && prettier --check --ignore-path .gitignore \"**/*.{json,md,yaml,yml}\"", "test": "npm run lint && nyc --reporter=html --reporter=text mocha --throw-deprecation test/*.test.js" }, - "version": "7.2.3" + "version": "7.3.0" } diff --git a/TaskServer/package-lock.json b/TaskServer/package-lock.json index 9da031d46..fc670f1b4 100644 --- a/TaskServer/package-lock.json +++ b/TaskServer/package-lock.json @@ -5,9 +5,9 @@ "requires": true, "dependencies": { "ccxt": { - "version": "1.25.80", - "resolved": "https://registry.npmjs.org/ccxt/-/ccxt-1.25.80.tgz", - "integrity": "sha512-AUWagxMa8PMexRabbktWezlmVacj6L2Ep4844ebIXUOyME2Ommg7O/9/pq0F2Ne1IHcJnNJzHrMYQvkh2gBtlw==" + "version": "1.27.45", + "resolved": "https://registry.npmjs.org/ccxt/-/ccxt-1.27.45.tgz", + "integrity": "sha512-4ADlbcIWDzIWjtLvsrtux5jMFj7pU4kVuiqtI2Btq6NEhQ4r/4+LirXdEFlCF6/wIU3XSHabxMd/8nu8HC1KJw==" }, "debug": { "version": "4.1.1", @@ -48,9 +48,9 @@ "integrity": "sha512-jLYV0DORrzY3xaz/S9ydJL6Iz7essZeAfnAavsJ+zsJGZ1MOnsS52yRjU3uF3pJa/lla7+wisp//fxOwOH8SKQ==" }, "telegraf": { - "version": "3.37.0", - "resolved": "https://registry.npmjs.org/telegraf/-/telegraf-3.37.0.tgz", - "integrity": "sha512-V3448qwfOolBqkIc87yxjW4zMvR2P6AIF24pPTlX9WhZPwA1TF/x3nQhnWPRLtGh2SJuvDcr83iTkXPXT7Opnw==", + "version": "3.38.0", + "resolved": "https://registry.npmjs.org/telegraf/-/telegraf-3.38.0.tgz", + "integrity": "sha512-va4VlrKWp64JrowFoZX/NPzzA6q38kvaIukVXOWFO1V+jR1G8+hCfgJy4TX8Z3rwLJzwaBEet1QhikHDRZWl3A==", "requires": { "debug": "4.1.1", "minimist": "1.2.5", @@ -66,9 +66,9 @@ "integrity": "sha512-njVv1EAhIZnmQVLocZEADYUyqA1WIXuVcDYlsp+mXua/XB0pxx+PKtMSPeZ/EE4wPWTw9h/hA9ASTT6yQelkiw==" }, "ws": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.2.3.tgz", - "integrity": "sha512-HTDl9G9hbkNDk98naoR/cHDws7+EyYMOdL1BmjsZXRUjf7d+MficC4B7HLUPlSiho0vg+CWKrGIt/VJBd1xunQ==" + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.3.0.tgz", + "integrity": "sha512-iFtXzngZVXPGgpTlP1rBqsUK82p9tKqsWRPg5L56egiljujJT3vGAYnHANvFxBieXrTFavhzhxW52jnaWV+w2w==" } } }