diff --git a/Exchange/ExchangeAPI.js b/Exchange/ExchangeAPI.js new file mode 100644 index 000000000..2ad5eddfd --- /dev/null +++ b/Exchange/ExchangeAPI.js @@ -0,0 +1,301 @@ +exports.newExchangeAPI = function newExchangeAPI(bot, logger) { + + /* + + This module allows trading bots to connect to the exchange and do trading operations on it. So far it can only work with Poloniex. + + */ + const _ = require('lodash') + const isValidOrder = require('./exchangeUtils').isValidOrder + const graphqlClient = require('graphql-client') + const appRoot = require('app-root-path') + const auth = require(`${appRoot}/utils/auth`) + + let MODULE_NAME = "Exchange API"; + + let thisObject = { + initialize: initialize, + getTicker: getTicker, + getOpenPositions: getOpenPositions, + getExecutedTrades: getExecutedTrades, + putPosition: putPosition, + movePosition: movePosition, + getPublicTradeHistory: getPublicTradeHistory, + getExchangeProperties: getExchangeProperties, + getMaxDecimalPositions: getMaxDecimalPositions + }; + + let apiClient; + + return thisObject; + + async function initialize(callBackFunction) { + try { + + if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] initialize -> Entering function."); } + + // TODO integrate with financial beings module to get the exchange + let botExchange = 'Poloniex'; + let exchange = botExchange.toLowerCase() + 'Client.js'; + let api = require('./wrappers/' + exchange); + + const accessToken = await auth.authenticate() + + let keyVaultAPI = createKeyVaultAPIClient(accessToken) + apiClient = api.newAPIClient(keyVaultAPI, logger); + + callBackFunction(global.DEFAULT_OK_RESPONSE); + + } catch (err) { + logger.write(MODULE_NAME, "[ERROR] initialize -> err = " + err.stack); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + function createKeyVaultAPIClient(authToken) { + if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] createKeyVaultAPIClient -> Entering function."); } + + const keyVaultAPI = graphqlClient({ + url: global.GATEWAY_ENDPOINT, + headers: { + Authorization: 'Bearer ' + authToken + } + }); + + keyVaultAPI.signTransaction = function (transaction, next) { + let variables = { + botId: bot.codeName, + transaction: transaction + } + + keyVaultAPI.query(` + mutation($botId: String, $transaction: String!){ + keyVault_SignTransaction(botId: $botId, transaction: $transaction){ + key, + signature, + date + } + }`, variables, function (req, res) { + if (res.status === 401) { + next(undefined, 'Error from graphql: Not authorized'); + } + }).then(res => { + if (res.errors) { + next(undefined, 'Error from graphql: ' + res.errors); + } else { + let signature = { + Key: res.data.keyVault_SignTransaction.key, + Sign: res.data.keyVault_SignTransaction.signature + } + next(signature) + } + }).catch(error => { + next(undefined, 'Error signing the message on the key vault: ' + error.message); + }); + } + + if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] createKeyVaultAPIClient -> Returning graphql client."); } + + return keyVaultAPI; + } + + /* + * Position Object = { + * id, String + * type, String + * rate, Number + * amountA, Number + * amountB, Number + * fee, Number + * datetime Date + * }; + */ + function truncDecimals(pFloatValue) { + let decimals = getMaxDecimalPositions(); + return parseFloat(parseFloat(pFloatValue).toFixed(decimals)); + } + + /* + * Return number of decimals for the current market + */ + function getMaxDecimalPositions() { + return getMarketConfig().maxDecimals; + } + + /* + * Return number of decimals for the current market + */ + function getMarketConfig() { + return _.find(getExchangeProperties().markets, (p) => { + return _.first(p.pair) === global.MARKET.assetA.toUpperCase() && + _.last(p.pair) === global.MARKET.assetB.toUpperCase(); + }); + } + + /* + * Return number of decimals for the current market + */ + function getExchangeProperties() { + try { + + if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] getExchangeProperties -> Entering function."); } + + return apiClient.getExchangeProperties(); + + } catch (err) { + logger.write(MODULE_NAME, "[ERROR] getExchangeProperties -> err = " + err.message); + callBack(global.DEFAULT_FAIL_RESPONSE); + } + } + + /* + * Returns the price for a given pair of assets. + * The object returned is an array of trades: + * ticker = { + * bid, Number + * ask, Number + * last Number + * }; + */ + function getTicker(pMarket, callBack) { + try { + + if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] getTicker -> Entering function."); } + + apiClient.getTicker(pMarket, callBack); + + } catch (err) { + logger.write(MODULE_NAME, "[ERROR] getTicker -> err = " + err.message); + callBack(global.DEFAULT_FAIL_RESPONSE); + } + } + + /* + * Returns the open positions ath the exchange for a given market and user account. + * The object returned is an array of positions + * + */ + function getOpenPositions(pMarket, callBack) { + try { + + if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] getOpenPositions -> Entering function."); } + if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] getOpenPositions -> pMarket = " + JSON.stringify(pMarket)); } + + apiClient.getOpenPositions(pMarket, callBack); + + } catch (err) { + logger.write(MODULE_NAME, "[ERROR] getOpenPositions -> Error = " + err.message); + callBack(global.DEFAULT_FAIL_RESPONSE); + } + } + + /* + * Returns the trades for a given order number. + * The object returned is an array of positions + */ + function getExecutedTrades(pPositionId, callBack) { + try { + + if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] getExecutedTrades -> Entering function."); } + if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] getExecutedTrades -> pPositionId = " + pPositionId); } + + apiClient.getExecutedTrades(pPositionId, callBack); + + } catch (err) { + logger.write(MODULE_NAME, "[ERROR] getExecutedTrades -> Error = " + err.message); + callBack(global.DEFAULT_FAIL_RESPONSE); + } + } + + /* + * Creates a new buy or sell order. + * The orderNumber is returned. String + */ + function putPosition(pMarket, pType, pRate, pAmountA, pAmountB, callBack) { + try { + + if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] putPosition -> Entering function."); } + if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] putPosition -> pMarket = " + JSON.stringify(pMarket)); } + if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] putPosition -> pType = " + pType); } + if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] putPosition -> pRate = " + truncDecimals(pRate)); } + if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] putPosition -> pAmountA = " + truncDecimals(pAmountA)); } + if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] putPosition -> pAmountB = " + truncDecimals(pAmountB)); } + + let check = isValidOrder({ + market: getMarketConfig(), + api: apiClient, + amount: truncDecimals(pAmountB), + price: truncDecimals(pRate) + }); + + if (check.valid) { + if (pType === "buy") { + apiClient.buy(pMarket.assetA, pMarket.assetB, truncDecimals(pRate), truncDecimals(pAmountB), callBack); + return; + } + + if (pType === "sell") { + apiClient.sell(pMarket.assetA, pMarket.assetB, truncDecimals(pRate), truncDecimals(pAmountB), callBack); + return; + } + + logger.write(MODULE_NAME, "[ERROR] putPosition -> pType must be either 'buy' or 'sell'."); + callBack(global.DEFAULT_FAIL_RESPONSE); + + } else { + logger.write(MODULE_NAME, "[ERROR] putPosition -> The order is invalid: " + check.reason); + callBack(global.DEFAULT_FAIL_RESPONSE); + } + + } catch (err) { + logger.write(MODULE_NAME, "[ERROR] putPosition -> err = " + err.message); + callBack(global.DEFAULT_FAIL_RESPONSE); + } + } + + /* + * Move an existing position to the new rate. + * The new orderNumber is returned. + */ + function movePosition(pPosition, pNewRate, pNewAmountB, callBack) { + try { + + if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] movePosition -> Entering function."); } + if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] movePosition -> pPosition = " + JSON.stringify(pPosition)); } + if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] movePosition -> pNewRate = " + truncDecimals(pNewRate)); } + + apiClient.movePosition(pPosition, truncDecimals(pNewRate), truncDecimals(pNewAmountB), callBack); + + } catch (err) { + logger.write(MODULE_NAME, "[ERROR] movePosition -> err = " + err.message); + callBack(global.DEFAULT_FAIL_RESPONSE); + } + } + + /* + * Returns all the trade history from the Exchange since startTime to endTime orderd by tradeId. + * It's possible that the exchange doesn't support this method. + * The object returned is an array of trades: + * trade = { + * tradeID, String + * globalTradeID, String + * type, String + * rate, Number + * amountA, Number + * amountB, Number + * date Date + * }; + */ + function getPublicTradeHistory(assetA, assetB, startTime, endTime, callBack) { + try { + + if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] getTradeHistory -> Entering function."); } + + apiClient.getPublicTradeHistory(assetA, assetB, startTime, endTime, callBack); + + } catch (err) { + logger.write(MODULE_NAME, "[ERROR] getTradeHistory -> err = " + err.message); + callBack(global.DEFAULT_FAIL_RESPONSE); + } + } +}; diff --git a/Exchange/exchangeUtils.js b/Exchange/exchangeUtils.js new file mode 100644 index 000000000..853d6d825 --- /dev/null +++ b/Exchange/exchangeUtils.js @@ -0,0 +1,100 @@ +// generic low level reusuable utils for interacting with exchanges. + +const retry = require('retry'); +const _ = require('lodash'); + +const retryInstance = (options, checkFn, callback) => { + if(!options) { + options = { + retries: 100, + factor: 1.2, + minTimeout: 1 * 1000, + maxTimeout: 4 * 1000 + }; + } + + let attempt = 0; + + const operation = retry.operation(options); + operation.attempt(function(currentAttempt) { + checkFn((err, result) => { + if (!err) { + return callback(global.DEFAULT_OK_RESPONSE, result); + } else { + if (err.result === global.CUSTOM_OK_RESPONSE.result) { + return callback(err, result); + } + } + + let maxAttempts = err.retry; + if(maxAttempts === true) + maxAttempts = 10; + + if(err.retry && attempt++ < maxAttempts) { + return operation.retry(err); + } + + if(err.notFatal) { + if(err.backoffDelay) { + return setTimeout(() => operation.retry(err), err.backoffDelay); + } + + return operation.retry(err); + } + + callback(err, result); + }); + }); +} + +const isValidOrder = ({api, market, amount, price}) => { + let reason = false; + + // Check amount + if(amount < market.minimalOrder.amount) { + reason = 'Amount is too small'; + } + + // Some exchanges have restrictions on prices + if( + _.isFunction(api.isValidPrice) && + !api.isValidPrice(price) + ) { + reason = 'Price is not valid'; + } + + if( + _.isFunction(api.isValidLot) && + !api.isValidLot(price, amount) + ) { + reason = 'Lot size is too small'; + } + + return { + reason, + valid: !reason + } +} + +const includes = function(str, list) { + if (!_.isString(str)) + return false; + + return _.some(list, item => str.includes(item)); +} + + +const getMarketConfig = function(exchangeProperties) { + return _.find(exchangeProperties.markets, (p) => { + return _.first(p.pair) === global.MARKET.assetA.toUpperCase() && + _.last(p.pair) === global.MARKET.assetB.toUpperCase(); + }); +} + +module.exports = { + retry: retryInstance, + includes: includes, + isValidOrder, + getMarketConfig + +} \ No newline at end of file diff --git a/Exchange/wrappers/beautifier.js b/Exchange/wrappers/beautifier.js new file mode 100644 index 000000000..5e5e6a051 --- /dev/null +++ b/Exchange/wrappers/beautifier.js @@ -0,0 +1,183 @@ +const _ = require('underscore'); + +class Beautifier { + + constructor() { + this._beautifications = { + aggTrades: { + a: 'aggTradeId', + p: 'price', + q: 'quantity', + f: 'firstTradeId', + l: 'lastTradeId', + T: 'timestamp', + m: 'maker', + M: 'bestPriceMatch' + }, + klines: { + 0: 'openTime', + 1: 'open', + 2: 'high', + 3: 'low', + 4: 'close', + 5: 'volume', + 6: 'closeTime', + 7: 'quoteAssetVolume', + 8: 'trades', + 9: 'takerBaseAssetVolume', + 10: 'takerQuoteAssetVolume', + 11: 'ignored' + }, + bids: [ + { + 0: 'price', + 1: 'quantity', + 2: 'ignored' + } + ], + asks: [ + { + 0: 'price', + 1: 'quantity', + 2: 'ignored' + } + ], + depthUpdateEvent: { + e: 'eventType', + E: 'eventTime', + s: 'symbol', + u: 'updateId', + b: 'bidDepthDelta', + a: 'askDepthDelta' + }, + bidDepthDelta: [ + { + 0: 'price', + 1: 'quantity', + 2: 'ignored' + } + ], + askDepthDelta: [ + { + 0: 'price', + 1: 'quantity', + 2: 'ignored' + } + ], + klineEvent: { + e: 'eventType', + E: 'eventTime', + s: 'symbol', + k: 'kline' + }, + kline: { + t: 'startTime', + T: 'endTime', + s: 'symbol', + i: 'interval', + f: 'firstTradeId', + L: 'lastTradeId', + o: 'open', + c: 'close', + h: 'high', + l: 'low', + v: 'volume', + n: 'trades', + x: 'final', + q: 'quoteVolume', + V: 'volumeActive', + Q: 'quoteVolumeActive', + B: 'ignored' + }, + aggTradeEvent: { + e: 'eventType', + E: 'eventTime', + s: 'symbol', + a: 'tradeId', + p: 'price', + q: 'quantity', + f: 'firstTradeId', + l: 'lastTradeId', + T: 'time', + m: 'maker', + M: 'ignored' + }, + outboundAccountInfoEvent: { + e: 'eventType', + E: 'eventTime', + m: 'makerCommission', + t: 'takerCommission', + b: 'buyerCommission', + s: 'sellerCommission', + T: 'canTrade', + W: 'canWithdraw', + D: 'canDeposit', + B: 'balances' + }, + balances: [ + { + a: 'asset', + f: 'availableBalance', + l: 'onOrderBalance' + } + ], + executionReportEvent: { + e: 'eventType', + E: 'eventTime', + s: 'symbol', + c: 'newClientOrderId', + S: 'side', + o: 'orderType', + f: 'cancelType', // GTC 'Good till Cancel', IOC: 'Immediate or Cancel' + q: 'quantity', + p: 'price', + x: 'executionType', + X: 'orderStatus', + r: 'rejectReason', + i: 'orderId', + l: 'lastTradeQuantity', + z: 'accumulatedQuantity', + L: 'lastTradePrice', + n: 'commission', + N: 'commissionAsset', + m: 'maker', + T: 'tradeTime', + t: 'tradeId' + } + } + } + + beautify(object, type) { + const beautifications = _.isObject(type) ? type : this._beautifications[type]; + if (!beautifications) { + return object; + } + let newItem = {}; + _.each(object, (value, key) => { + if (_.isArray(value)) { + const newArray = []; + if (_.isArray(this._beautifications[beautifications[key]])) { + _.each(value, arrayValue => { + newArray.push(this.beautify(arrayValue, this._beautifications[beautifications[key]][0])); + }); + } else { + _.each(value, (value, key) => { + newItem.push(this.beautify(value, beautifications[key])) + }); + } + const newKey = beautifications[key] || key; + newItem[newKey] = newArray; + } else if (_.isObject(value)) { + const newKey = beautifications[key] || key; + newItem[newKey] = this.beautify(value, beautifications[key]); + } else { + const newKey = beautifications[key] || key; + newItem[newKey] = value; + } + }); + return newItem; + } + +} + +module.exports = Beautifier; \ No newline at end of file diff --git a/Exchange/wrappers/binance.js b/Exchange/wrappers/binance.js new file mode 100644 index 000000000..624c0fc06 --- /dev/null +++ b/Exchange/wrappers/binance.js @@ -0,0 +1,368 @@ +// Source: https://github.com/zoeyg/binance/blob/master/lib/rest.js + +const request = require('request'); +const qs = require('querystring'); +const _ = require('underscore'); +const crypto = require('crypto'); +const Beautifier = require('./beautifier.js'); +const assert = require('assert'); + +class BinanceRest { + + constructor({ + key, + secret, + recvWindow = false, + timeout = 15000, + disableBeautification = false, + handleDrift = false + }) { + this.key = key; + this.secret = secret; + this.recvWindow = recvWindow; + this.timeout = timeout; + this.disableBeautification = disableBeautification; + this.handleDrift = handleDrift; + + this._beautifier = new Beautifier(); + this._baseUrl = 'https://api.binance.com/'; + this._drift = 0; + this._syncInterval = 0; + } + + _makeRequest(query, callback, route, security, method, attempt = 0) { + assert(_.isUndefined(callback) || _.isFunction(callback), 'callback must be a function or undefined'); + assert(_.isObject(query), 'query must be an object'); + + let queryString; + const type = _.last(route.split('/')), + options = { + url: `${this._baseUrl}${route}`, + timeout: this.timeout + }; + + if (security === 'SIGNED') { + if (this.recvWindow) { + query.recvWindow = this.recvWindow; + } + queryString = qs.stringify(query); + options.url += '?' + queryString; + if (options.url.substr(options.url.length - 1) !== '?') { + options.url += '&'; + } + options.url += `signature=${this._sign(queryString)}`; + } else { + queryString = qs.stringify(query); + if (queryString) { + options.url += '?' + queryString; + } + } + if (security === 'API-KEY' || security === 'SIGNED') { + options.headers = { 'X-MBX-APIKEY': this.key }; + } + if (method) { + options.method = method; + } + + const action = cb => { + request(options, (err, response, body) => { + let payload; + try { + payload = JSON.parse(body); + } catch (e) { + payload = body; + } + if (err) { + cb(err, payload); + } else if (response.statusCode < 200 || response.statusCode > 299) { + /* + * If we get a response that the timestamp is ahead of the server, + * calculate the drift and then attempt the request again + */ + if (response.statusCode === 400 && payload.code === -1021 && + this.handleDrift && attempt === 0) { + + this.calculateDrift() + .then(() => { + query.timestamp = this._getTime() + this._drift; + return this._makeRequest(query, cb, route, security, method, + ++attempt); + }); + } else { + cb(new Error(`Response code ${response.statusCode}`), payload); + } + } else { + if (_.isArray(payload)) { + payload = _.map(payload, (item) => { + return this._doBeautifications(item, type); + }); + } else { + payload = this._doBeautifications(payload); + } + cb(err, payload); + } + }); + }; + if (callback) { + action(callback); + } else { + return new Promise((resolve, reject) => action((err, payload) => { + if (err) { + if (payload === undefined) { + reject(err); + } else { + reject(payload); + } + } else { + resolve(payload); + } + })); + } + } + + _doBeautifications(response, route) { + if (this.disableBeautification) { + return response; + } + return this._beautifier.beautify(response, route); + } + + _sign(queryString) { + return crypto.createHmac('sha256', this.secret) + .update(queryString) + .digest('hex'); + } + + _setTimestamp(query) { + if (!query.timestamp) { + query.timestamp = this._getTime() + this._drift; + } + } + + _getTime() { + return new Date().getTime(); + } + + calculateDrift() { + const systemTime = this._getTime(); + return this.time() + .then((response) => { + // Calculate the approximate trip time from here to binance + const transitTime = parseInt((this._getTime() - systemTime) / 2); + this._drift = response.serverTime - (systemTime + transitTime); + }); + } + + startTimeSync(interval = 300000, onRecalculateDriftCb) { + return new Promise((resolve, reject) => { + // If there's already an interval running, clear it and reset values + if (this._syncInterval !== 0) { + this.endTimeSync(); + return resolve(); + } + + // Calculate initial drift value and setup interval to periodically update it + this.calculateDrift() + .then(resolve) + .catch(reject); + + this._syncInterval = setInterval(() => { + const promise = this.calculateDrift(); + + if (_.isFunction(onRecalculateDriftCb)) { + onRecalculateDriftCb(promise); + } + }, interval); + }); + } + + endTimeSync() { + clearInterval(this._syncInterval); + this._drift = 0; + this._syncInterval = 0; + } + + // Public APIs + ping(callback) { + return this._makeRequest({}, callback, 'api/v1/ping'); + } + + time(callback) { + return this._makeRequest({}, callback, 'api/v1/time'); + } + + depth(query = {}, callback) { + if (_.isString(query)) { + query = { symbol: query }; + } + + return this._makeRequest(query, callback, 'api/v1/depth'); + } + + trades(query = {}, callback) { + if (_.isString(query)) { + query = { symbol: query }; + } + + return this._makeRequest(query, callback, 'api/v1/trades'); + } + + historicalTrades(query = {}, callback) { + if (_.isString(query)) { + query = { symbol: query }; + } + + return this._makeRequest(query, callback, 'api/v1/historicalTrades', 'API-KEY'); + } + + aggTrades(query = {}, callback) { + if (_.isString(query)) { + query = { symbol: query }; + } + + return this._makeRequest(query, callback, 'api/v1/aggTrades'); + } + + exchangeInfo(callback) { + return this._makeRequest({}, callback, 'api/v1/exchangeInfo'); + } + + klines(query = {}, callback) { + return this._makeRequest(query, callback, 'api/v1/klines'); + } + + ticker24hr(query = {}, callback) { + if (_.isString(query)) { + query = { symbol: query }; + } + + return this._makeRequest(query, callback, 'api/v1/ticker/24hr'); + } + + tickerPrice(query = {}, callback) { + if (_.isString(query)) { + query = { symbol: query }; + } + + return this._makeRequest(query, callback, 'api/v3/ticker/price'); + } + + bookTicker(query = {}, callback) { + if (_.isString(query)) { + query = { symbol: query }; + } + + return this._makeRequest(query, callback, 'api/v3/ticker/bookTicker'); + } + + allBookTickers(callback) { + return this._makeRequest({}, callback, 'api/v1/ticker/allBookTickers'); + } + + allPrices(callback) { + return this._makeRequest({}, callback, 'api/v1/ticker/allPrices'); + } + + // Private APIs + newOrder(query = {}, callback) { + this._setTimestamp(query); + return this._makeRequest(query, callback, 'api/v3/order', 'SIGNED', 'POST'); + } + + testOrder(query = {}, callback) { + this._setTimestamp(query); + return this._makeRequest(query, callback, 'api/v3/order/test', 'SIGNED', 'POST'); + } + + queryOrder(query = {}, callback) { + this._setTimestamp(query); + return this._makeRequest(query, callback, 'api/v3/order', 'SIGNED'); + } + + cancelOrder(query = {}, callback) { + this._setTimestamp(query); + return this._makeRequest(query, callback, 'api/v3/order', 'SIGNED', 'DELETE'); + } + + openOrders(query = {}, callback) { + if (_.isString(query)) { + query = { symbol: query }; + } + this._setTimestamp(query); + return this._makeRequest(query, callback, 'api/v3/openOrders', 'SIGNED'); + } + + allOrders(query = {}, callback) { + if (_.isString(query)) { + query = { symbol: query }; + } + this._setTimestamp(query); + return this._makeRequest(query, callback, 'api/v3/allOrders', 'SIGNED'); + } + + account(query = {}, callback) { + if (_.isFunction(query)) { + callback = query; + query = {}; + } + this._setTimestamp(query); + return this._makeRequest(query, callback, 'api/v3/account', 'SIGNED'); + } + + myTrades(query = {}, callback) { + if (_.isString(query)) { + query = { symbol: query }; + } + this._setTimestamp(query); + return this._makeRequest(query, callback, 'api/v3/myTrades', 'SIGNED'); + } + + withdraw(query = {}, callback) { + this._setTimestamp(query); + return this._makeRequest(query, callback, 'wapi/v3/withdraw.html', 'SIGNED', 'POST'); + } + + depositHistory(query = {}, callback) { + if (_.isString(query)) { + query = { asset: query }; + } + this._setTimestamp(query); + return this._makeRequest(query, callback, 'wapi/v3/depositHistory.html', 'SIGNED'); + } + + withdrawHistory(query = {}, callback) { + if (_.isString(query)) { + query = { asset: query }; + } + this._setTimestamp(query); + return this._makeRequest(query, callback, 'wapi/v3/withdrawHistory.html', 'SIGNED'); + } + + depositAddress(query = {}, callback) { + if (_.isString(query)) { + query = { asset: query }; + } + this._setTimestamp(query); + return this._makeRequest(query, callback, 'wapi/v3/depositAddress.html', 'SIGNED'); + } + + accountStatus(callback) { + const query = {}; + this._setTimestamp(query); + return this._makeRequest(query, callback, 'wapi/v3/accountStatus.html', 'SIGNED'); + } + + startUserDataStream(callback) { + return this._makeRequest({}, callback, 'api/v1/userDataStream', 'API-KEY', 'POST'); + } + + keepAliveUserDataStream(query = {}, callback) { + return this._makeRequest(query, callback, 'api/v1/userDataStream', 'API-KEY', 'PUT'); + } + + closeUserDataStream(query = {}, callback) { + return this._makeRequest(query, callback, 'api/v1/userDataStream', 'API-KEY', 'DELETE'); + } +} + +module.exports = BinanceRest; \ No newline at end of file diff --git a/Exchange/wrappers/binanceClient.js b/Exchange/wrappers/binanceClient.js new file mode 100644 index 000000000..a46ca7d24 --- /dev/null +++ b/Exchange/wrappers/binanceClient.js @@ -0,0 +1,360 @@ +exports.newAPIClient = function newAPIClient(pKey, pSecret, logger) { + + /* + /* ATENTION: This Library is used both a the cloud (AACloud) and also at the AAWeb on the server side without any modifications. + /* There is a second version, stripped of all the inner functionality that runs at AAWeb browser side, which channels the requests to the server side one. + */ + + const FULL_LOG = true; + const LOG_FILE_CONTENT = true; + const MODULE_NAME = "binanceClient"; + + const retry = require('../exchangeUtils').retry; + const includes = require('../exchangeUtils').includes; + const _ = require('lodash'); + const Binance = require("./binance"); + const exchangeProperties = require('./poloniexProperties.json'); + + const recoverableErrors = [ + 'SOCKETTIMEDOUT', + 'TIMEDOUT', + 'CONNRESET', + 'CONNREFUSED', + 'NOTFOUND', + 'Error -1021', + 'Response code 429', + 'Response code 5', + 'ETIMEDOUT' + ]; + + let API = new Binance({ + key: pKey, + secret: pSecret, + timeout: 15000, + recvWindow: 60000, + disableBeautification: false, + handleDrift: true, + }); + + let thisObject = { + getTicker: getTicker, + getOpenPositions: getOpenPositions, + getExecutedTrades: getExecutedTrades, + buy: buy, + sell: sell, + movePosition: movePosition, + getPublicTradeHistory: getPublicTradeHistory, + getExchangeProperties: getExchangeProperties, + isValidPrice: isValidPrice, + isValidLot: isValidLot + }; + + return thisObject; + + function joinCurrencies(currencyA, currencyB) { + // If only one arg, then return the first + if (typeof currencyB !== 'string') { + return currencyA; + } + + return currencyB + '' + currencyA; + } + + /* + * Returns the properties for this exchange + */ + function getExchangeProperties() { + return exchangeProperties; + } + + function truncDecimals(pFloatValue) { + + let decimals = 6; + + return parseFloat(parseFloat(pFloatValue).toFixed(decimals)); + + } + + /* + * Returns the price for a given pair of assets. + * The object returned is an array of trades: + * ticker = { + * bid, Number + * ask, Number + * last Number + * }; + */ + function getTicker(pMarket, callBack) { + + let market = joinCurrencies(pMarket.assetA, pMarket.assetB); + const handle = (err, response) => { + let ticker; + if (err.result === global.DEFAULT_OK_RESPONSE.result) { + ticker = { + bid: Number(response.bidPrice), + ask: Number(response.askPrice), + last: Number(response.lastPrice) + }; + } + callBack(err, ticker); + }; + + const fetch = next => API.ticker24hr(market, analizeResponse(next)); + + retry(null, fetch, handle); + } + + /* + * Returns the open positions ath the exchange for a given market and user account. + * The object returned is an array of positions: + * position = { + * id, + * type, + * rate, Number + * amountA, Number + * amountB, Number + * fee, (not required) Number + * datetime + * }; + */ + function getOpenPositions(pMarket, callBack) { + + let market = joinCurrencies(pMarket.assetA, pMarket.assetB); + const handle = (err, response) => { + let exchangePositions = []; + if (err.result === global.DEFAULT_OK_RESPONSE.result) { + for (let i = 0; i < response.length; i++) { + let openPosition = { + id: response[i].orderId, + type: response[i].side.toLowerCase(), + rate: Number(response[i].price), + amountA: truncDecimals(response[i].origQty * response[i].price), + amountB: Number(response[i].origQty), + date: (new Date(response[i].time)).valueOf() + }; + exchangePositions.push(openPosition); + } + } + callBack(err, exchangePositions); + }; + + const fetch = next => API.openOrders(market, analizeResponse(next)); + + retry(null, fetch, handle); + } + + /* + * Returns the trades for a given order number. + * The object returned is an array of positions: + * position = { + * id, + * type, + * rate, Number + * amountA, Number + * amountB, Number + * fee, Number + * datetime + * }; + */ + function getExecutedTrades(pPositionId, callBack) { + + let market = joinCurrencies(global.MARKET.assetA, global.MARKET.assetB); + const handle = (err, response) => { + let exchangeTrades = []; + if (err.result === global.DEFAULT_OK_RESPONSE.result) { + for (let i = 0; i < response.length; i++) { + if (response[i].orderId === pPositionId) { + let type = "sell" + if (response[i].isBuyer === true) { + type = "buy"; + } + let trade = { + id: response[i].orderId, + type: type, + rate: Number(response[i].price), + amountA: truncDecimals(response[i].qty * response[i].price), + amountB: Number(response[i].qty), + fee: Number(response[i].commission), + date: (new Date(response[i].time)).valueOf() + }; + exchangeTrades.push(trade); + break; + } + } + } + callBack(err, exchangeTrades); + }; + + const fetch = next => API.myTrades(market, analizeResponse(next)); + + retry(null, fetch, handle); + } + + /* + * Creates a new buy order. + * The orderNumber is returned. + */ + function buy(pCurrencyA, pCurrencyB, pRate, pAmount, callBack) { + + var parameters = { + symbol: joinCurrencies(pCurrencyA, pCurrencyB), + side: 'BUY', + type: 'LIMIT', + quantity: pAmount, + price: pRate, + timeInForce: 'GTC' + }; + const handle = (err, response) => { + let orderNumber; + if (err.result === global.DEFAULT_OK_RESPONSE.result) { + orderNumber = response.orderId; + } + callBack(err, orderNumber); + }; + + const fetch = next => API.newOrder(parameters, analizeResponse(next)); + + retry(null, fetch, handle); + + } + + /* + * Creates a new sell order. + * The orderNumber is returned. String + */ + function sell(pCurrencyA, pCurrencyB, pRate, pAmount, callBack) { + + var parameters = { + symbol: joinCurrencies(pCurrencyA, pCurrencyB), + side: 'SELL', + type: 'LIMIT', + quantity: pAmount, + price: pRate, + timeInForce: 'GTC' + }; + const handle = (err, response) => { + let orderNumber; + if (err.result === global.DEFAULT_OK_RESPONSE.result) { + orderNumber = response.orderId; + } + callBack(err, orderNumber); + }; + + const fetch = next => API.newOrder(parameters, analizeResponse(next)); + + retry(null, fetch, handle); + } + + /* //TODO Complete partial orders + * Move an existing position to the new rate. + * The new orderNumber is returned. String + */ + function movePosition(pPosition, pNewRate, pNewAmountB, callBack) { + + var parameters = { + symbol: joinCurrencies(global.MARKET.assetA, global.MARKET.assetB), + orderId: pPosition.id + }; + + if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] moveOrder -> Step1 - Cancelling Position: " + JSON.stringify(pPosition)); } + + const handle = (err, response) => { + if (err.result === global.DEFAULT_OK_RESPONSE.result) { + if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] moveOrder -> Step1 Complete - Position Cancelled. Proceeding to put the new position."); } + + if (position.type === "buy") + thisObject.buy(global.MARKET.assetA, global.MARKET.assetB, pNewRate, pNewAmountB, callBack); + else + thisObject.sell(global.MARKET.assetA, global.MARKET.assetB, pNewRate, pNewAmountB, callBack); + } else { + callBack(err); + } + }; + + const fetch = next => API.cancelOrder(parameters, analizeResponse(next)); + + retry(null, fetch, handle); + } + + /* //TODO Pending Review + * Returns all the trade history from the Exchange since startTime to endTime orderd by tradeId. + * It's possible that the exchange doesn't support this method. + * The object returned is an array of trades: + * trade = { + * tradeIdAtExchange, + * marketIdAtExchange, + * type, + * rate, Number + * amountA, Number + * amountB, Number + * datetime + * }; + */ + function getPublicTradeHistory(assetA, assetB, startTime, endTime, callBack) { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] getPublicTradeHistory -> Not implemented yet."); } + callBack(global.DEFAULT_FAIL_RESPONSE); + } + + function isValidPrice(price) { + return price >= market.minimalOrder.price; + } + + function isValidLot(price, amount) { + return amount * price >= market.minimalOrder.order; + } + + function analizeResponse(callBack) { + + return (exchangeErr, exchangeResponse) => { + let error; + + /* This function analizes the different situations we might encounter trying to access Poloniex and returns appropiate standard errors. */ + + let stringExchangeErr = JSON.stringify(exchangeErr); + let stringExchangeResponse = JSON.stringify(exchangeResponse); + + try { + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] analizeResponse -> exchangeErr = " + stringExchangeErr); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] analizeResponse -> exchangeResponse = " + stringExchangeResponse); } + + if (exchangeErr) { + error = global.DEFAULT_FAIL_RESPONSE; + } else if (!exchangeResponse) { + error = { + result: global.DEFAULT_FAIL_RESPONSE.result, + message: 'Empty response' + }; + } else if (includes(exchangeResponse.error, [''])) { + error = { + result: global.DEFAULT_FAIL_RESPONSE.result, + message: exchangeResponse + }; + } else if (includes(exchangeResponse.error, ['Order does not exist.'])) { + error = { + result: global.CUSTOM_OK_RESPONSE.result, + message: exchangeResponse.error + }; + } else if (exchangeResponse.error) { + error = { + result: global.DEFAULT_FAIL_RESPONSE.result, + message: exchangeResponse.error + }; + } + + if (error) { + if (includes(error.message, recoverableErrors)) { + error.notFatal = true; + } + } + + return callBack(error, exchangeResponse); + + } catch (err) { + logger.write(MODULE_NAME, "[ERROR] analizeResponse -> err.message = " + err.message); + return callBack(global.DEFAULT_FAIL_RESPONSE, exchangeResponse); + } + } + } + +} diff --git a/Exchange/wrappers/binanceProperties.json b/Exchange/wrappers/binanceProperties.json new file mode 100644 index 000000000..ad4438de0 --- /dev/null +++ b/Exchange/wrappers/binanceProperties.json @@ -0,0 +1,4594 @@ +{ + "assets": [ + "NULS", + "VEN", + "BNB", + "NEO", + "LINK", + "SALT", + "IOTA", + "ETC", + "AST", + "KNC", + "WTC", + "SNGLS", + "EOS", + "SNT", + "MCO", + "BTC", + "OAX", + "OMG", + "GAS", + "BQX", + "QTUM", + "BNT", + "DNT", + "ICN", + "SNM", + "STRAT", + "ZRX", + "FUN", + "LTC", + "ETH", + "XVG", + "BCC", + "ADA", + "ADX", + "AE", + "AGI", + "AION", + "AMB", + "APPC", + "ARK", + "ARN", + "BAT", + "BCD", + "BCN", + "BCPT", + "BLZ", + "BRD", + "BTG", + "BTS", + "CDT", + "CHAT", + "CLOAK", + "CMT", + "CND", + "CVC", + "DASH", + "DATA", + "DENT", + "DGD", + "DLT", + "EDO", + "ELF", + "ENG", + "ENJ", + "EVX", + "FUEL", + "GNT", + "GRS", + "GTO", + "GVT", + "GXS", + "HSR", + "ICX", + "INS", + "IOST", + "IOTX", + "KEY", + "KMD", + "LEND", + "LOOM", + "LRC", + "LSK", + "LUN", + "MANA", + "MDA", + "MFT", + "MOD", + "MTH", + "MTL", + "NANO", + "NAS", + "NAV", + "NCASH", + "NEBL", + "NPXS", + "NXS", + "ONT", + "OST", + "PIVX", + "POA", + "POE", + "POWR", + "PPT", + "QKC", + "QLC", + "QSP", + "RCN", + "RDN", + "REP", + "REQ", + "RLC", + "RPX", + "SC", + "SKY", + "STEEM", + "STORJ", + "STORM", + "SUB", + "SYS", + "THETA", + "TNB", + "TNT", + "TRIG", + "TRX", + "TUSD", + "VIA", + "VIB", + "VIBE", + "WABI", + "WAN", + "WAVES", + "WINGS", + "WPR", + "XEM", + "XLM", + "XMR", + "XRP", + "XZC", + "YOYO", + "ZEC", + "ZEN", + "ZIL" + ], + "currencies": [ + "BNB", + "BTC", + "ETH", + "USDT" + ], + "markets": [ + { + "pair": [ + "BNB", + "NULS" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "BNB", + "VEN" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.0001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "BNB" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 1e-7, + "order": 0.001 + } + }, + { + "pair": [ + "BTC", + "NULS" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "BTC", + "NEO" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "NULS" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "LINK" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "BTC", + "SALT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 1e-7, + "order": 0.001 + } + }, + { + "pair": [ + "BTC", + "IOTA" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "BTC", + "ETC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "AST" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-7, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "KNC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "BTC", + "WTC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 1e-7, + "order": 0.001 + } + }, + { + "pair": [ + "BTC", + "SNGLS" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "EOS" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "ETH", + "SNT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "ETH", + "MCO" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "USDT", + "BTC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.000001, + "price": 0.01, + "order": 10 + } + }, + { + "pair": [ + "ETH", + "OAX" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-7, + "order": 0.01 + } + }, + { + "pair": [ + "ETH", + "OMG" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "GAS" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "BQX" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-7, + "order": 0.01 + } + }, + { + "pair": [ + "ETH", + "WTC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "ETH", + "QTUM" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "ETH", + "BNT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "ETH", + "DNT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "ETH", + "ICN" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-7, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "SNM" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "SNM" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "ETH", + "SNGLS" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "BQX" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "NEO" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "ETH", + "KNC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-7, + "order": 0.01 + } + }, + { + "pair": [ + "ETH", + "STRAT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "ETH", + "ZRX" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "QTUM" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "FUN" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "LTC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "LINK" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "ETH" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.001, + "price": 0.000001, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "XVG" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "STRAT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 1e-7, + "order": 0.001 + } + }, + { + "pair": [ + "BTC", + "ZRX" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "IOTA" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "BCC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.001, + "price": 0.000001, + "order": 0.001 + } + }, + { + "pair": [ + "BTC", + "OMG" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.001 + } + }, + { + "pair": [ + "BTC", + "MCO" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "SALT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "ADA" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "ADA" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "ADA" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "USDT", + "ADA" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.1, + "price": 0.00001, + "order": 10 + } + }, + { + "pair": [ + "BNB", + "ADX" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "ADX" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "ADX" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-7, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "AE" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "AE" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 1e-7, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "AE" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "AGI" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "AGI" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "AGI" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "AION" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "AION" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 1e-7, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "AION" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "AMB" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "AMB" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "AMB" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "APPC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "APPC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "APPC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-7, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "ARK" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 1e-7, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "ARK" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "ARN" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "ARN" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "AST" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "BNB", + "BAT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "BAT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "BAT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "BCC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.00001, + "price": 0.01, + "order": 1 + } + }, + { + "pair": [ + "ETH", + "BCC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.001, + "price": 0.00001, + "order": 0.01 + } + }, + { + "pair": [ + "USDT", + "BCC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.00001, + "price": 0.01, + "order": 10 + } + }, + { + "pair": [ + "BTC", + "BCD" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.001, + "price": 0.000001, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "BCD" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.001, + "price": 0.00001, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "BCN" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 0.000001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "BCN" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "BCN" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "BCPT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "BCPT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "BCPT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "BLZ" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "BLZ" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "BLZ" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "ETH", + "BNB" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "BNT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "BNB", + "BRD" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "BRD" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "BRD" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-7, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "BTG" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "BTG" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "BTS" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "BTS" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "BTS" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "CDT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "CDT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "CHAT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "CHAT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "CLOAK" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 1e-7, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "CLOAK" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "CMT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "CMT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "CMT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "CND" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 0.000001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "CND" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "CND" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "CVC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "CVC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "CVC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "DASH" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.001, + "price": 0.000001, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "DASH" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.001, + "price": 0.00001, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "DATA" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "DATA" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "DENT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "DENT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "DGD" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.001, + "price": 0.000001, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "DGD" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.001, + "price": 0.00001, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "DLT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "DLT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "DLT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "DNT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "BTC", + "EDO" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 1e-7, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "EDO" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "ELF" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "ELF" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "ENG" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "ENG" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-7, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "ENJ" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 0.000001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "ENJ" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "ENJ" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "EOS" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.0001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "EOS" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 1e-7, + "order": 0.001 + } + }, + { + "pair": [ + "USDT", + "EOS" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.0001, + "order": 10 + } + }, + { + "pair": [ + "BNB", + "ETC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.0001, + "order": 1 + } + }, + { + "pair": [ + "ETH", + "ETC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "USDT", + "ETC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.0001, + "order": 10 + } + }, + { + "pair": [ + "BTC", + "EVX" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "EVX" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-7, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "FUEL" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "FUEL" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "FUN" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "BNB", + "GNT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "GNT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "GNT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "GRS" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "GRS" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "GTO" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "GTO" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "GTO" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "GVT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 1e-7, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "GVT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "GXS" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 1e-7, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "GXS" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "HSR" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "HSR" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "ICN" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "BNB", + "ICX" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "ICX" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 1e-7, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "ICX" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "USDT", + "ICX" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.0001, + "order": 10 + } + }, + { + "pair": [ + "BTC", + "INS" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 1e-7, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "INS" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "IOST" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "IOST" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "IOTA" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "USDT", + "IOTA" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.0001, + "order": 10 + } + }, + { + "pair": [ + "BTC", + "IOTX" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "IOTX" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "KEY" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "KEY" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "KMD" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 1e-7, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "KMD" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "LEND" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "LEND" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "LOOM" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "LOOM" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "LOOM" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "LRC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "LRC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "LSK" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.0001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "LSK" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 1e-7, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "LSK" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "LTC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.00001, + "price": 0.01, + "order": 1 + } + }, + { + "pair": [ + "ETH", + "LTC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.001, + "price": 0.00001, + "order": 0.01 + } + }, + { + "pair": [ + "USDT", + "LTC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.00001, + "price": 0.01, + "order": 10 + } + }, + { + "pair": [ + "BTC", + "LUN" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 1e-7, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "LUN" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "MANA" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "MANA" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "MCO" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "MDA" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "MDA" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-7, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "MFT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 0.000001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "MFT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "MFT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "MOD" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 1e-7, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "MOD" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "MTH" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "MTH" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "MTL" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 1e-7, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "MTL" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "NANO" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.0001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "NANO" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 1e-7, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "NANO" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "NAS" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "NAS" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 1e-7, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "NAS" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "NAV" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "NAV" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 1e-7, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "NAV" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "NCASH" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 0.000001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "NCASH" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "NCASH" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "NEBL" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "NEBL" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 1e-7, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "NEBL" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "NEO" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.001, + "price": 0.001, + "order": 1 + } + }, + { + "pair": [ + "USDT", + "NEO" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.001, + "price": 0.001, + "order": 10 + } + }, + { + "pair": [ + "BTC", + "NPXS" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "NPXS" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "NXS" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.0001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "NXS" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 1e-7, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "NXS" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "OAX" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "BNB", + "ONT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "ONT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 1e-7, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "ONT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "USDT", + "ONT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.001, + "price": 0.001, + "order": 10 + } + }, + { + "pair": [ + "BNB", + "OST" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 0.000001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "OST" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "OST" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "PIVX" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "PIVX" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 1e-7, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "PIVX" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "POA" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "POA" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "POA" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "POE" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "POE" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "POWR" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "POWR" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "POWR" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "PPT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 1e-7, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "PPT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "QKC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "QKC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "QLC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 0.000001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "QLC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "QLC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "QSP" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 0.000001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "QSP" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "QSP" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "QTUM" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "USDT", + "QTUM" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.001, + "price": 0.001, + "order": 10 + } + }, + { + "pair": [ + "BNB", + "RCN" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 0.000001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "RCN" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "RCN" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "RDN" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "RDN" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "RDN" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-7, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "REP" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.001, + "price": 0.001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "REP" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.001, + "price": 0.000001, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "REP" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.001, + "price": 0.00001, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "REQ" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "REQ" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "RLC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "RLC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 1e-7, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "RLC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "RPX" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 0.000001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "RPX" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "RPX" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "SC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 0.000001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "SC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "SC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "SKY" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.001, + "price": 0.001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "SKY" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.001, + "price": 0.000001, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "SKY" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.001, + "price": 0.00001, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "SNT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "BNB", + "STEEM" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "STEEM" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 1e-7, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "STEEM" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "STORJ" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "STORJ" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-7, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "STORM" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 0.000001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "STORM" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "STORM" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "SUB" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "SUB" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "SYS" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "SYS" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "SYS" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "THETA" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "THETA" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "THETA" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "TNB" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "TNB" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "TNT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "TNT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "TRIG" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "TRIG" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 1e-7, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "TRIG" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "TRX" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "TRX" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "USDT", + "TRX" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.1, + "price": 0.00001, + "order": 10 + } + }, + { + "pair": [ + "BNB", + "TUSD" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "TUSD" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "TUSD" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "USDT", + "TUSD" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.0001, + "order": 10 + } + }, + { + "pair": [ + "BTC", + "VEN" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "VEN" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "USDT", + "VEN" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.0001, + "order": 10 + } + }, + { + "pair": [ + "BNB", + "VIA" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "VIA" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 1e-7, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "VIA" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "VIB" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "BTC", + "VIBE" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "VIBE" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-7, + "order": 0.01 + } + }, + { + "pair": [ + "ETH", + "VIB" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "WABI" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "WABI" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "WABI" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "WAN" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "WAN" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 1e-7, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "WAN" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "WAVES" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.0001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "WAVES" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 1e-7, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "WAVES" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "WINGS" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "WINGS" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-7, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "WPR" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "WPR" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "WTC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.0001, + "order": 1 + } + }, + { + "pair": [ + "BNB", + "XEM" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "XEM" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "XEM" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "XLM" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "XLM" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "XLM" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "USDT", + "XLM" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 10 + } + }, + { + "pair": [ + "BTC", + "XMR" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.001, + "price": 0.000001, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "XMR" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.001, + "price": 0.00001, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "XRP" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "XRP" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "XRP" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "USDT", + "XRP" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.1, + "price": 0.00001, + "order": 10 + } + }, + { + "pair": [ + "BTC", + "XVG" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "BNB", + "XZC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.001, + "price": 0.001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "XZC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "XZC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "YOYO" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 0.000001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "YOYO" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "YOYO" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "ZEC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.001, + "price": 0.000001, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "ZEC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.001, + "price": 0.00001, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "ZEN" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.001, + "price": 0.001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "ZEN" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.001, + "price": 0.000001, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "ZEN" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.001, + "price": 0.00001, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "ZIL" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 0.000001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "ZIL" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "ZIL" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "USDT", + "BNB" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.0001, + "order": 10 + } + }, + { + "pair": [ + "USDT", + "ETH" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.00001, + "price": 0.01, + "order": 10 + } + } + ] +} \ No newline at end of file diff --git a/Exchange/wrappers/poloniex.js b/Exchange/wrappers/poloniex.js new file mode 100644 index 000000000..9a1a32b41 --- /dev/null +++ b/Exchange/wrappers/poloniex.js @@ -0,0 +1,440 @@ +// Source: https://github.com/premasagar/poloniex.js +// Documentation: https://poloniex.com/support/api/ + +module.exports = (function () { + 'use strict'; + + // Module dependencies + var request = require('request'), + nonce = require('nonce')(); + + // Constants + var version = '0.0.9', + PUBLIC_API_URL = 'https://poloniex.com/public', + PRIVATE_API_URL = 'https://poloniex.com/tradingApi', + USER_AGENT = 'poloniex.js ' + version; + //USER_AGENT = 'Mozilla/5.0 (Windows NT 6.3; WOW64; rv:26.0) Gecko/20100101 Firefox/26.0' + + // Helper methods + function joinCurrencies(currencyA, currencyB) { + // If only one arg, then return the first + if (typeof currencyB !== 'string') { + return currencyA; + } + + return currencyA + '_' + currencyB; + } + + // Constructor + function Poloniex(keyVaultAPI) { + // Generate headers signed by this user's key and secret. + // The secret is encapsulated and never exposed + this._getPrivateHeaders = function (parameters, next) { + var paramString, signature; + + // Convert to `arg1=foo&arg2=bar` + paramString = Object.keys(parameters).map(function (param) { + return encodeURIComponent(param) + '=' + encodeURIComponent(parameters[param]); + }).join('&'); + + keyVaultAPI.signTransaction(paramString, next); + }; + } + + // Currently, this fails with `Error: CERT_UNTRUSTED` + // Poloniex.STRICT_SSL can be set to `false` to avoid this. Use with caution. + // Will be removed in future, once this is resolved. + Poloniex.STRICT_SSL = true; + + // Customisable user agent string + Poloniex.USER_AGENT = USER_AGENT; + + // Prototype + Poloniex.prototype = { + constructor: Poloniex, + + // Make an API request + _request: function (options, callback) { + if (!('headers' in options)) { + options.headers = {}; + } + + options.json = true; + options.headers['User-Agent'] = Poloniex.USER_AGENT; + options.strictSSL = Poloniex.STRICT_SSL; + options.timeout = 60 * 1000; + + request(options, function (err, response, body) { + // Empty response + if (!err && (typeof body === 'undefined' || body === null)) { + err = 'Empty response'; + } + + callback(err, body); + }); + + return this; + }, + + // Make a public API request + _public: function (command, parameters, callback) { + var options; + + if (typeof parameters === 'function') { + callback = parameters; + parameters = {}; + } + + parameters || (parameters = {}); + parameters.command = command; + options = { + method: 'GET', + url: PUBLIC_API_URL, + qs: parameters + }; + + options.qs.command = command; + return this._request(options, callback); + }, + + // Make a private API request + _private: function (command, parameters, callback) { + var options; + + if (typeof parameters === 'function') { + callback = parameters; + parameters = {}; + } + + parameters || (parameters = {}); + parameters.command = command; + parameters.nonce = nonce(); + + options = { + method: 'POST', + url: PRIVATE_API_URL, + form: parameters + }; + + let headers = this._getPrivateHeaders(parameters, next) + + let thisObject = this + + function next(pHeaders, error) { + if (!error) { + options.headers = pHeaders; + return thisObject._request(options, callback); + } else { + callback(error); + } + + } + }, + + ///// + // PUBLIC METHODS + + returnTicker: function (callback) { + return this._public('returnTicker', callback); + }, + + return24hVolume: function (callback) { + return this._public('return24hVolume', callback); + }, + + returnOrderBook: function (currencyA, currencyB, callback) { + var currencyPair; + + if (typeof currencyB === 'function') { + currencyPair = currencyA; + callback = currencyB; + currencyB = null; + } + + else { + currencyPair = joinCurrencies(currencyA, currencyB); + } + + var parameters = { + currencyPair: currencyPair + }; + + return this._public('returnOrderBook', parameters, callback); + }, + + returnChartData: function (currencyA, currencyB, period, start, end, callback) { + var parameters = { + currencyPair: joinCurrencies(currencyA, currencyB), + period: period, + start: start, + end: end + }; + + return this._public('returnChartData', parameters, callback); + }, + + returnCurrencies: function (callback) { + return this._public('returnCurrencies', callback); + }, + + returnLoanOrders: function (currency, callback) { + return this._public('returnLoanOrders', { currency: currency }, callback); + }, + + returnTradeHistory: function (currencyA, currencyB, start, end, callback) { + if (arguments.length < 5) { + callback = start; + start = Date.now() / 1000 - 60 * 60; + end = Date.now() / 1000 + 60 * 60; // Some buffer in case of client/server time out of sync. + } + + var parameters = { + currencyPair: joinCurrencies(currencyA, currencyB), + start: start, + end: end + }; + + return this._public('returnTradeHistory', parameters, callback); + }, + + ///// + // PRIVATE METHODS + + returnBalances: function (callback) { + return this._private('returnBalances', {}, callback); + }, + + returnCompleteBalances: function (account, callback) { + var parameters = {}; + + if (typeof account === 'function') { + callback = account; + } + + else if (typeof account === 'string' && !!account) { + parameters.account = account; + } + + return this._private('returnCompleteBalances', parameters, callback); + }, + + returnDepositAddresses: function (callback) { + return this._private('returnDepositAddresses', {}, callback); + }, + + generateNewAddress: function (currency, callback) { + return this._private('generateNewAddress', { currency: currency }, callback); + }, + + returnDepositsWithdrawals: function (start, end, callback) { + return this._private('returnDepositsWithdrawals', { start: start, end: end }, callback); + }, + + // can be called with `returnOpenOrders('all', callback)` + returnOpenOrders: function (currencyA, currencyB, callback) { + var currencyPair; + + if (typeof currencyB === 'function') { + currencyPair = currencyA; + callback = currencyB; + currencyB = null; + } + + else { + currencyPair = joinCurrencies(currencyA, currencyB); + } + + var parameters = { + currencyPair: currencyPair + }; + + return this._private('returnOpenOrders', parameters, callback); + }, + + returnOrderTrades: function (orderNumber, callback) { + var parameters = { + orderNumber: orderNumber + }; + + return this._private('returnOrderTrades', parameters, callback); + }, + + buy: function (currencyA, currencyB, rate, amount, callback) { + var parameters = { + currencyPair: joinCurrencies(currencyA, currencyB), + rate: rate, + amount: amount + }; + + return this._private('buy', parameters, callback); + }, + + sell: function (currencyA, currencyB, rate, amount, callback) { + var parameters = { + currencyPair: joinCurrencies(currencyA, currencyB), + rate: rate, + amount: amount + }; + + return this._private('sell', parameters, callback); + }, + + cancelOrder: function (currencyA, currencyB, orderNumber, callback) { + var parameters = { + currencyPair: joinCurrencies(currencyA, currencyB), + orderNumber: orderNumber + }; + + return this._private('cancelOrder', parameters, callback); + }, + + moveOrder: function (orderNumber, rate, amount, callback) { + var parameters = { + orderNumber: orderNumber, + rate: rate, + amount: amount ? amount : null + }; + + return this._private('moveOrder', parameters, callback); + }, + + withdraw: function (currency, amount, address, callback) { + var parameters = { + currency: currency, + amount: amount, + address: address + }; + + return this._private('withdraw', parameters, callback); + }, + + returnFeeInfo: function (callback) { + return this._private('returnFeeInfo', {}, callback); + }, + + returnAvailableAccountBalances: function (account, callback) { + var parameters = {}; + + if (typeof account === 'function') { + callback = account; + } + + else if (typeof account === 'string' && !!account) { + parameters.account = account; + } + + return this._private('returnAvailableAccountBalances', parameters, callback); + }, + + returnTradableBalances: function (callback) { + return this._private('returnTradableBalances', {}, callback); + }, + + transferBalance: function (currency, amount, fromAccount, toAccount, callback) { + var parameters = { + currency: currency, + amount: amount, + fromAccount: fromAccount, + toAccount: toAccount + }; + + return this._private('transferBalance', parameters, callback); + }, + + returnMarginAccountSummary: function (callback) { + return this._private('returnMarginAccountSummary', {}, callback); + }, + + marginBuy: function (currencyA, currencyB, rate, amount, lendingRate, callback) { + var parameters = { + currencyPair: joinCurrencies(currencyA, currencyB), + rate: rate, + amount: amount, + lendingRate: lendingRate ? lendingRate : null + }; + + return this._private('marginBuy', parameters, callback); + }, + + marginSell: function (currencyA, currencyB, rate, amount, lendingRate, callback) { + var parameters = { + currencyPair: joinCurrencies(currencyA, currencyB), + rate: rate, + amount: amount, + lendingRate: lendingRate ? lendingRate : null + }; + + return this._private('marginSell', parameters, callback); + }, + + getMarginPosition: function (currencyA, currencyB, callback) { + var parameters = { + currencyPair: joinCurrencies(currencyA, currencyB) + }; + + return this._private('getMarginPosition', parameters, callback); + }, + + closeMarginPosition: function (currencyA, currencyB, callback) { + var parameters = { + currencyPair: joinCurrencies(currencyA, currencyB) + }; + + return this._private('closeMarginPosition', parameters, callback); + }, + + createLoanOffer: function (currency, amount, duration, autoRenew, lendingRate, callback) { + var parameters = { + currency: currency, + amount: amount, + duration: duration, + autoRenew: autoRenew, + lendingRate: lendingRate + }; + + return this._private('createLoanOffer', parameters, callback); + }, + + cancelLoanOffer: function (orderNumber, callback) { + var parameters = { + orderNumber: orderNumber + }; + + return this._private('cancelLoanOffer', parameters, callback); + }, + + returnOpenLoanOffers: function (callback) { + return this._private('returnOpenLoanOffers', {}, callback); + }, + + returnActiveLoans: function (callback) { + return this._private('returnActiveLoans', {}, callback); + }, + + returnLendingHistory: function (start, end, limit, callback) { + var parameters = { + start: start, + end: end, + limit: limit + }; + + return this._private('returnLendingHistory', parameters, callback); + }, + + toggleAutoRenew: function (orderNumber, callback) { + return this._private('toggleAutoRenew', { orderNumber: orderNumber }, callback); + } + + }; + + // Backwards Compatibility + Poloniex.prototype.getTicker = Poloniex.prototype.returnTicker; + Poloniex.prototype.get24hVolume = Poloniex.prototype.return24hVolume; + Poloniex.prototype.getOrderBook = Poloniex.prototype.returnOrderBook; + Poloniex.prototype.getTradeHistory = Poloniex.prototype.returnChartData; + Poloniex.prototype.myBalances = Poloniex.prototype.returnBalances; + Poloniex.prototype.myOpenOrders = Poloniex.prototype.returnOpenOrders; + Poloniex.prototype.myTradeHistory = Poloniex.prototype.returnTradeHistory; + + return Poloniex; +})(); diff --git a/Exchange/wrappers/poloniexClient.js b/Exchange/wrappers/poloniexClient.js new file mode 100644 index 000000000..7476728c1 --- /dev/null +++ b/Exchange/wrappers/poloniexClient.js @@ -0,0 +1,353 @@ +exports.newAPIClient = function newAPIClient(keyVaultAPI, logger) { + + /* + /* ATENTION: This Library is used both a the cloud (AACloud) and also at the AAWeb on the server side without any modifications. + /* There is a second version, stripped of all the inner functionality that runs at AAWeb browser side, which channels the requests to the server side one. + */ + + const FULL_LOG = true; + const LOG_FILE_CONTENT = true; + const MODULE_NAME = "poloniexClient"; + + const retry = require('../exchangeUtils').retry; + const includes = require('../exchangeUtils').includes; + const _ = require('lodash'); + const Poloniex = require("./poloniex"); + const exchangeProperties = require('./poloniexProperties.json'); + + const recoverableErrors = [ + 'SOCKETTIMEDOUT', + 'TIMEDOUT', + 'CONNRESET', + 'CONNREFUSED', + 'NOTFOUND', + '429', + '522', + '504', + '503', + '500', + '502', + 'Empty response', + 'Please try again in a few minutes.', + 'Nonce must be greater than', + 'Internal error. Please try again.', + 'Connection timed out. Please try again.', + 'ENOTFOUND', + 'ECONNREFUSED', + 'CONNREFUSED', + 'NOTFOUND', + 'ESOCKETTIMEDOUT', + 'ECONNRESET', + 'Connection timed out', + 'Connection Error', + 'Order not found, or you are not the person who placed it.', + 'ETIMEDOUT' + ]; + + let API = new Poloniex(keyVaultAPI); + + let thisObject = { + getTicker: getTicker, + getOpenPositions: getOpenPositions, + getExecutedTrades: getExecutedTrades, + buy: buy, + sell: sell, + movePosition: movePosition, + getPublicTradeHistory: getPublicTradeHistory, + getExchangeProperties: getExchangeProperties, + isValidLot: isValidLot + }; + + return thisObject; + + function joinCurrencies(currencyA, currencyB) { + // If only one arg, then return the first + if (typeof currencyB !== 'string') { + return currencyA; + } + + return currencyA + '_' + currencyB; + } + + + /* + * Returns the properties for this exchange + */ + function getExchangeProperties() { + return exchangeProperties; + } + + /* + * Returns the price for a given pair of assets. + * The object returned is an array of trades: + * ticker = { + * bid, Number + * ask, Number + * last Number + * }; + */ + function getTicker(pMarket, callBack) { + + const handle = (err, response) => { + let ticker; + let market = joinCurrencies(pMarket.assetA, pMarket.assetB); + if (err.result === global.DEFAULT_OK_RESPONSE.result) { + ticker = { + bid: Number(response[market].highestBid), + ask: Number(response[market].lowestAsk), + last: Number(response[market].last) + }; + } + callBack(err, ticker); + }; + + const fetch = next => API.getTicker(analizeResponse(next)); + + retry(null, fetch, handle); + } + + /* + * Returns the open positions ath the exchange for a given market and user account. + * The object returned is an array of positions: + * position = { + * id, + * type, + * rate, Number + * amountA, Number + * amountB, Number + * fee, (not required) Number + * datetime + * }; + */ + function getOpenPositions(pMarket, callBack) { + + const handle = (err, response) => { + let exchangePositions = []; + if (err.result === global.DEFAULT_OK_RESPONSE.result) { + for (let i = 0; i < response.length; i++) { + let openPosition = { + id: response[i].orderNumber, + type: response[i].type, + rate: Number(response[i].rate), + amountA: Number(response[i].total), + amountB: Number(response[i].amount), + date: (new Date(response[i].time)).valueOf() + }; + exchangePositions.push(openPosition); + } + } + callBack(err, exchangePositions); + }; + + const fetch = next => API.returnOpenOrders(pMarket.assetA, pMarket.assetB, analizeResponse(next)); + + retry(null, fetch, handle); + } + + /* + * Returns the trades for a given order number. + * The object returned is an array of positions: + * position = { + * id, + * type, + * rate, Number + * amountA, Number + * amountB, Number + * fee, Number + * datetime + * }; + */ + function getExecutedTrades(pPositionId, callBack) { + + const handle = (err, response) => { + let trades = []; + if (err.result === global.DEFAULT_OK_RESPONSE.result) { + for (let i = 0; i < response.length; i++) { + let trade = { + id: response[i].tradeID, + type: response[i].type, + rate: Number(response[i].rate), + amountA: Number(response[i].total), + amountB: Number(response[i].amount), + fee: Number(response[i].fee), + date: (new Date(response[i].date)).valueOf() + } + trades.push(trade); + } + } else if (err.result === global.CUSTOM_OK_RESPONSE.result) { + // No trades found at the exchange for the position, but returning empy trades object. + err = global.DEFAULT_OK_RESPONSE; + } + callBack(err, trades); + }; + + const fetch = next => API.returnOrderTrades(pPositionId, analizeResponse(next)); + + retry(null, fetch, handle); + } + + /* + * Creates a new buy order. + * The orderNumber is returned. String + */ + function buy(pCurrencyA, pCurrencyB, pRate, pAmount, callBack) { + + const handle = (err, response) => { + let orderNumber; + if (err.result === global.DEFAULT_OK_RESPONSE.result) { + orderNumber = response.orderNumber; + } + callBack(err, orderNumber); + }; + + const fetch = next => API.buy(pCurrencyA, pCurrencyB, pRate, pAmount, analizeResponse(next)); + + retry(null, fetch, handle); + + } + + /* + * Creates a new sell order. + * The orderNumber is returned. String + */ + function sell(pCurrencyA, pCurrencyB, pRate, pAmount, callBack) { + + const handle = (err, response) => { + let orderNumber; + if (err.result === global.DEFAULT_OK_RESPONSE.result) { + orderNumber = response.orderNumber; + } + callBack(err, orderNumber); + }; + + const fetch = next => API.sell(pCurrencyA, pCurrencyB, pRate, pAmount, analizeResponse(next)); + + retry(null, fetch, handle); + } + + /* + * Move an existing position to the new rate. + * The orderNumber is returned. String + */ + function movePosition(pPosition, pNewRate, pNewAmountB, callBack) { + + const handle = (err, response) => { + let orderNumber; + if (err.result === global.DEFAULT_OK_RESPONSE.result) { + orderNumber = response.orderNumber; + } + callBack(err, orderNumber); + }; + + const fetch = next => API.moveOrder(pPosition.id, pNewRate, pNewAmountB, analizeResponse(next)); + + retry(null, fetch, handle); + } + + /* + * Returns all the trade history from the Exchange since startTime to endTime orderd by tradeId. + * It's possible that the exchange doesn't support this method. + * The object returned is an array of trades: + * trade = { + * tradeID, String + * globalTradeID, String + * type, String + * rate, Number + * amountA, Number + * amountB, Number + * date Date + * }; + */ + function getPublicTradeHistory(assetA, assetB, startTime, endTime, callBack) { + + const handle = (err, response) => { + let trades = []; + if (err.result === global.DEFAULT_OK_RESPONSE.result) { + for (let i = 0; i < response.length; i++) { + let trade = { + tradeID: response[i].tradeID, + globalTradeID: response[i].globalTradeID, + type: response[i].type, + rate: Number(response[i].rate), + total: Number(response[i].total), + amount: Number(response[i].amount), + date: new Date(response[i].date) + } + trades.push(trade); + } + } + callBack(err, trades); + }; + + const fetch = next => API.returnTradeHistory(assetA, assetB, startTime, endTime, analizeResponse(next)); + + retry(null, fetch, handle); + } + + function isValidLot(price, amount) { + return amount * price >= 0.0001; + } + + function analizeResponse(callBack) { + + return (exchangeErr, exchangeResponse) => { + let error; + + /* This function analizes the different situations we might encounter trying to access Poloniex and returns appropiate standard errors. */ + + let stringExchangeErr = JSON.stringify(exchangeErr); + let stringExchangeResponse = JSON.stringify(exchangeResponse); + + try { + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] analizeResponse -> exchangeErr = " + stringExchangeErr); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] analizeResponse -> exchangeResponse = " + stringExchangeResponse); } + + if (exchangeErr) { + error = global.DEFAULT_FAIL_RESPONSE; + + if (includes(exchangeErr.code, recoverableErrors)) { + error.notFatal = true; + } + } else if (!exchangeResponse || exchangeResponse === undefined) { + error = { + result: global.DEFAULT_FAIL_RESPONSE.result, + message: 'Empty response', + notFatal: true + }; + } else if (includes(exchangeResponse.error, ['Please complete the security check to proceed.'])) { + error = { + result: global.DEFAULT_FAIL_RESPONSE.result, + message: 'The IP has been flagged by CloudFlare.' + }; + } else if (includes(exchangeResponse.error, [''])) { + error = { + result: global.DEFAULT_FAIL_RESPONSE.result, + message: exchangeResponse + }; + } else if (includes(exchangeResponse.error, ['Not enough'])) { + error = { + result: global.DEFAULT_RETRY_RESPONSE.result, + message: exchangeResponse.error + }; + } else if (includes(exchangeResponse.error, ['Order not found, or you are not the person who placed it.'])) { + error = { + result: global.CUSTOM_OK_RESPONSE.result, + message: exchangeResponse.error + }; + } else if (exchangeResponse.error) { + error = { + result: global.DEFAULT_FAIL_RESPONSE.result, + message: exchangeResponse.error + }; + } + + return callBack(error, exchangeResponse); + + } catch (err) { + logger.write(MODULE_NAME, "[ERROR] analizeResponse -> err.message = " + err.message); + return callBack(global.DEFAULT_FAIL_RESPONSE, exchangeResponse); + } + } + } + +} diff --git a/Exchange/wrappers/poloniexProperties.json b/Exchange/wrappers/poloniexProperties.json new file mode 100644 index 000000000..a5716ba3b --- /dev/null +++ b/Exchange/wrappers/poloniexProperties.json @@ -0,0 +1,3513 @@ +{ + "currencies": ["BTC", "ETH", "XMR", "USDT"], + "assets": [ + "1CR", "ABY", "AC", "ACH", "ADN", "AEON", "AERO", "AIR", "AMP", "APH", + "ARCH", "AUR", "AXIS", "BALLS", "BANK", "BBL", "BBR", "BCC", "BCH", "BCN", + "BCY", "BDC", "BDG", "BELA", "BITCNY", "BITS", "BITUSD", "BLK", "BLOCK", + "BLU", "BNS", "BONES", "BOST", "BTC", "BTCD", "BTCS", "BTM", "BTS", + "BURN", "BURST", "C2", "CACH", "CAI", "CC", "CCN", "CGA", "CHA", "CINNI", + "CLAM", "CNL", "CNMT", "CNOTE", "COMM", "CON", "CORG", "CRYPT", "CURE", + "CVC", "CYC", "DAO", "DASH", "DCR", "DGB", "DICE", "DIEM", "DIME", "DIS", "DNS", + "DOGE", "DRKC", "DRM", "DSH", "DVK", "EAC", "EBT", "ECC", "EFL", "EMC2", + "EMO", "ENC", "ETC", "ETH", "eTOK", "EXE", "EXP", "FAC", "FCN", "FCT", + "FIBRE", "FLAP", "FLDC", "FLO", "FLT", "FOX", "FRAC", "FRK", "FRQ", "GNO", + "FVZ", "FZ", "FZN", "GAME", "GAP", "GAS", "GDN", "GEMZ", "GEO", "GIAR", "GLB", + "GML", "GNS", "GNT", "GOLD", "GPC", "GPUC", "GRC", "GRCX", "GRS", "GUE", "H2O", + "HIRO", "HOT", "HUC", "HUGE", "HVC", "HYP", "HZ", "IFC", "INDEX", "IOC", + "ITC", "IXC", "JLH", "JPC", "JUG", "KDC", "KEY", "LBC", "LC", "LCL", + "LEAF", "LGC", "LOL", "LOVE", "LQD", "LSK", "LTBC", "LTC", "LTCX", + "MAID", "MAST", "MAX", "MCN", "MEC", "METH", "MIL", "MIN", "MINT", "MMC", + "MMNXT", "MMXIV", "MNTA", "MON", "MRC", "MRS", "MTS", "MUN", "MYR", + "MZC", "N5X", "NAS", "NAUT", "NAV", "NBT", "NEOS", "NL", "NMC", "NOBL", + "NOTE", "NOXT", "NRS", "NSR", "NTX", "NXT", "NXTI", "OMG", "OMNI", "OPAL", + "PAND", "PASC", "PAWN", "PIGGY", "PINK", "PLX", "PMC", "POT", "PPC", "PRC", + "PRT", "PTS", "Q2C", "QBK", "QCN", "QORA", "QTL", "RADS", "RBY", "RDD", "REP", + "RIC", "RZR", "SBD", "SC", "SDC", "SHIBE", "SHOPX", "SILK", "SJCX", + "SLR", "SMC", "SOC", "SPA", "SQL", "SRCC", "SRG", "SSD", "STEEM", "STR", + "SUM", "SUN", "SWARM", "SXC", "SYNC", "SYS", "TAC", "TOR", "TRUST", + "TWE", "UIS", "ULTC", "UNITY", "URO", "USDE", "USDT", "UTC", "UTIL", + "UVC", "VIA", "VOOT", "VOX", "VRC", "VTC", "WC", "WDC", "WIKI", "WOLF", + "X13", "XAI", "XAP", "XBC", "XC", "XCH", "XCN", "XCP", "XCR", "XDN", + "XDP", "XEM", "XHC", "XLB", "XMG", "XMR", "XPB", "XPM", "XRP", "XSI", + "XST", "XSV", "XUSD", "XVC", "XXC", "BCH", "YACC", "YANG", "YC", "YIN", "ZEC", + "ZRX" + ], + "markets": [ + { + "pair": [ + "BTC", + "1CR" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "ABY" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "AC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "ACH" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "ADN" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "AEON" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "AERO" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "AIR" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "AMP" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "APH" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "ARCH" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "AUR" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "AXIS" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "BALLS" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "BANK" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "BBL" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "BBR" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "BCC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "BCN" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "BCH" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "BCY" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "BDC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "BDG" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "BELA" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "BITCNY" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "BITS" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "BITUSD" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "BLK" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "BLOCK" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "BLU" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "BNS" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "BONES" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "BOST" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "BTCD" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "BTCS" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "BTM" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "BTS" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "BURN" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "BURST" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "C2" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "CACH" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "CAI" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "CC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "CCN" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "CGA" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "CHA" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "CINNI" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "CLAM" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "CNL" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "CNMT" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "CNOTE" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "COMM" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "CON" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "CORG" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "CRYPT" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "CURE" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "CVC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "CYC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "DAO" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "DASH" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "DCR" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "DGB" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "DICE" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "DIEM" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "DIME" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "DIS" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "DNS" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "DOGE" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "DRKC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "DRM" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "DSH" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "DVK" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "EAC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "EBT" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "ECC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "EFL" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "EMC2" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "EMO" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "ENC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "ETC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "ETH" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "eTOK" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "EXE" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "EXP" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "FAC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "FCN" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "FCT" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "FIBRE" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "FLAP" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "FLDC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "FLO" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "FLT" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "FOX" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "FRAC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "FRK" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "FRQ" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "FVZ" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "FZ" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "FZN" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "GAME" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "GAP" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "GAS" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "GDN" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "GEMZ" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "GEO" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "GIAR" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "GLB" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "GML" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "GNS" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "GOLD" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "GPC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "GPUC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "GRC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "GRCX" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "GRS" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "GUE" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "H2O" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "HIRO" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "HOT" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "HUC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "HUGE" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "HVC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "HYP" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "HZ" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "IFC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "INDEX" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "IOC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "ITC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "IXC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "JLH" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "JPC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "JUG" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "KDC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "KEY" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "LBC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "LC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "LCL" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "LEAF" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "LGC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "LOL" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "LOVE" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "LQD" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "LSK" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "LTBC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "LTC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "LTCX" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "MAID" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "MAST" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "MAX" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "MCN" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "MEC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "METH" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "MIL" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "MIN" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "MINT" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "MMC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "MMNXT" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "MMXIV" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "MNTA" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "MON" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "MRC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "MRS" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "MTS" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "MUN" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "MYR" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "MZC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "N5X" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "NAS" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "NAUT" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "NAV" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "NBT" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "NEOS" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "NL" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "NMC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "NOBL" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "NOTE" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "NOXT" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "NRS" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "NSR" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "NTX" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "NXT" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "NXTI" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "OMG" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "OMNI" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "OPAL" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "PAND" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "PASC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "PAWN" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "PIGGY" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "PINK" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "PLX" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "PMC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "POT" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "PPC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "PRC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "PRT" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "PTS" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "Q2C" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "QBK" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "QCN" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "QORA" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "QTL" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "RADS" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "RBY" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "RDD" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "REP" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "RIC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "RZR" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "SBD" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "SC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "SDC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "SHIBE" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "SHOPX" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "SILK" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "SJCX" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "SLR" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "SMC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "SOC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "SPA" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "SQL" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "SRCC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "SRG" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "SSD" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "STEEM" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "STR" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "SUM" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "SUN" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "SWARM" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "SXC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "SYNC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "SYS" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "TAC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "TOR" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "TRUST" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "TWE" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "UIS" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "ULTC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "UNITY" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "URO" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "USDE" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "USDT" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "UTC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "UTIL" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "UVC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "VIA" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "VOOT" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "VOX" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "VRC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "VTC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "WC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "WDC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "WIKI" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "WOLF" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "X13" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "XAI" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "XAP" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "XBC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "XC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "XCH" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "XCN" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "XCP" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "XCR" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "XDN" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "XDP" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "XEM" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "XHC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "XLB" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "XMG" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "XMR" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "XPB" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "XPM" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "XRP" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "XSI" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "XST" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "XSV" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "XUSD" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "XVC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "XXC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "YACC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "YANG" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "YC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "YIN" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "ZEC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "ZRX" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "USDT", + "BTC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "USDT", + "BCH" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "USDT", + "DASH" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "USDT", + "ETC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "USDT", + "ETH" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "USDT", + "LTC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "USDT", + "NXT" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "USDT", + "REP" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "USDT", + "STR" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "USDT", + "XMR" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "USDT", + "XRP" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "USDT", + "ZEC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "ETH", + "CVC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "ETH", + "ETC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "ETH", + "BCH" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "ETH", + "GAS" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "ETH", + "GNO" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "ETH", + "GNT" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "ETH", + "LSK" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "ETH", + "OMG" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "ETH", + "REP" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "ETH", + "STEEM" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "ETH", + "ZEC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "ETH", + "ZRX" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "XMR", + "BCN" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "XMR", + "BLK" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "XMR", + "BTCD" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "XMR", + "DASH" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "XMR", + "LTC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "XMR", + "MAID" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "XMR", + "NXT" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "XMR", + "ZEC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + } + ] +} \ No newline at end of file