diff --git a/.gitignore b/.gitignore
index 7ab8c3a90..6f7be3c13 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,9 +9,6 @@ bin/*
*.cache
node_modules/*
exchange/Auth0.js
-configs/Email.Config.json
-
-configs/User.Profile.json
-configs/Execution.Config.json
-configs/Secret.Keys.json
.env
+
+\.vscode/
diff --git a/Assistant.js b/Assistant.js
index d4fbb4346..7300aa196 100644
--- a/Assistant.js
+++ b/Assistant.js
@@ -1,13 +1,13 @@
exports.newAssistant = function newAssistant(BOT, logger, UTILITIES) {
- /*
+ /*
This module allows trading bots to execute actions on the exchange, and also on its current recorded state.
*/
const MODULE_NAME = "Assistant";
-
+
var nodemailer = require('nodemailer');
let bot = BOT;
@@ -23,25 +23,26 @@
getInvestment: getInvestment,
getProfits: getProfits,
getCombinedProfits: getCombinedProfits,
- getROI: getROI,
+ getROI: getROI,
getMarketRate: getMarketRate,
getTicker: getTicker,
sendMessage: sendMessage,
rememberThis: rememberThis,
remindMeOf: remindMeOf,
- truncDecimals: truncDecimals,
- sendEmail: sendEmail
+ truncDecimals: truncDecimals,
+ sendEmail: sendEmail,
+ addExtraData: addExtraData
};
let utilities = UTILITIES.newCloudUtilities(bot, logger);
let exchangePositions = []; // These are the open positions at the exchange at the account the bot is authorized to use.
- let openPositions = []; // These are the open positions the bot knows it made by itself.
+ let openPositions = []; // These are the open positions the bot knows it made by itself.
let context;
let exchangeAPI;
- let marketRate;
+ let marketRate;
let ticker;
return thisObject;
@@ -99,7 +100,7 @@
if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] initialize -> getMarketRateFromExchange -> onTicker -> Entering function."); }
- if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
+ if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] initialize -> getMarketRateFromExchange -> onTicker -> We could not get the Market Price now."); }
@@ -118,7 +119,7 @@
logger.write(MODULE_NAME, "[ERROR] initialize -> getMarketRateFromExchange -> onTicker -> err = " + err.message);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
- }
+ }
} catch (err) {
logger.write(MODULE_NAME, "[ERROR] initialize -> getMarketRateFromExchange -> err = " + err.message);
@@ -404,7 +405,7 @@
callBack(global.DEFAULT_FAIL_RESPONSE);
}
}
-
+
function ordersExecutionCheck(callBack) {
try {
@@ -533,9 +534,9 @@
if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] ordersExecutionCheck -> loopBody -> getPositionTradesAtExchange -> pPositionId = " + pPositionId); }
/*
-
+
Given one position, we request all the associated trades to it.
-
+
*/
switch (bot.startMode) {
@@ -561,9 +562,9 @@
let thisPosition = context.executionContext.positions[i];
if (thisPosition.id === pPositionId) {
-
+
let feeRate = 0.002; // Default backtesting fee simulation
-
+
let trade = {
id: Math.trunc(Math.random(1) * 1000000),
type: thisPosition.type,
@@ -573,7 +574,7 @@
fee: thisObject.truncDecimals(feeRate).toString(),
date: (new Date()).valueOf()
}
-
+
trades.push(trade);
onResponse(global.DEFAULT_OK_RESPONSE, trades);
@@ -645,11 +646,11 @@
if (global.LOG_CONTROL[MODULE_NAME].logContent === true) { logger.write(MODULE_NAME, "[INFO] ordersExecutionCheck -> loopBody -> confirmOrderWasExecuted -> pTrades = " + JSON.stringify(pTrades)); }
/*
-
+
To confirm everything is ok, we will add all the amounts on trades asociated to the order and
they must be equal to the one on file. Otherwise something very strange could have happened,
in which case we will halt the bot execution.
-
+
*/
let sumAssetA = 0;
@@ -660,7 +661,7 @@
sumAssetA = sumAssetA + thisObject.truncDecimals(trade.amountA);
sumAssetB = sumAssetB + thisObject.truncDecimals(trade.amountB);
}
-
+
sumAssetA = thisObject.truncDecimals(sumAssetA);
sumAssetB = thisObject.truncDecimals(sumAssetB);
@@ -676,9 +677,9 @@
}
/*
-
+
Confirmed that order was executed. Next thing to do is to remember the trades and change its status.
-
+
*/
position.status = "executed";
@@ -715,27 +716,27 @@
if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] ordersExecutionCheck -> loopBody -> confirmOrderWasPartiallyExecuted -> Entering function."); }
/*
-
+
To confirm everything is ok, we will add all the amounts on trades plus the remaining amounts
at the order at the exchange and they must be equal to the one on file. Otherwise an inconsistent
state has been detected, in which case we will halt the bot execution.
-
+
*/
let sumAssetA = 0;
let sumAssetB = 0;
-
+
for (let k = 0; k < pTrades.length; k++) {
let trade = pTrades[k];
sumAssetA = sumAssetA + thisObject.truncDecimals(trade.amountA);
sumAssetB = sumAssetB + thisObject.truncDecimals(trade.amountB);
}
-
+
/* To this we add the current position amounts. */
-
+
sumAssetA = sumAssetA + thisObject.truncDecimals(exchangePosition.amountA);
sumAssetB = sumAssetB + thisObject.truncDecimals(exchangePosition.amountB);
-
+
sumAssetA = thisObject.truncDecimals(sumAssetA);
sumAssetB = thisObject.truncDecimals(sumAssetB);
@@ -759,16 +760,16 @@
logger.write(MODULE_NAME, "[INFO] ordersExecutionCheck -> loopBody -> confirmOrderWasPartiallyExecuted -> sumAssetB = " + sumAssetB);
logger.write(MODULE_NAME, "[ERROR] ordersExecutionCheck -> loopBody -> confirmOrderWasPartiallyExecuted -> Cannot confirm that a partial execution was done well.");
-
+
/* There are diferences on the responses between the getPosition and getTrades that causes some issues, let's retry. */
callBack(global.DEFAULT_RETRY_RESPONSE);
return;
}
/*
-
+
Confirmed that order was partially executed. Next thing to do is to remember the trades and the new position.
-
+
*/
position.amountA = exchangePosition.amountA;
@@ -817,8 +818,8 @@
let assetB = 0;
if (trade.type === 'buy') {
-
- /*
+
+ /*
The fee received at each trade is the factor by which if we multiply asset B, we get the amount of Asset B extracted as fees by the exchange.
This happens with each individual trade. Remeber that one order can potentially be executed with 1 to many trades.
@@ -841,7 +842,7 @@
if (trade.type === 'sell') {
- /*
+ /*
The fee received at each trade is the factor by which if we multiply asset A, we get the amount of Asset A extracted as fees by the exchange.
This happens with each individual trade. Remeber that one order can potentially be executed with 1 to many trades.
@@ -860,7 +861,7 @@
/* Not the available balance for asset B is not affected since it was already reduced when the order was placed. */
- }
+ }
}
} catch (err) {
@@ -1040,7 +1041,7 @@
context.newHistoryRecord.newPositions++;
- recalculateRateAverages();
+ recalculateRateAverages();
/* Recalculate Available Balances */
@@ -1048,7 +1049,7 @@
context.executionContext.availableBalance.assetA = thisObject.truncDecimals(context.executionContext.availableBalance.assetA - pAmountA);
context.newHistoryRecord.lastBuyRate = pRate;
- }
+ }
if (position.type === 'sell') {
@@ -1056,7 +1057,7 @@
context.newHistoryRecord.lastSellRate = pRate;
}
- callBackFunction(global.DEFAULT_OK_RESPONSE);
+ callBackFunction(global.DEFAULT_OK_RESPONSE, position);
return;
}
break;
@@ -1179,9 +1180,9 @@
context.newHistoryRecord.movedPositions++;
- recalculateRateAverages();
+ recalculateRateAverages();
- callBackFunction(global.DEFAULT_OK_RESPONSE);
+ callBackFunction(global.DEFAULT_OK_RESPONSE, newPosition);
}
break;
case global.DEFAULT_RETRY_RESPONSE.result: { // Something bad happened, but if we retry in a while it might go through the next time.
@@ -1316,7 +1317,7 @@
return JSON.parse(JSON.stringify(ROI));
}
-
+
function getMarketRate() {
return marketRate;
}
@@ -1357,10 +1358,15 @@
return context.executionContext.remember[pKey];
}
-
+
function sendEmail(pTitle, pBody, pTo) {
logger.write(MODULE_NAME, "[WARN] sendEmail -> Send emails is currently disabled.");
- return;
+ return;
+ }
+
+ function addExtraData(pExtraDataArray) {
+
+ context.extraData = pExtraDataArray;
}
function truncDecimals(pFloatValue, pDecimals) {
@@ -1370,4 +1376,4 @@
return parseFloat(parseFloat(pFloatValue).toFixed(pDecimals));
}
-};
\ No newline at end of file
+};
diff --git a/AACloud.sln b/CloneExecutor.sln
similarity index 100%
rename from AACloud.sln
rename to CloneExecutor.sln
diff --git a/CloudRequire.js b/CloudRequire.js
index 1597614d5..7bc874962 100644
--- a/CloudRequire.js
+++ b/CloudRequire.js
@@ -38,7 +38,28 @@
let USER_BOT_MODULE = {};
USER_BOT_MODULE.newUserBot = eval(text);
- callBackFunction(global.DEFAULT_OK_RESPONSE, USER_BOT_MODULE);
+ /*
+ This following code is to load the bot code from a file on the file system.
+ It is useful for when you are activelly changing the code and dont wont to upload it to the storage at every run
+ */
+
+ /*
+ let fs = require('fs');
+ try {
+ let fileName = "C:/Users/Luis/source/repos/Bots/AAMasters/AAChris-Indicator-Bot/Multi-Period-Daily/User.Bot.js";
+ fs.readFile(fileName, onFileRead);
+
+ function onFileRead(err, file) {
+ let fileString = file.toString();
+ USER_BOT_MODULE.newUserBot = eval(fileString);
+ callBackFunction(global.DEFAULT_OK_RESPONSE, USER_BOT_MODULE);
+ }
+ }
+ catch(err) {
+ console.log("ERROR LOADING FILE FROM FILE SYSTEM");
+ }
+ */
+ callBackFunction(global.DEFAULT_OK_RESPONSE, USER_BOT_MODULE); // Coment this when loading from file system.
} catch (err) {
logger.write(MODULE_NAME, "[ERROR] downloadBot -> onFileReceived -> err.message = " + err.message);
diff --git a/Context.js b/Context.js
index df5cd196f..1d272378a 100644
--- a/Context.js
+++ b/Context.js
@@ -45,7 +45,8 @@
messageBody: ""
},
initialize: initialize,
- saveThemAll: saveThemAll
+ saveThemAll: saveThemAll,
+ extraData: []
};
/*
@@ -492,7 +493,9 @@
thisObject.newHistoryRecord.messageBody
];
- thisObject.executionHistory.push(newRecord);
+ let recordWithExtraData = newRecord.concat(thisObject.extraData);
+
+ thisObject.executionHistory.push(recordWithExtraData);
let fileContent = JSON.stringify(thisObject.executionHistory);
diff --git a/DataDependencies.js b/DataDependencies.js
index db08c5a77..df98108cc 100644
--- a/DataDependencies.js
+++ b/DataDependencies.js
@@ -9,6 +9,7 @@
let ownerBot; // This is the bot owner of the Data Set.
let thisObject = {
+ config: undefined,
dataSets: new Map(),
initialize: initialize,
keys: []
@@ -23,6 +24,15 @@
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] initialize -> Entering function."); }
+ thisObject.config = pDataDependenciesConfig;
+
+ if (thisObject.config === undefined) {
+
+ // We allow old indicators not to declare their data dependencies.
+
+ callBackFunction(global.DEFAULT_OK_RESPONSE);
+ return;
+ }
/*
For each dependency declared at the bot config, we will initialize a DataSet as part of this initialization process.
@@ -31,11 +41,11 @@
let alreadyCalledBack = false;
let addCount = 0;
- for (let i = 0; i < pDataDependenciesConfig.length; i++) {
+ for (let i = 0; i < thisObject.config.length; i++) {
let dataSetModule = DATA_SET.newDataSet(BOT, logger, BLOB_STORAGE, UTILITIES);
- dataSetModule.initialize(pDataDependenciesConfig[i], onInitilized);
+ dataSetModule.initialize(thisObject.config[i], onInitilized);
function onInitilized(err) {
@@ -58,14 +68,14 @@
let key;
- key = pDataDependenciesConfig[i].devTeam + "-" + pDataDependenciesConfig[i].bot + "-" + pDataDependenciesConfig[i].product + "-" + pDataDependenciesConfig[i].dataSet + "-" + pDataDependenciesConfig[i].dataSetVersion;
+ key = thisObject.config[i].devTeam + "-" + thisObject.config[i].bot + "-" + thisObject.config[i].product + "-" + thisObject.config[i].dataSet + "-" + thisObject.config[i].dataSetVersion;
thisObject.keys.push(key);
thisObject.dataSets.set(key, dataSetModule);
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] initialize -> addDataSet -> DataSet added to Map. -> key = " + key); }
- if (addCount === pDataDependenciesConfig.length) {
+ if (addCount === thisObject.config.length) {
if (alreadyCalledBack === false) {
callBackFunction(global.DEFAULT_OK_RESPONSE);
return;
diff --git a/DataSet.js b/DataSet.js
index 074135d0a..215137939 100644
--- a/DataSet.js
+++ b/DataSet.js
@@ -5,7 +5,6 @@
let bot = BOT;
let thisObject = {
- file: undefined, // Here we have the JSON object representing the file content.
initialize: initialize,
getTextFile: getTextFile,
createTextFile: createTextFile
diff --git a/DebugLog.js b/DebugLog.js
index 70adf7be0..d4b23743f 100644
--- a/DebugLog.js
+++ b/DebugLog.js
@@ -42,7 +42,7 @@
function newInternalLoop(pBot, pProcess) {
- console.log(new Date().toISOString() + " " + strPad(pBot, 20) + " " + strPad(pProcess, 30) + " Entered into Internal Loop # " + strPad(internalLoopCounter + 1, 4));
+ console.log(new Date().toISOString() + " " + strPad(pBot, 20) + " " + strPad(pProcess, 30) + " Entered into Internal Loop # " + strPad(internalLoopCounter + 1, 4) + " bot.processDatetime = " + thisObject.bot.processDatetime.toISOString());
persist();
@@ -60,13 +60,6 @@
internalLoopCounter++;
- if (global.CURRENT_EXECUTION_AT === "Browser") {
-
- //console.log("[INFO] DebugLog -> persist -> We do not persist logs while running at the Browser");
- return;
-
- }
-
let contentToPersist = accumulatedLog;
accumulatedLog = "[";
@@ -149,28 +142,20 @@
if (global.CURRENT_EXECUTION_AT === "IDE") {
- console.log("AACloud" + spacePad(pModule, 50) + " : " + pMessage);
+ console.log("CloneExecutor" + spacePad(pModule, 50) + " : " + pMessage);
}
if (disableLogging === true) { return; }
- if (global.CURRENT_EXECUTION_AT === "Browser") {
-
- /* Only at the browser we send the messages to the console. At the Cloud it does not make sense. */
-
- console.log("AACloud" + spacePad(pModule, 50) + " : " + pMessage);
- return;
- }
-
- if (global.CURRENT_EXECUTION_AT === "Cloud") {
+ if (global.CURRENT_EXECUTION_AT === "Node") {
/* Only ERRORs go to the cloud console. */
if (pMessage.indexOf("[ERROR]") >= 0) {
let now = new Date;
- console.log("Loop." + pad(thisObject.bot.loopCounter, 8) + " " + now.toUTCString() + " AACloud " + spacePad(pModule, 20) + " : " + pMessage);
+ console.log("Loop." + pad(thisObject.bot.loopCounter, 8) + " " + now.toUTCString() + " CloneExecutor " + spacePad(pModule, 20) + " : " + pMessage);
}
}
diff --git a/Exchange/ExchangeAPI.js b/Exchange/ExchangeAPI.js
deleted file mode 100644
index 2ad5eddfd..000000000
--- a/Exchange/ExchangeAPI.js
+++ /dev/null
@@ -1,301 +0,0 @@
-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
deleted file mode 100644
index 853d6d825..000000000
--- a/Exchange/exchangeUtils.js
+++ /dev/null
@@ -1,100 +0,0 @@
-// 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
deleted file mode 100644
index 5e5e6a051..000000000
--- a/Exchange/wrappers/beautifier.js
+++ /dev/null
@@ -1,183 +0,0 @@
-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
deleted file mode 100644
index 624c0fc06..000000000
--- a/Exchange/wrappers/binance.js
+++ /dev/null
@@ -1,368 +0,0 @@
-// 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
deleted file mode 100644
index a46ca7d24..000000000
--- a/Exchange/wrappers/binanceClient.js
+++ /dev/null
@@ -1,360 +0,0 @@
-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
deleted file mode 100644
index ad4438de0..000000000
--- a/Exchange/wrappers/binanceProperties.json
+++ /dev/null
@@ -1,4594 +0,0 @@
-{
- "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
deleted file mode 100644
index 9a1a32b41..000000000
--- a/Exchange/wrappers/poloniex.js
+++ /dev/null
@@ -1,440 +0,0 @@
-// 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
deleted file mode 100644
index 7476728c1..000000000
--- a/Exchange/wrappers/poloniexClient.js
+++ /dev/null
@@ -1,353 +0,0 @@
-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
deleted file mode 100644
index a5716ba3b..000000000
--- a/Exchange/wrappers/poloniexProperties.json
+++ /dev/null
@@ -1,3513 +0,0 @@
-{
- "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
diff --git a/IndicatorBotProcessMainLoop.js b/IndicatorBotProcessMainLoop.js
index 5ed0969df..f9c58dd20 100644
--- a/IndicatorBotProcessMainLoop.js
+++ b/IndicatorBotProcessMainLoop.js
@@ -9,6 +9,8 @@
let COMMONS_MODULE;
const BLOB_STORAGE = require(ROOT_DIR + 'BlobStorage');
+ const MULTI_PERIOD_MARKET = require(ROOT_DIR + 'MultiPeriodMarket');
+ const MULTI_PERIOD_DAILY = require(ROOT_DIR + 'MultiPeriodDaily');
const DEBUG_MODULE = require(ROOT_DIR + 'DebugLog');
let logger; // We need this here in order for the loopHealth function to work and be able to rescue the loop when it gets in trouble.
@@ -48,25 +50,10 @@
let filePath;
- switch (global.CURRENT_EXECUTION_AT) { // This is what determines if the bot is loaded from the devTeam or an endUser copy.
- case "Cloud": {
- if (global.RUN_AS_TEAM) {
- filePath = global.DEV_TEAM + "/" + "bots" + "/" + bot.repo + "/" + pProcessConfig.name; // DevTeams bots only are run at the cloud.
- } else {
- filePath = global.DEV_TEAM + "/" + "members" + "/" + global.USER_LOGGED_IN + "/" + global.CURRENT_BOT_REPO + "/" + pProcessConfig.name; // DevTeam Members bots only are run at the browser.
- }
- break;
- }
- case "Browser": {
- filePath = global.DEV_TEAM + "/" + "members" + "/" + global.USER_LOGGED_IN + "/" + global.CURRENT_BOT_REPO + "/" + pProcessConfig.name; // DevTeam Members bots only are run at the browser.
- break;
- }
- default: {
- parentLogger.write(MODULE_NAME, "[ERROR] initialize -> onInizialized -> CURRENT_EXECUTION_AT must be either 'Cloud' or 'Browser'.");
- parentLogger.write(MODULE_NAME, "[ERROR] initialize -> onInizialized -> global.CURRENT_EXECUTION_AT = " + global.CURRENT_EXECUTION_AT);
- callBackFunction(global.DEFAULT_FAIL_RESPONSE);
- return;
- }
+ if (global.RUN_AS_TEAM) {
+ filePath = global.DEV_TEAM + "/" + "bots" + "/" + bot.repo + "/" + pProcessConfig.name; // DevTeams bots only are run at the cloud.
+ } else {
+ filePath = global.DEV_TEAM + "/" + "members" + "/" + global.USER_LOGGED_IN + "/" + global.CURRENT_BOT_REPO + "/" + pProcessConfig.name; // DevTeam Members bots only are run at the browser.
}
const CLOUD_REQUIRE = require(ROOT_DIR + 'CloudRequire');
@@ -85,22 +72,7 @@
USER_BOT_MODULE = pMODULE;
- switch (global.CURRENT_EXECUTION_AT) {
- case "Cloud": {
- filePath = global.DEV_TEAM + "/" + "bots" + "/" + bot.repo;
- break;
- }
- case "Browser": {
- filePath = global.DEV_TEAM + "/" + "members" + "/" + global.USER_LOGGED_IN + "/" + global.CURRENT_BOT_REPO;
- break;
- }
- default: {
- parentLogger.write(MODULE_NAME, "[ERROR] initialize -> onInizialized -> onBotDownloaded -> CURRENT_EXECUTION_AT must be either 'Cloud' or 'Browser'.");
- parentLogger.write(MODULE_NAME, "[ERROR] initialize -> onInizialized -> onBotDownloaded -> global.CURRENT_EXECUTION_AT = " + global.CURRENT_EXECUTION_AT);
- callBackFunction(global.DEFAULT_FAIL_RESPONSE);
- return;
- }
- }
+ filePath = global.DEV_TEAM + "/" + "bots" + "/" + bot.repo;
cloudRequire.downloadCommons(cloudStorage, filePath, onCommonsDownloaded);
@@ -175,6 +147,8 @@
const UTILITIES = require(ROOT_DIR + 'CloudUtilities');
const STATUS_REPORT = require(ROOT_DIR + 'StatusReport');
const STATUS_DEPENDENCIES = require(ROOT_DIR + 'StatusDependencies');
+ const DATA_DEPENDENCIES = require(ROOT_DIR + 'DataDependencies');
+ const DATA_SET = require(ROOT_DIR + 'DataSet');
/* We define the datetime for the process that we are running now. This will be the official processing time for both the infraestructure and the bot. */
@@ -182,13 +156,15 @@
/* High level log entry */
- console.log(bot.processDatetime.toISOString() + " " + pad(bot.codeName, 20) + " " + pad(bot.process, 30) + " " + pad(pMonth, 2) + "/" + pad(pYear, 4)
- + " Entered into Main Loop # " + pad(Number(bot.loopCounter), 8));
+ console.log(new Date().toISOString() + " " + pad(bot.codeName, 20) + " " + pad(bot.process, 30) + " " + pad(pMonth, 2) + "/" + pad(pYear, 4)
+ + " Entered into Main Loop # " + pad(Number(bot.loopCounter), 8) + " bot.processDatetime = " + bot.processDatetime.toISOString());
/* We will prepare first the infraestructure needed for the bot to run. There are 3 modules we need to sucessfullly initialize first. */
let userBot;
+ let processFramework;
let statusDependencies;
+ let dataDependencies;
let nextWaitTime;
@@ -213,7 +189,7 @@
switch (err.result) {
case global.DEFAULT_OK_RESPONSE.result: {
logger.write(MODULE_NAME, "[INFO] run -> loop -> initializeStatusDependencies -> onInizialized -> Execution finished well.");
- initializeUserBot();
+ initializeDataDependencies();
return;
}
case global.DEFAULT_RETRY_RESPONSE.result: { // Something bad happened, but if we retry in a while it might go through the next time.
@@ -269,6 +245,109 @@
}
}
+ function initializeDataDependencies() {
+
+ try {
+
+ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> initializeDataDependencies -> Entering function."); }
+
+ dataDependencies = DATA_DEPENDENCIES.newDataDependencies(bot, logger, DATA_SET, BLOB_STORAGE, UTILITIES);
+
+ dataDependencies.initialize(processConfig.dataDependencies, onInizialized);
+
+ function onInizialized(err) {
+
+ try {
+
+ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> initializeDataDependencies -> onInizialized -> Entering function."); }
+
+ switch (err.result) {
+ case global.DEFAULT_OK_RESPONSE.result: {
+ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> initializeDataDependencies -> onInizialized -> Execution finished well."); }
+
+ /* If the process is configured to run inside a framework, we continue there, otherwise we run the bot directly. */
+ if (processConfig.framework === undefined) {
+ initializeUserBot();
+ return;
+ }
+
+ switch (processConfig.framework.name) {
+ case 'Multi-Period-Market': {
+ processFramework = MULTI_PERIOD_MARKET.newMultiPeriodMarket(bot, logger, COMMONS_MODULE, UTILITIES, BLOB_STORAGE, USER_BOT_MODULE, COMMONS_MODULE);
+ intitializeProcessFramework();
+ break;
+ }
+ case 'Multi-Period-Daily': {
+ processFramework = MULTI_PERIOD_DAILY.newMultiPeriodDaily(bot, logger, COMMONS_MODULE, UTILITIES, BLOB_STORAGE, USER_BOT_MODULE, COMMONS_MODULE);
+ intitializeProcessFramework();
+ break;
+ }
+ default: {
+ logger.write(MODULE_NAME, "[ERROR] run -> loop -> initializeDataDependencies -> onInizialized -> Process Framework not Supported.");
+ logger.write(MODULE_NAME, "[ERROR] run -> loop -> initializeDataDependencies -> onInizialized -> Process Framework Name = " + processConfig.framework.name);
+ logger.persist();
+ clearInterval(fixedTimeLoopIntervalHandle);
+ clearTimeout(nextLoopTimeoutHandle);
+ clearTimeout(checkLoopHealthHandle);
+ bot.enableCheckLoopHealth = false;
+ callBackFunction(err);
+ return;
+ }
+ }
+ return;
+ }
+ case global.DEFAULT_RETRY_RESPONSE.result: { // Something bad happened, but if we retry in a while it might go through the next time.
+ logger.write(MODULE_NAME, "[ERROR] run -> loop -> initializeDataDependencies -> onInizialized -> Retry Later. Requesting Execution Retry.");
+ nextWaitTime = 'Retry';
+ loopControl(nextWaitTime);
+ return;
+ }
+ case global.DEFAULT_FAIL_RESPONSE.result: { // This is an unexpected exception that we do not know how to handle.
+ logger.write(MODULE_NAME, "[ERROR] run -> loop -> initializeDataDependencies -> onInizialized -> Operation Failed. Aborting the process.");
+ logger.persist();
+ clearInterval(fixedTimeLoopIntervalHandle);
+ clearTimeout(nextLoopTimeoutHandle);
+ clearTimeout(checkLoopHealthHandle);
+ bot.enableCheckLoopHealth = false;
+ callBackFunction(err);
+ return;
+ }
+ default: {
+ logger.write(MODULE_NAME, "[ERROR] run -> loop -> initializeDataDependencies -> onInizialized -> Unhandled err.result received. -> err.result = " + err.result);
+ logger.write(MODULE_NAME, "[ERROR] run -> loop -> initializeDataDependencies -> onInizialized -> Unhandled err.result received. -> err.message = " + err.message);
+
+ logger.persist();
+ clearInterval(fixedTimeLoopIntervalHandle);
+ clearTimeout(nextLoopTimeoutHandle);
+ clearTimeout(checkLoopHealthHandle);
+ bot.enableCheckLoopHealth = false;
+ callBackFunction(global.DEFAULT_FAIL_RESPONSE);
+ return;
+ }
+ }
+
+ } catch (err) {
+ logger.write(MODULE_NAME, "[ERROR] run -> loop -> initializeDataDependencies -> onInizialized -> err = " + err.message);
+ logger.persist();
+ clearInterval(fixedTimeLoopIntervalHandle);
+ clearTimeout(nextLoopTimeoutHandle);
+ clearTimeout(checkLoopHealthHandle);
+ bot.enableCheckLoopHealth = false;
+ callBackFunction(err);
+ }
+ }
+
+ } catch (err) {
+ logger.write(MODULE_NAME, "[ERROR] run -> loop -> initializeDataDependencies -> err = " + err.message);
+ logger.persist();
+ clearInterval(fixedTimeLoopIntervalHandle);
+ clearTimeout(nextLoopTimeoutHandle);
+ clearTimeout(checkLoopHealthHandle);
+ bot.enableCheckLoopHealth = false;
+ callBackFunction(err);
+ }
+ }
+
function initializeUserBot() {
try {
@@ -500,6 +579,235 @@
}
}
+ function intitializeProcessFramework() {
+
+ try {
+
+ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> intitializeProcessFramework -> Entering function."); }
+
+ processFramework.initialize(processConfig, statusDependencies, dataDependencies, onInizialized, dataDependencies);
+
+ function onInizialized(err) {
+
+ try {
+
+ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> intitializeProcessFramework -> onInizialized -> Entering function."); }
+
+ switch (err.result) {
+ case global.DEFAULT_OK_RESPONSE.result: {
+ logger.write(MODULE_NAME, "[INFO] run -> loop -> intitializeProcessFramework -> onInizialized -> Execution finished well.");
+ startProcessFramework();
+ return;
+ }
+ case global.DEFAULT_RETRY_RESPONSE.result: { // Something bad happened, but if we retry in a while it might go through the next time.
+ logger.write(MODULE_NAME, "[ERROR] run -> loop -> intitializeProcessFramework -> onInizialized -> Retry Later. Requesting Execution Retry.");
+ nextWaitTime = 'Retry';
+ loopControl(nextWaitTime);
+ return;
+ }
+ case global.DEFAULT_FAIL_RESPONSE.result: { // This is an unexpected exception that we do not know how to handle.
+ logger.write(MODULE_NAME, "[ERROR] run -> loop -> intitializeProcessFramework -> onInizialized -> Operation Failed. Aborting the process.");
+ logger.persist();
+ clearInterval(fixedTimeLoopIntervalHandle);
+ clearTimeout(nextLoopTimeoutHandle);
+ clearTimeout(checkLoopHealthHandle);
+ bot.enableCheckLoopHealth = false;
+ callBackFunction(err);
+ return;
+ }
+ case global.CUSTOM_OK_RESPONSE.result: {
+
+ switch (err.message) {
+ case "Too far in the future.": {
+ logger.write(MODULE_NAME, "[WARN] run -> loop -> intitializeProcessFramework -> onInizialized > Too far in the future. This Loop will enter in coma.");
+ nextWaitTime = 'Coma';
+ loopControl(nextWaitTime);
+ return;
+ }
+ case "Not needed now, but soon.": {
+ logger.write(MODULE_NAME, "[WARN] run -> loop -> intitializeProcessFramework -> onInizialized > Not needed now, but soon. This Loop will continue with Normal wait time.");
+ nextWaitTime = 'Normal';
+ loopControl(nextWaitTime);
+ return;
+ }
+ default: {
+ logger.write(MODULE_NAME, "[ERROR] run -> loop -> intitializeProcessFramework -> onInizialized > Unhandled custom response received. -> err.message = " + err.message);
+ logger.persist();
+ clearInterval(fixedTimeLoopIntervalHandle);
+ clearTimeout(nextLoopTimeoutHandle);
+ clearTimeout(checkLoopHealthHandle);
+ bot.enableCheckLoopHealth = false;
+ callBackFunction(err);
+ return;
+ }
+ }
+ }
+ default: {
+ logger.write(MODULE_NAME, "[ERROR] run -> loop -> intitializeProcessFramework -> onInizialized -> Unhandled err.result received. -> err.result = " + err.result);
+ logger.write(MODULE_NAME, "[ERROR] run -> loop -> intitializeProcessFramework -> onInizialized -> Unhandled err.result received. -> err.message = " + err.message);
+
+ logger.persist();
+ clearInterval(fixedTimeLoopIntervalHandle);
+ clearTimeout(nextLoopTimeoutHandle);
+ clearTimeout(checkLoopHealthHandle);
+ bot.enableCheckLoopHealth = false;
+ callBackFunction(global.DEFAULT_FAIL_RESPONSE);
+ return;
+ }
+ }
+
+ } catch (err) {
+ logger.write(MODULE_NAME, "[ERROR] run -> loop -> intitializeProcessFramework -> onInizialized -> err = " + err.message);
+ logger.persist();
+ clearInterval(fixedTimeLoopIntervalHandle);
+ clearTimeout(nextLoopTimeoutHandle);
+ clearTimeout(checkLoopHealthHandle);
+ bot.enableCheckLoopHealth = false;
+ callBackFunction(err);
+ }
+ }
+
+ } catch (err) {
+ logger.write(MODULE_NAME, "[ERROR] run -> loop -> intitializeProcessFramework -> err = " + err.message);
+ logger.persist();
+ clearInterval(fixedTimeLoopIntervalHandle);
+ clearTimeout(nextLoopTimeoutHandle);
+ clearTimeout(checkLoopHealthHandle);
+ bot.enableCheckLoopHealth = false;
+ callBackFunction(err);
+ }
+ }
+
+ function startProcessFramework() {
+
+ try {
+
+ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> startProcessFramework -> Entering function."); }
+
+ processFramework.start(onFinished);
+
+ function onFinished(err) {
+
+ try {
+
+ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> startProcessFramework -> onFinished -> Entering function."); }
+
+ switch (err.result) {
+ case global.DEFAULT_OK_RESPONSE.result: {
+ logger.write(MODULE_NAME, "[INFO] run -> loop -> startProcessFramework -> onFinished -> Execution finished well.");
+ nextWaitTime = 'Normal';
+ loopControl(nextWaitTime);
+ return;
+ }
+ case global.DEFAULT_RETRY_RESPONSE.result: { // Something bad happened, but if we retry in a while it might go through the next time.
+ logger.write(MODULE_NAME, "[ERROR] run -> loop -> startProcessFramework -> onFinished -> Retry Later. Requesting Execution Retry.");
+ nextWaitTime = 'Retry';
+ loopControl(nextWaitTime);
+ return;
+ }
+ case global.DEFAULT_FAIL_RESPONSE.result: { // This is an unexpected exception that we do not know how to handle.
+ logger.write(MODULE_NAME, "[ERROR] run -> loop -> startProcessFramework -> onFinished -> Operation Failed. Aborting the process.");
+ logger.persist();
+ clearInterval(fixedTimeLoopIntervalHandle);
+ clearTimeout(nextLoopTimeoutHandle);
+ clearTimeout(checkLoopHealthHandle);
+ bot.enableCheckLoopHealth = false;
+ callBackFunction(err);
+ return;
+ }
+ case global.CUSTOM_OK_RESPONSE.result: {
+
+ switch (err.message) {
+ case "Dependency does not exist.": {
+ logger.write(MODULE_NAME, "[WARN] run -> loop -> startProcessFramework -> onFinished -> Dependency does not exist. This Loop will go to sleep.");
+ nextWaitTime = 'Sleep';
+ loopControl(nextWaitTime);
+ return;
+ }
+ case "Dependency not ready.": {
+ logger.write(MODULE_NAME, "[WARN] run -> loop -> startProcessFramework -> onFinished -> Dependency not ready. This Loop will go to sleep.");
+ nextWaitTime = 'Sleep';
+ loopControl(nextWaitTime);
+ return;
+ }
+ case "Month before it is needed.": {
+ logger.write(MODULE_NAME, "[WARN] run -> loop -> startProcessFramework -> onFinished -> Month before it is needed. This Loop will be terminated.");
+ logger.persist();
+ clearInterval(fixedTimeLoopIntervalHandle);
+ clearTimeout(nextLoopTimeoutHandle);
+ clearTimeout(checkLoopHealthHandle);
+ bot.enableCheckLoopHealth = false;
+ callBackFunction(global.DEFAULT_OK_RESPONSE);
+ return;
+ }
+ case "Month fully processed.": {
+ logger.write(MODULE_NAME, "[WARN] run -> loop -> startProcessFramework -> onFinished -> Month fully processed. This Loop will be terminated.");
+ logger.persist();
+ clearInterval(fixedTimeLoopIntervalHandle);
+ clearTimeout(nextLoopTimeoutHandle);
+ clearTimeout(checkLoopHealthHandle);
+ bot.enableCheckLoopHealth = false;
+ callBackFunction(global.DEFAULT_OK_RESPONSE);
+ return;
+ }
+ case "End of the month reached.": {
+ logger.write(MODULE_NAME, "[WARN] run -> loop -> startProcessFramework -> onFinished -> End of the month reached. This Loop will be terminated.");
+ logger.persist();
+ clearInterval(fixedTimeLoopIntervalHandle);
+ clearTimeout(nextLoopTimeoutHandle);
+ clearTimeout(checkLoopHealthHandle);
+ bot.enableCheckLoopHealth = false;
+ callBackFunction(global.DEFAULT_OK_RESPONSE);
+ return;
+ }
+ default: {
+ logger.write(MODULE_NAME, "[ERROR] run -> loop -> startProcessFramework -> onFinished -> Unhandled custom response received. -> err.message = " + err.message);
+ logger.persist();
+ clearInterval(fixedTimeLoopIntervalHandle);
+ clearTimeout(nextLoopTimeoutHandle);
+ clearTimeout(checkLoopHealthHandle);
+ bot.enableCheckLoopHealth = false;
+ callBackFunction(err);
+ return;
+ }
+ }
+ }
+ default: {
+ logger.write(MODULE_NAME, "[ERROR] run -> loop -> startProcessFramework -> onFinished -> Unhandled err.result received. -> err.result = " + err.result);
+ logger.write(MODULE_NAME, "[ERROR] run -> loop -> startProcessFramework -> onFinished -> Unhandled err.result received. -> err.message = " + err.message);
+
+ logger.persist();
+ clearInterval(fixedTimeLoopIntervalHandle);
+ clearTimeout(nextLoopTimeoutHandle);
+ clearTimeout(checkLoopHealthHandle);
+ bot.enableCheckLoopHealth = false;
+ callBackFunction(global.DEFAULT_FAIL_RESPONSE);
+ return;
+ }
+ }
+
+ } catch (err) {
+ logger.write(MODULE_NAME, "[ERROR] run -> loop -> startProcessFramework -> onFinished -> err = " + err.message);
+ logger.persist();
+ clearInterval(fixedTimeLoopIntervalHandle);
+ clearTimeout(nextLoopTimeoutHandle);
+ clearTimeout(checkLoopHealthHandle);
+ bot.enableCheckLoopHealth = false;
+ callBackFunction(err);
+ }
+ }
+
+ } catch (err) {
+ logger.write(MODULE_NAME, "[ERROR] run -> loop -> startProcessFramework -> err = " + err.message);
+ logger.persist();
+ clearInterval(fixedTimeLoopIntervalHandle);
+ clearTimeout(nextLoopTimeoutHandle);
+ clearTimeout(checkLoopHealthHandle);
+ bot.enableCheckLoopHealth = false;
+ callBackFunction(err);
+ }
+ }
+
function loopControl(nextWaitTime) {
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> loopControl -> Entering function."); }
@@ -560,7 +868,7 @@
function checkLoopHealth(pLastLoop) {
- if (global.CURRENT_EXECUTION_AT !== "Cloud") {
+ if (global.CURRENT_EXECUTION_AT !== "Node") {
return;
}
@@ -610,34 +918,8 @@
if (err.result === global.DEFAULT_OK_RESPONSE.result) {
- let filePath;
-
- switch (global.CURRENT_EXECUTION_AT) { // This is what determines if the bot is loaded from the devTeam or an endUser copy.
- case "Cloud": {
- filePath = global.DEV_TEAM + "/" + "AACloud"; // DevTeams bots only are run at the cloud.
- break;
- }
- case "Browser": {
- if (global.SHALL_BOT_STOP === false) {
- continueCallBack();
- } else {
- stopCallBack();
- }
- return;
- }
- default: {
- logger.write(MODULE_NAME, "[ERROR] run -> loop -> shallWeStop -> onInizialized -> CURRENT_EXECUTION_AT must be either 'Cloud' or 'Browser'.");
- logger.write(MODULE_NAME, "[ERROR] run -> loop -> shallWeStop -> onInizialized -> global.CURRENT_EXECUTION_AT = " + global.CURRENT_EXECUTION_AT);
- logger.persist();
- clearInterval(fixedTimeLoopIntervalHandle);
- clearTimeout(nextLoopTimeoutHandle);
- clearTimeout(checkLoopHealthHandle);
- bot.enableCheckLoopHealth = false;
- callBackFunction(global.DEFAULT_FAIL_RESPONSE);
- return;
- }
- }
-
+ let filePath = global.DEV_TEAM + "/" + "AACloud"; // DevTeams bots only are run at the cloud.
+
let fileName = "this.config.json";
cloudStorage.getTextFile(filePath, fileName, onFileReceived);
diff --git a/Integrations/OperationsModuleIntegration.js b/Integrations/OperationsModuleIntegration.js
index b8de71616..43001d62c 100644
--- a/Integrations/OperationsModuleIntegration.js
+++ b/Integrations/OperationsModuleIntegration.js
@@ -1,13 +1,9 @@
const axios = require('axios')
-const appRoot = require('app-root-path')
-const { logger } = require(`${appRoot}/utils/logger`)
-const auth = require(`${appRoot}/utils/auth`)
+const auth = require('../utils/auth')
exports.updateExecutionResults = async function (summaryDate, buyAverage, sellAverage,
marketRate, combinedProfitsA, combinedProfitsB) {
- logger.debug('updateExecutionResults -> Entering Function.')
-
try {
const accessToken = await auth.authenticate()
@@ -50,12 +46,10 @@ exports.updateExecutionResults = async function (summaryDate, buyAverage, sellAv
}
})
- if (!operationsResponse.data.errors)
- logger.debug('updateExecutionResults -> Operations Module Response: %s', operationsResponse.data.data.operations_UpdateExecutionSummary)
- else throw new Error(operationsResponse.data.errors[0].message)
+ if (operationsResponse.data.errors)
+ throw new Error(operationsResponse.data.errors[0].message)
} catch (error) {
- logger.error('updateExecutionResults -> Error: ' + error.stack)
- throw new Error('There has been an error updating the execution report: ' + error)
+ throw new Error('There has been an error updating the execution on the clone: ' + error)
}
}
\ No newline at end of file
diff --git a/MultiPeriodDaily.js b/MultiPeriodDaily.js
new file mode 100644
index 000000000..4127b0c15
--- /dev/null
+++ b/MultiPeriodDaily.js
@@ -0,0 +1,759 @@
+exports.newMultiPeriodDaily = function newMultiPeriodDaily(bot, logger, COMMONS, UTILITIES, BLOB_STORAGE, USER_BOT_MODULE, COMMONS_MODULE) {
+
+ const FULL_LOG = true;
+ const LOG_FILE_CONTENT = false;
+ const MODULE_NAME = "Multi Period Daily";
+ const commons = COMMONS.newCommons(bot, logger, UTILITIES);
+ const GMT_SECONDS = ':00.000 GMT+0000';
+ const ONE_DAY_IN_MILISECONDS = 24 * 60 * 60 * 1000;
+
+ thisObject = {
+ initialize: initialize,
+ start: start
+ };
+
+ let utilities = UTILITIES.newCloudUtilities(bot, logger);
+
+ let statusDependencies;
+ let dataDependencies;
+ let storages = [];
+ let dataFiles = [];
+
+ let usertBot;
+ let currentBotStorage = BLOB_STORAGE.newBlobStorage(bot, logger);
+
+ let processConfig;
+
+ return thisObject;
+
+ function initialize(pProcessConfig, pStatusDependencies, pDataDependencies, callBackFunction) {
+
+ try {
+
+ logger.fileName = MODULE_NAME;
+ logger.initialize();
+
+ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] initialize -> Entering function."); }
+
+ statusDependencies = pStatusDependencies;
+ dataDependencies = pDataDependencies;
+ processConfig = pProcessConfig;
+
+ for (let i = 0; i < dataDependencies.config.length; i++) {
+
+ let key;
+ let storage;
+ let dependency = dataDependencies.config[i];
+
+ key = dependency.devTeam + "-" +
+ dependency.bot + "-" +
+ dependency.product + "-" +
+ dependency.dataSet + "-" +
+ dependency.dataSetVersion
+
+ storage = dataDependencies.dataSets.get(key);
+
+ storages.push(storage);
+
+ }
+
+ currentBotStorage.initialize(bot.devTeam, onStorageInizialized);
+
+ function onStorageInizialized(err) {
+
+ if (err.result === global.DEFAULT_OK_RESPONSE.result) {
+
+ usertBot = USER_BOT_MODULE.newUserBot(bot, logger, COMMONS_MODULE, UTILITIES, BLOB_STORAGE);
+ usertBot.initialize(dataDependencies, callBackFunction);
+
+ } else {
+ logger.write(MODULE_NAME, "[ERROR] initialize -> onStorageInizialized -> err = " + err.message);
+ callBackFunction(err);
+ }
+ }
+
+ } catch (err) {
+ logger.write(MODULE_NAME, "[ERROR] initialize -> err = " + err.message);
+ callBackFunction(global.DEFAULT_FAIL_RESPONSE);
+ }
+ }
+
+ function start(callBackFunction) {
+
+ try {
+
+ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> Entering function."); }
+
+ let market = global.MARKET;
+
+ /* Context Variables */
+
+ let contextVariables = {
+ lastFile: undefined, // Datetime of the last file files sucessfully produced by this process.
+ dateBeginOfMarket: undefined, // Datetime of the first trade file in the whole market history.
+ dateEndOfMarket: undefined // Datetime of the last file available to be used as an input of this process.
+ };
+
+ let previousDay; // Holds the date of the previous day relative to the processing date.
+
+ let interExecutionMemoryArray;
+
+ getContextVariables();
+
+ function getContextVariables() {
+
+ try {
+
+ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> Entering function."); }
+
+ let thisReport;
+ let reportKey;
+ let statusReport;
+
+ if (processConfig.framework.startDate.fixedDate !== undefined) {
+
+ /* The starting date is fixed, we will start from there. */
+
+ contextVariables.dateBeginOfMarket = new Date(processConfig.framework.startDate.fixedDate);
+
+ } else {
+
+ /*
+ We look first for the bot who knows the begining of the marke in order to get when the market starts.
+ */
+
+ let botWhoKnowsTheBeginingOfTheMarket = statusDependencies.config[processConfig.framework.startDate.takeItFromStatusDependency];
+
+ reportKey = botWhoKnowsTheBeginingOfTheMarket.devTeam + "-" + botWhoKnowsTheBeginingOfTheMarket.bot + "-" + botWhoKnowsTheBeginingOfTheMarket.process + "-" + "dataSet.V1";
+ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> reportKey = " + reportKey); }
+
+ statusReport = statusDependencies.statusReports.get(reportKey);
+
+ if (statusReport === undefined) { // This means the status report does not exist, that could happen for instance at the begining of a month.
+ logger.write(MODULE_NAME, "[WARN] start -> getContextVariables -> Status Report does not exist. Retrying Later. ");
+ callBackFunction(global.DEFAULT_RETRY_RESPONSE);
+ return;
+ }
+
+ if (statusReport.status === "Status Report is corrupt.") {
+ logger.write(MODULE_NAME, "[ERROR] start -> getContextVariables -> Can not continue because dependecy Status Report is corrupt. ");
+ callBackFunction(global.DEFAULT_RETRY_RESPONSE);
+ return;
+ }
+
+ thisReport = statusDependencies.statusReports.get(reportKey).file;
+
+ if (thisReport.lastFile === undefined) {
+ logger.write(MODULE_NAME, "[WARN] start -> getContextVariables -> Undefined Last File. -> reportKey = " + reportKey);
+ logger.write(MODULE_NAME, "[HINT] start -> getContextVariables -> It is too early too run this process since the trade history of the market is not there yet.");
+
+ let customOK = {
+ result: global.CUSTOM_OK_RESPONSE.result,
+ message: "Dependency does not exist."
+ }
+ logger.write(MODULE_NAME, "[WARN] start -> getContextVariables -> customOK = " + customOK.message);
+ callBackFunction(customOK);
+ return;
+ }
+
+ contextVariables.dateBeginOfMarket = new Date(thisReport.lastFile.year + "-" + thisReport.lastFile.month + "-" + thisReport.lastFile.days + " " + thisReport.lastFile.hours + ":" + thisReport.lastFile.minutes + GMT_SECONDS);
+
+ }
+
+ if (processConfig.framework.endDate.fixedDate !== undefined) {
+
+ /* The ending date is fixed, we will end there. */
+
+ contextVariables.dateEndOfMarket = new Date(processConfig.framework.endDate.fixedDate);
+
+ } else {
+
+ /*
+ Here we get the status report from the bot who knows which is the end of the market.
+ */
+
+ let botWhoKnowsTheEndOfTheMarket = statusDependencies.config[processConfig.framework.endDate.takeItFromStatusDependency];
+
+ reportKey = botWhoKnowsTheEndOfTheMarket.devTeam + "-" + botWhoKnowsTheEndOfTheMarket.bot + "-" + botWhoKnowsTheEndOfTheMarket.process + "-" + "dataSet.V1";
+ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> reportKey = " + reportKey); }
+
+ statusReport = statusDependencies.statusReports.get(reportKey);
+
+ if (statusReport === undefined) { // This means the status report does not exist, that could happen for instance at the begining of a month.
+ logger.write(MODULE_NAME, "[WARN] start -> getContextVariables -> Status Report does not exist. Retrying Later. ");
+ callBackFunction(global.DEFAULT_RETRY_RESPONSE);
+ return;
+ }
+
+ if (statusReport.status === "Status Report is corrupt.") {
+ logger.write(MODULE_NAME, "[ERROR] start -> getContextVariables -> Can not continue because dependecy Status Report is corrupt. ");
+ callBackFunction(global.DEFAULT_RETRY_RESPONSE);
+ return;
+ }
+
+ thisReport = statusDependencies.statusReports.get(reportKey).file;
+
+ if (thisReport.lastFile === undefined) {
+ logger.write(MODULE_NAME, "[WARN] start -> getContextVariables -> Undefined Last File. -> reportKey = " + reportKey);
+
+ let customOK = {
+ result: global.CUSTOM_OK_RESPONSE.result,
+ message: "Dependency not ready."
+ }
+ logger.write(MODULE_NAME, "[WARN] start -> getContextVariables -> customOK = " + customOK.message);
+ callBackFunction(customOK);
+ return;
+ }
+
+ contextVariables.dateEndOfMarket = new Date(thisReport.lastFile.valueOf());
+ }
+
+ /* Finally we get our own Status Report. */
+
+ reportKey = bot.devTeam + "-" + bot.codeName + "-" + "Multi-Period-Daily" + "-" + "dataSet.V1";
+ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> reportKey = " + reportKey); }
+
+ statusReport = statusDependencies.statusReports.get(reportKey);
+
+ if (statusReport === undefined) { // This means the status report does not exist, that could happen for instance at the begining of a month.
+ logger.write(MODULE_NAME, "[WARN] start -> getContextVariables -> Status Report does not exist. Retrying Later. ");
+ callBackFunction(global.DEFAULT_RETRY_RESPONSE);
+ return;
+ }
+
+ if (statusReport.status === "Status Report is corrupt.") {
+ logger.write(MODULE_NAME, "[ERROR] start -> getContextVariables -> Can not continue because self dependecy Status Report is corrupt. Aborting Process.");
+ callBackFunction(global.DEFAULT_FAIL_RESPONSE);
+ return;
+ }
+
+ thisReport = statusDependencies.statusReports.get(reportKey).file;
+
+ if (thisReport.lastFile !== undefined) {
+
+ if (bot.hasTheBotJustStarted === true && processConfig.framework.startDate.resumeExecution === "false") {
+
+ startFromBegining();
+ return;
+ }
+
+ contextVariables.lastFile = new Date(thisReport.lastFile);
+ interExecutionMemoryArray = thisReport.interExecutionMemoryArray;
+
+ processTimePeriods();
+ return;
+
+ } else {
+
+ /*
+ In the case when there is no status report, we assume like the last processed file is the one on the date of Begining of Market.
+ */
+
+ startFromBegining();
+ return;
+ }
+
+ function startFromBegining() {
+
+ contextVariables.lastFile = new Date(contextVariables.dateBeginOfMarket.getUTCFullYear() + "-" + (contextVariables.dateBeginOfMarket.getUTCMonth() + 1) + "-" + contextVariables.dateBeginOfMarket.getUTCDate() + " " + "00:00" + GMT_SECONDS);
+
+ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> startFromBegining -> thisReport.lastFile === undefined"); }
+ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> startFromBegining -> contextVariables.lastFile = " + contextVariables.lastFile); }
+
+ /*
+ The first time the process is running is the right time to create the data structure that is going to be shared across different executions.
+ This data structure has one object per each timePeriod.
+ */
+
+ interExecutionMemoryArray = [];
+
+ for (let i = 0; i < global.dailyFilePeriods.length; i++) {
+ let emptyObject = {};
+ interExecutionMemoryArray.push(emptyObject);
+ }
+
+ processTimePeriods();
+
+ }
+
+ } catch (err) {
+ logger.write(MODULE_NAME, "[ERROR] start -> getContextVariables -> err = " + err.message);
+ if (err.message === "Cannot read property 'file' of undefined") {
+ logger.write(MODULE_NAME, "[HINT] start -> getContextVariables -> Check the bot configuration to see if all of its statusDependencies declarations are correct. ");
+ logger.write(MODULE_NAME, "[HINT] start -> getContextVariables -> Dependencies loaded -> keys = " + JSON.stringify(statusDependencies.keys));
+ }
+ callBackFunction(global.DEFAULT_FAIL_RESPONSE);
+ }
+ }
+
+ function processTimePeriods() {
+
+ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> Entering function."); }
+
+ try {
+
+ let n;
+ let botNeverRan = true;
+
+ bot.processDatetime = new Date(contextVariables.lastFile.valueOf() - ONE_DAY_IN_MILISECONDS); // Go back one day to start well when we advance time at the begining of the loop.
+
+ advanceTime();
+
+ function advanceTime() {
+
+ try {
+
+ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> advanceTime -> Entering function."); }
+
+ bot.processDatetime = new Date(bot.processDatetime.valueOf() + ONE_DAY_IN_MILISECONDS);
+ previousDay = new Date(bot.processDatetime.valueOf() - ONE_DAY_IN_MILISECONDS);
+
+ logger.newInternalLoop(bot.codeName, bot.process);
+
+ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> advanceTime -> bot.processDatetime = " + bot.processDatetime); }
+ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> advanceTime -> previousDay = " + previousDay); }
+
+ /* Validation that we are not going past the head of the market. */
+
+ if (bot.processDatetime.valueOf() > contextVariables.dateEndOfMarket.valueOf()) {
+
+ const logText = "Head of the market found @ " + previousDay.getUTCFullYear() + "/" + (previousDay.getUTCMonth() + 1) + "/" + previousDay.getUTCDate() + ".";
+ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> advanceTime -> " + logText); }
+
+ callBackFunction(global.DEFAULT_OK_RESPONSE);
+ return;
+
+ }
+
+ periodsLoop();
+
+ } catch (err) {
+ logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> advanceTime -> err = " + err.message);
+ callBackFunction(global.DEFAULT_FAIL_RESPONSE);
+ }
+ }
+
+ function periodsLoop() {
+
+ try {
+
+ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> periodsLoop -> Entering function."); }
+
+ /*
+
+ We will iterate through all posible periods.
+
+ */
+
+ n = 0 // loop Variable representing each possible period as defined at the periods array.
+
+ periodsLoopBody();
+
+ }
+ catch (err) {
+ logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoop -> err = " + err.message);
+ callBackFunction(global.DEFAULT_FAIL_RESPONSE);
+ }
+ }
+
+ function periodsLoopBody() {
+
+ try {
+
+ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> periodsLoopBody -> Entering function."); }
+
+ const timePeriod = global.dailyFilePeriods[n][0];
+ const outputPeriodLabel = global.dailyFilePeriods[n][1];
+
+ let dependencyIndex = 0;
+ dataFiles = [];
+
+ dependencyLoopBody();
+
+ function dependencyLoopBody() {
+
+ try {
+
+ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> Entering function."); }
+
+ let dependency = dataDependencies.config[dependencyIndex];
+ let storage = storages[dependencyIndex];
+
+ let previousFile;
+ let currentFile;
+
+ if (bot.processDatetime.valueOf() > contextVariables.dateBeginOfMarket.valueOf()) {
+ getPreviousFile();
+ } else {
+ previousFile = [];
+ getCurrentFile()
+ }
+
+ function getPreviousFile() {
+
+ try {
+
+ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getPreviousFile -> Entering function."); }
+
+ let dateForPath = previousDay.getUTCFullYear() + '/' + utilities.pad(previousDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(previousDay.getUTCDate(), 2);
+ let filePath = dependency.product + '/' + "Multi-Period-Daily" + "/" + outputPeriodLabel + "/" + dateForPath;
+ let fileName = market.assetA + '_' + market.assetB + ".json";
+
+ storage.getTextFile(filePath, fileName, onFileReceived, true);
+
+ function onFileReceived(err, text) {
+
+ try {
+
+ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getPreviousFile -> onFileReceived -> Entering function."); }
+ if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getPreviousFile -> onFileReceived -> text = " + text); }
+
+ if (err.message === "File does not exist." && botNeverRan === true) {
+
+ /*
+ Sometimes one of the dependencies of an indicator for some reasons are not calculated from the begining of the market.
+ When that happens we can not find those files. What we do in this situation is to move the time fordward until we can find
+ all the dependencies and the first run of the bot is successful.
+
+ After that, we will not accept more missing files on any of the dependencies, and if any is missing we will abort the processing.
+ */
+ logger.write(MODULE_NAME, "[WARN] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getPreviousFile -> onFileReceived -> Skipping day because file " + filePath + "/" + fileName + " was not found.");
+
+ advanceTime();
+ return;
+ }
+
+ if (err.result === "Fail Because" && err.message === "File does not exist.") {
+
+ logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getCurrentFile -> onFileReceived -> err = " + err.message);
+ logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getCurrentFile -> onFileReceived -> filePath = " + filePath);
+ logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getCurrentFile -> onFileReceived -> fileName = " + fileName);
+ callBackFunction(global.DEFAULT_RETRY_RESPONSE);
+ return;
+ }
+
+ if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
+
+ logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getPreviousFile -> onFileReceived -> err = " + err.message);
+ logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getPreviousFile -> onFileReceived -> filePath = " + filePath);
+ logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getPreviousFile -> onFileReceived -> fileName = " + fileName);
+ callBackFunction(err);
+ return;
+ }
+
+ previousFile = JSON.parse(text);
+
+ getCurrentFile();
+
+ }
+ catch (err) {
+ logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getPreviousFile -> onFileReceived -> err = " + err.message);
+ callBackFunction(global.DEFAULT_FAIL_RESPONSE);
+ }
+ }
+ }
+ catch (err) {
+ logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getPreviousFile -> err = " + err.message);
+ callBackFunction(global.DEFAULT_FAIL_RESPONSE);
+ }
+ }
+
+ function getCurrentFile() {
+
+ try {
+
+ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getCurrentFile -> Entering function."); }
+
+ let dateForPath = bot.processDatetime.getUTCFullYear() + '/' + utilities.pad(bot.processDatetime.getUTCMonth() + 1, 2) + '/' + utilities.pad(bot.processDatetime.getUTCDate(), 2);
+ let filePath = dependency.product + '/' + "Multi-Period-Daily" + "/" + outputPeriodLabel + "/" + dateForPath;
+ let fileName = market.assetA + '_' + market.assetB + ".json";
+
+ storage.getTextFile(filePath, fileName, onFileReceived, true);
+
+ function onFileReceived(err, text) {
+
+ try {
+
+ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getCurrentFile -> onFileReceived -> Entering function."); }
+ if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getCurrentFile -> onFileReceived -> text = " + text); }
+
+ if (err.result === "Fail Because" && err.message === "File does not exist.") {
+
+ logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getCurrentFile -> onFileReceived -> err = " + err.message);
+ logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getCurrentFile -> onFileReceived -> filePath = " + filePath);
+ logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getCurrentFile -> onFileReceived -> fileName = " + fileName);
+ callBackFunction(global.DEFAULT_RETRY_RESPONSE);
+ return;
+ }
+
+ if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
+
+ logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getCurrentFile -> onFileReceived -> err = " + err.message);
+ logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getCurrentFile -> onFileReceived -> filePath = " + filePath);
+ logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getCurrentFile -> onFileReceived -> fileName = " + fileName);
+ callBackFunction(err);
+ return;
+ }
+
+ currentFile = JSON.parse(text);
+
+ let dataFile = previousFile.concat(currentFile);
+
+ dataFiles.push(dataFile);
+ dependencyControlLoop();
+
+ }
+ catch (err) {
+ logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getCurrentFile -> onFileReceived -> err = " + err.message);
+ callBackFunction(global.DEFAULT_FAIL_RESPONSE);
+ }
+ }
+ }
+ catch (err) {
+ logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getCurrentFile -> err = " + err.message);
+ callBackFunction(global.DEFAULT_FAIL_RESPONSE);
+ }
+ }
+ }
+ catch (err) {
+ logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoop -> dependencyLoopBody -> err = " + err.message);
+ callBackFunction(global.DEFAULT_FAIL_RESPONSE);
+ }
+ }
+
+ function dependencyControlLoop() {
+
+ try {
+
+ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> dependencyControlLoop -> Entering function."); }
+
+ dependencyIndex++;
+
+ if (dependencyIndex < dataDependencies.config.length) {
+
+ dependencyLoopBody();
+
+ } else {
+
+ callTheBot();
+
+ }
+ }
+ catch (err) {
+ logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> dependencyControlLoop -> err = " + err.message);
+ callBackFunction(global.DEFAULT_FAIL_RESPONSE);
+ }
+ }
+
+ function callTheBot() {
+
+ try {
+
+ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> periodsLoopBody -> callTheBot -> Entering function."); }
+
+ const timePeriod = global.dailyFilePeriods[n][0];
+ const outputPeriodLabel = global.dailyFilePeriods[n][1];
+
+ usertBot.start(
+ dataFiles,
+ timePeriod,
+ outputPeriodLabel,
+ bot.processDatetime,
+ contextVariables.dateBeginOfMarket,
+ contextVariables.dateEndOfMarket,
+ interExecutionMemoryArray[n],
+ onBotFinished);
+
+ function onBotFinished(err) {
+
+ try {
+
+ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> periodsLoopBody -> callTheBot -> onBotFinished -> Entering function."); }
+
+ if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
+
+ callBackFunction(err);
+ return;
+ }
+
+ botNeverRan = false;
+ periodsControlLoop();
+ }
+ catch (err) {
+ logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> callTheBot -> onBotFinished -> err = " + err.message);
+ callBackFunction(global.DEFAULT_FAIL_RESPONSE);
+ }
+ }
+ }
+ catch (err) {
+ logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> callTheBot -> err = " + err.message);
+ callBackFunction(global.DEFAULT_FAIL_RESPONSE);
+ }
+ }
+ }
+ catch (err) {
+ logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> err = " + err.message);
+ callBackFunction(global.DEFAULT_FAIL_RESPONSE);
+ }
+ }
+
+ function periodsControlLoop() {
+
+ try {
+
+ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> periodsControlLoop -> Entering function."); }
+
+ n++;
+
+ if (n < global.dailyFilePeriods.length) {
+
+ periodsLoopBody();
+
+ } else {
+
+ n = 0;
+
+ writeDataRanges(onWritten);
+
+ function onWritten(err) {
+
+ try {
+
+ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> controlLoop -> onWritten -> Entering function."); }
+
+ if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
+ logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> controlLoop -> onWritten -> err = " + err.message);
+ callBackFunction(err);
+ return;
+ }
+
+ writeStatusReport(bot.processDatetime, advanceTime);
+
+ } catch (err) {
+ logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> controlLoop -> onWritten -> err = " + err.message);
+ callBackFunction(global.DEFAULT_FAIL_RESPONSE);
+ }
+ }
+ }
+ }
+ catch (err) {
+ logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsControlLoop -> err = " + err.message);
+ callBackFunction(global.DEFAULT_FAIL_RESPONSE);
+ }
+ }
+
+ }
+ catch (err) {
+ logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> err = " + err.message);
+ callBackFunction(global.DEFAULT_FAIL_RESPONSE);
+ }
+ }
+
+ function writeDataRanges(callBack) {
+
+ try {
+
+ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDataRanges -> Entering function."); }
+
+ let productIndex = 0;
+ productLoopBody();
+
+ function productLoopBody() {
+
+ let folderName = bot.products[productIndex].codeName;
+
+ writeDataRange(contextVariables.dateBeginOfMarket, bot.processDatetime, folderName, controlLoop);
+ }
+
+ function controlLoop() {
+
+ productIndex++;
+
+ if (productIndex < bot.products.length) {
+ productLoopBody();
+ } else {
+ callBack(global.DEFAULT_OK_RESPONSE);
+ }
+ }
+ }
+ catch (err) {
+ logger.write(MODULE_NAME, "[ERROR] start -> writeDataRanges -> err = " + err.message);
+ callBack(global.DEFAULT_FAIL_RESPONSE);
+ }
+
+ }
+
+ function writeDataRange(pBegin, pEnd, pProductFolder, callBack) {
+
+ try {
+
+ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDataRange -> Entering function."); }
+
+ let dataRange = {
+ begin: pBegin.valueOf(),
+ end: pEnd.valueOf()
+ };
+
+ let fileContent = JSON.stringify(dataRange);
+
+ let fileName = 'Data.Range.' + market.assetA + '_' + market.assetB + '.json';
+ let filePath = bot.filePathRoot + "/Output/" + pProductFolder + "/" + bot.process;
+
+ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDataRange -> fileName = " + fileName); }
+ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDataRange -> filePath = " + filePath); }
+
+ currentBotStorage.createTextFile(filePath, fileName, fileContent + '\n', onFileCreated);
+
+ function onFileCreated(err) {
+
+ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDataRange -> onFileCreated -> Entering function."); }
+
+ if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
+ logger.write(MODULE_NAME, "[ERROR] start -> writeDataRange -> onFileCreated -> err = " + err.message);
+ callBack(err);
+ return;
+ }
+
+ if (LOG_FILE_CONTENT === true) {
+ logger.write(MODULE_NAME, "[INFO] start -> writeDataRange -> onFileCreated -> Content written = " + fileContent);
+ }
+
+ callBack(global.DEFAULT_OK_RESPONSE);
+ }
+ }
+ catch (err) {
+ logger.write(MODULE_NAME, "[ERROR] start -> writeDataRange -> err = " + err.message);
+ callBack(global.DEFAULT_FAIL_RESPONSE);
+ }
+ }
+
+ function writeStatusReport(lastFileDate, callBack) {
+
+ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeStatusReport -> Entering function."); }
+ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeStatusReport -> lastFileDate = " + lastFileDate); }
+
+ try {
+
+ let reportKey = bot.devTeam + "-" + bot.codeName + "-" + "Multi-Period-Daily" + "-" + "dataSet.V1";
+ let thisReport = statusDependencies.statusReports.get(reportKey);
+
+ thisReport.file.lastExecution = bot.currentDaytime;
+ thisReport.file.lastFile = lastFileDate;
+ thisReport.file.interExecutionMemoryArray = interExecutionMemoryArray;
+ thisReport.save(callBack);
+
+ bot.hasTheBotJustStarted = false;
+ }
+ catch (err) {
+ logger.write(MODULE_NAME, "[ERROR] start -> writeStatusReport -> err = " + err.message);
+ callBackFunction(global.DEFAULT_FAIL_RESPONSE);
+ }
+ }
+ }
+
+ catch (err) {
+ logger.write(MODULE_NAME, "[ERROR] start -> err = " + err.message);
+ callBackFunction(global.DEFAULT_FAIL_RESPONSE);
+ }
+ }
+};
diff --git a/MultiPeriodMarket.js b/MultiPeriodMarket.js
new file mode 100644
index 000000000..9f8d7853f
--- /dev/null
+++ b/MultiPeriodMarket.js
@@ -0,0 +1,340 @@
+exports.newMultiPeriodMarket = function newMultiPeriodMarket(bot, logger, COMMONS, UTILITIES, BLOB_STORAGE, USER_BOT_MODULE, COMMONS_MODULE) {
+
+ const FULL_LOG = true;
+ const LOG_FILE_CONTENT = false;
+ const MODULE_NAME = "Multi Period Market";
+
+ const commons = COMMONS.newCommons(bot, logger, UTILITIES);
+
+ thisObject = {
+ initialize: initialize,
+ start: start
+ };
+
+ let utilities = UTILITIES.newCloudUtilities(bot, logger);
+
+ let statusDependencies;
+ let dataDependencies;
+ let storages = [];
+ let dataFiles = [];
+
+ let usertBot;
+
+ let processConfig;
+
+ return thisObject;
+
+ function initialize(pProcessConfig, pStatusDependencies, pDataDependencies, callBackFunction) {
+
+ try {
+
+ logger.fileName = MODULE_NAME;
+ logger.initialize();
+
+ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] initialize -> Entering function."); }
+
+ statusDependencies = pStatusDependencies;
+ dataDependencies = pDataDependencies;
+ processConfig = pProcessConfig;
+
+ for (let i = 0; i < dataDependencies.config.length; i++) {
+
+ let key;
+ let storage;
+ let dependency = dataDependencies.config[i];
+
+ key = dependency.devTeam + "-" +
+ dependency.bot + "-" +
+ dependency.product + "-" +
+ dependency.dataSet + "-" +
+ dependency.dataSetVersion
+
+ storage = dataDependencies.dataSets.get(key);
+
+ storages.push(storage);
+
+ }
+
+ usertBot = USER_BOT_MODULE.newUserBot(bot, logger, COMMONS_MODULE, UTILITIES, BLOB_STORAGE);
+ usertBot.initialize(dataDependencies, callBackFunction);
+
+ } catch (err) {
+ logger.write(MODULE_NAME, "[ERROR] initialize -> err = " + err.message);
+ callBackFunction(global.DEFAULT_FAIL_RESPONSE);
+ }
+ }
+
+ function start(callBackFunction) {
+
+ try {
+
+ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> Entering function."); }
+
+ let market = global.MARKET;
+
+ /* Context Variables */
+
+ let contextVariables = {
+ dateBeginOfMarket: undefined, // Datetime of the first trade file in the whole market history.
+ dateEndOfMarket: undefined // Datetime of the last file available to be used as an input of this process.
+ };
+
+ if (processConfig.framework.startDate.fixedDate !== undefined) {
+
+ /* The starting date is fixed, we will start from there. */
+
+ contextVariables.dateBeginOfMarket = new Date(processConfig.framework.startDate.fixedDate);
+
+ }
+
+ if (processConfig.framework.endDate.fixedDate !== undefined) {
+
+ /* The ending date is fixed, we will end there. */
+
+ contextVariables.dateEndOfMarket = new Date(processConfig.framework.endDate.fixedDate);
+
+ }
+
+ processTimePeriods();
+
+ function processTimePeriods() {
+
+ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> Entering function."); }
+
+ try {
+
+ let n;
+
+ periodsLoop();
+
+ function periodsLoop() {
+
+ try {
+
+ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> periodsLoop -> Entering function."); }
+
+ /*
+
+ We will iterate through all posible periods.
+
+ */
+
+ n = 0 // loop Variable representing each possible period as defined at the periods array.
+
+ periodsLoopBody();
+
+ }
+ catch (err) {
+ logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoop -> err = " + err.message);
+ callBackFunction(global.DEFAULT_FAIL_RESPONSE);
+ }
+ }
+
+ function periodsLoopBody() {
+
+ try {
+
+ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> periodsLoopBody -> Entering function."); }
+
+ const timePeriod = global.marketFilesPeriods[n][0];
+ const outputPeriodLabel = global.marketFilesPeriods[n][1];
+
+ let dependencyIndex = 0;
+ dataFiles = [];
+
+ dependencyLoopBody();
+
+ function dependencyLoopBody() {
+
+ try {
+
+ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> Entering function."); }
+
+ let dependency = dataDependencies.config[dependencyIndex];
+ let storage = storages[dependencyIndex];
+
+ getFile();
+
+ function getFile() {
+
+ try {
+
+ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getFile -> Entering function."); }
+
+ let fileName = market.assetA + '_' + market.assetB + ".json";
+
+ let filePath = dependency.product + "/" + "Multi-Period-Market" + "/" + outputPeriodLabel;
+
+ storage.getTextFile(filePath, fileName, onFileReceived, true);
+
+ function onFileReceived(err, text) {
+
+ try {
+
+ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getFile -> onFileReceived -> Entering function."); }
+ if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getFile -> onFileReceived -> text = " + text); }
+
+ if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
+
+ logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getFile -> onFileReceived -> err = " + err.message);
+ logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getFile -> onFileReceived -> filePath = " + filePath);
+ logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getFile -> onFileReceived -> fileName = " + fileName);
+ callBackFunction(err);
+ return;
+ }
+
+ let dataFile = JSON.parse(text);
+ dataFiles.push(dataFile);
+
+ dependencyControlLoop();
+
+ }
+ catch (err) {
+ logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getFile -> onFileReceived -> err = " + err.message);
+ callBackFunction(global.DEFAULT_FAIL_RESPONSE);
+ }
+ }
+ }
+ catch (err) {
+ logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getFile -> err = " + err.message);
+ callBackFunction(global.DEFAULT_FAIL_RESPONSE);
+ }
+ }
+
+ }
+ catch (err) {
+ logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoop -> dependencyLoopBody -> err = " + err.message);
+ callBackFunction(global.DEFAULT_FAIL_RESPONSE);
+ }
+ }
+
+ function dependencyControlLoop() {
+
+ try {
+
+ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> dependencyControlLoop -> Entering function."); }
+
+ dependencyIndex++;
+
+ if (dependencyIndex < dataDependencies.config.length) {
+
+ dependencyLoopBody();
+
+ } else {
+
+ callTheBot();
+
+ }
+ }
+ catch (err) {
+ logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> dependencyControlLoop -> err = " + err.message);
+ callBackFunction(global.DEFAULT_FAIL_RESPONSE);
+ }
+ }
+
+ function callTheBot() {
+
+ try {
+
+ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> periodsLoopBody -> callTheBot -> Entering function."); }
+
+ const timePeriod = global.marketFilesPeriods[n][0];
+ const outputPeriodLabel = global.marketFilesPeriods[n][1];
+
+ usertBot.start(
+ dataFiles,
+ timePeriod,
+ outputPeriodLabel,
+ contextVariables.dateBeginOfMarket,
+ contextVariables.dateEndOfMarket,
+ onBotFinished);
+
+ function onBotFinished(err) {
+
+ try {
+
+ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> periodsLoopBody -> callTheBot -> onBotFinished -> Entering function."); }
+
+ if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
+
+ callBackFunction(err);
+ return;
+ }
+
+ periodsControlLoop();
+ }
+ catch (err) {
+ logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> callTheBot -> onBotFinished -> err = " + err.message);
+ callBackFunction(global.DEFAULT_FAIL_RESPONSE);
+ }
+ }
+ }
+ catch(err){
+ logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> callTheBot -> err = " + err.message);
+ callBackFunction(global.DEFAULT_FAIL_RESPONSE);
+ }
+ }
+ }
+ catch (err) {
+ logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> err = " + err.message);
+ callBackFunction(global.DEFAULT_FAIL_RESPONSE);
+ }
+ }
+
+ function periodsControlLoop() {
+
+ try {
+
+ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> periodsControlLoop -> Entering function."); }
+
+ n++;
+
+ if (n < global.marketFilesPeriods.length) {
+
+ periodsLoopBody();
+
+ } else {
+
+ writeStatusReport(callBackFunction);
+
+ }
+ }
+ catch (err) {
+ logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsControlLoop -> err = " + err.message);
+ callBackFunction(global.DEFAULT_FAIL_RESPONSE);
+ }
+ }
+
+ }
+ catch (err) {
+ logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> err = " + err.message);
+ callBackFunction(global.DEFAULT_FAIL_RESPONSE);
+ }
+ }
+
+ function writeStatusReport(callBack) {
+
+ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeStatusReport -> Entering function."); }
+
+ try {
+
+ let reportKey = bot.devTeam + "-" + bot.codeName + "-" + "Multi-Period-Market" + "-" + "dataSet.V1";
+ let thisReport = statusDependencies.statusReports.get(reportKey);
+
+ thisReport.file.lastExecution = bot.processDatetime;
+ thisReport.save(callBack);
+
+ }
+ catch (err) {
+ logger.write(MODULE_NAME, "[ERROR] start -> writeStatusReport -> err = " + err.message);
+ callBackFunction(global.DEFAULT_FAIL_RESPONSE);
+ }
+ }
+ }
+
+ catch (err) {
+ logger.write(MODULE_NAME, "[ERROR] start -> err = " + err.message);
+ callBackFunction(global.DEFAULT_FAIL_RESPONSE);
+ }
+ }
+};
diff --git a/Project.njsproj b/Project.njsproj
index fe4d8f923..74198b26c 100644
--- a/Project.njsproj
+++ b/Project.njsproj
@@ -33,6 +33,13 @@
Code
+
+
+ Code
+
+
+ Code
+
Code
@@ -46,7 +53,6 @@
Code
-
@@ -60,7 +66,7 @@
Code
-
+
Code
@@ -91,7 +97,7 @@
-
+
diff --git a/README.md b/README.md
index 1604ed841..20138c17f 100644
--- a/README.md
+++ b/README.md
@@ -1,10 +1,12 @@
-# AACloud
+# Clone Executor
-This repository holds the code of the bits of the AA Platform that run in the cloud.
+Whithin the Superalgos project, we have the concept of Financial Beings, which are autonomous agents that have a financial life. These FBs entities have a master (imagine a class in programming) and clones (imagine an instance of a class running). The master is the one who aquires reputation after competitions. Every time we need to do a backtest, live trading or participating in a competition, a clone is extracted from the master and is put to run, either in backtest mode, live trading mode or competition mode. The clone lifespan is contrained by the purpose it was created. For instance, a clone created for a competition will live only during the period of such competition.
-## About the AA Project
+The software needed to execute these clones is the Clone Executor.
-The AA Platform is built and maintained by Advanced Algos, the start up behind the AA Project.
+## About the Superalgos Project
+
+Superalgos is built and maintained by the Superalgos Foundation and its Community.
Our mission is to enable the fast-paced evolution of crypto trading bots within the context of trading bots competitions.
@@ -24,7 +26,7 @@ If you are interested in coding your own crypto trading bots and eventually part
## Copyright and License Notice
-© Copyright 2018 Advanced Algos. Please see the [AACloud License](/LICENSE) for information on how you can use this software.
+© Copyright 2018 Advanced Algos. Please see the [Clone Executor License](/LICENSE) for information on how you can use this software.
## Disclaimer
diff --git a/Root.js b/Root.js
index 86486ae54..1d8ebc007 100644
--- a/Root.js
+++ b/Root.js
@@ -1,7 +1,4 @@
-const appRoot = require('app-root-path')
-const operationsIntegration = require(`${appRoot}/Integrations/OperationsModuleIntegration`)
-
-exports.newRoot = function newRoot() {
+exports.newRoot = function newRoot() {
/* Callbacks default responses. */
@@ -77,7 +74,7 @@ exports.newRoot = function newRoot() {
let cloudStorage;
- let logDisplace = "AACloud" + " ";
+ let logDisplace = "CloneExecutor" + " ";
let UI_COMMANDS;
return thisObject;
@@ -140,21 +137,7 @@ exports.newRoot = function newRoot() {
if (err.result === global.DEFAULT_OK_RESPONSE.result) {
- let filePath;
-
- switch (global.CURRENT_EXECUTION_AT) {
- case "Cloud": {
- filePath = global.DEV_TEAM + "/" + "AACloud"; // DevTeams bots only are run at the cloud.
- break;
- }
- case "Browser": {
- filePath = global.DEV_TEAM + "/" + "members" + "/" + global.USER_LOGGED_IN + "/" + "AACloud"; // DevTeam Members bots only are run at the browser.
- break;
- }
- default: {
- console.log(logDisplace + "Root : [ERROR] start -> getBotConfig -> onInizialized -> CURRENT_EXECUTION_AT must be either 'Cloud' or 'Browser' ");
- }
- }
+ let filePath = global.DEV_TEAM + "/" + "AACloud"; // DevTeams bots only are run at the cloud.
let fileName = "this.config.json";
@@ -205,292 +188,187 @@ exports.newRoot = function newRoot() {
const TRADING_BOT_MAIN_LOOP_MODULE = require('./TradingBotProcessMainLoop');
const INDICATOR_BOT_MAIN_LOOP_MODULE = require('./IndicatorBotProcessMainLoop');
- const EXTRACTION_BOT_MAIN_LOOP_MODULE = require('./ExtractionBotProcessMainLoop');
+ const EXTRACTION_BOT_MAIN_LOOP_MODULE = require('./SensorBotProcessMainLoop');
/* Loop through all the processes configured to be run by this Node.js Instance. */
- for (let p = 0; p < global.PLATFORM_CONFIG.executionList.length; p++) {
+ let cloneToExecute = global.EXECUTION_CONFIG.cloneToExecute;
- let listItem;
+ /* Now we will read the config of the bot from the path we obtained at the CloneExecutor config. */
- /*
- The local configuration allows to select the configuration to run
- locally, without overwriting the server config.
- Here we check that the local configuration for the execution
- exist, if it doesn't exist we will take the one on the server.
- */
- if (global.EXECUTION_CONFIG === undefined) {
- listItem = PLATFORM_CONFIG.executionList[p];
- } else {
- listItem = global.EXECUTION_CONFIG.executionList[p];
- }
+ let botConfig;
- if (listItem === undefined || listItem.enabled !== "true") {
+ getBotConfig();
- console.log(logDisplace + "Root : [INFO] start -> Skipping process for being disabled.");
- console.log(logDisplace + "Root : [INFO] start -> listItem.process = " + PLATFORM_CONFIG.executionList[p].process);
+ function getBotConfig() {
- continue;
- }
+ try {
+ console.log(logDisplace + "Root : [INFO] start -> getBotConfig -> Entering function. ");
- /* Now we will read the config of the bot from the path we obtained at the AACloud config. */
+ const BLOB_STORAGE = require(ROOT_DIR + 'BlobStorage');
+ let cloudStorage = BLOB_STORAGE.newBlobStorage(cloneToExecute);
- let botConfig;
+ cloudStorage.initialize("AAPlatform", onInizialized, true);
- getBotConfig();
+ function onInizialized(err) {
- function getBotConfig() {
+ if (err.result === global.DEFAULT_OK_RESPONSE.result) {
- try {
- console.log(logDisplace + "Root : [INFO] start -> getBotConfig -> Entering function. ");
+ let filePath = global.DEV_TEAM + "/" + "bots" + "/" + cloneToExecute.repo; // DevTeams bots only are run at the cloud.
- const BLOB_STORAGE = require(ROOT_DIR + 'BlobStorage');
- let cloudStorage = BLOB_STORAGE.newBlobStorage(listItem);
+ let fileName = "this.bot.config.json";
- cloudStorage.initialize("AAPlatform", onInizialized, true);
+ cloudStorage.getTextFile(filePath, fileName, onFileReceived);
- function onInizialized(err) {
+ function onFileReceived(err, text) {
- if (err.result === global.DEFAULT_OK_RESPONSE.result) {
+ if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
+ console.log(logDisplace + "Root : [ERROR] start -> getBotConfig -> onInizialized -> onFileReceived -> err = " + err.message);
+ console.log(logDisplace + "Root : [ERROR] start -> getBotConfig -> onInizialized -> onFileReceived -> filePath = " + filePath);
+ console.log(logDisplace + "Root : [ERROR] start -> getBotConfig -> onInizialized -> onFileReceived -> fileName = " + fileName);
- let filePath;
-
- switch (global.CURRENT_EXECUTION_AT) {
- case "Cloud": {
- filePath = global.DEV_TEAM + "/" + "bots" + "/" + listItem.repo; // DevTeams bots only are run at the cloud.
-
- console.log(logDisplace + "Root : [INFO] start -> getBotConfig -> Getting Bot Config from the devTeams's Bot. ");
- console.log(logDisplace + "Root : [INFO] start -> getBotConfig -> filePath = " + filePath);
- break;
- }
- case "Browser": {
- filePath = global.DEV_TEAM + "/" + "members" + "/" + global.USER_LOGGED_IN + "/" + global.CURRENT_BOT_REPO; // DevTeam Members bots only are run at the browser.
-
- console.log(logDisplace + "Root : [INFO] start -> getBotConfig -> Getting Bot Config from the endUser's Bot. ");
- console.log(logDisplace + "Root : [INFO] start -> getBotConfig -> global.USER_LOGGED_IN = " + global.USER_LOGGED_IN);
- console.log(logDisplace + "Root : [INFO] start -> getBotConfig -> filePath = " + filePath);
- break;
- }
- default: {
- console.log(logDisplace + "Root : [ERROR] start -> getBotConfig -> onInizialized -> CURRENT_EXECUTION_AT must be either 'Cloud' or 'Browser' ");
- }
+ return;
}
- let fileName = "this.bot.config.json";
-
- cloudStorage.getTextFile(filePath, fileName, onFileReceived);
-
- function onFileReceived(err, text) {
-
- if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
- console.log(logDisplace + "Root : [ERROR] start -> getBotConfig -> onInizialized -> onFileReceived -> err = " + err.message);
- console.log(logDisplace + "Root : [ERROR] start -> getBotConfig -> onInizialized -> onFileReceived -> filePath = " + filePath);
- console.log(logDisplace + "Root : [ERROR] start -> getBotConfig -> onInizialized -> onFileReceived -> fileName = " + fileName);
-
- return;
- }
-
- try {
- botConfig = JSON.parse(text);
- botConfig.repo = listItem.repo;
- findProcess();
- } catch (err) {
- console.log(logDisplace + "Root : [ERROR] start -> getBotConfig -> onInizialized -> onFileReceived -> err = " + err.message);
- return;
- }
+ try {
+ botConfig = JSON.parse(text);
+ botConfig.repo = cloneToExecute.repo;
+ findProcess();
+ } catch (err) {
+ console.log(logDisplace + "Root : [ERROR] start -> getBotConfig -> onInizialized -> onFileReceived -> err = " + err.message);
+ return;
}
-
- } else {
- console.log(logDisplace + "Root : [ERROR] start -> getBotConfig -> onInizialized -> err = " + err.message);
- return;
}
+
+ } else {
+ console.log(logDisplace + "Root : [ERROR] start -> getBotConfig -> onInizialized -> err = " + err.message);
+ return;
}
}
- catch (err) {
- console.log(logDisplace + "Root : [ERROR] start -> getBotConfig -> err.message = " + err.message);
- return;
- }
}
+ catch (err) {
+ console.log(logDisplace + "Root : [ERROR] start -> getBotConfig -> err.message = " + err.message);
+ return;
+ }
+ }
- function findProcess() {
+ function findProcess() {
- try {
- if (FULL_LOG === true) { console.log(logDisplace + "Root : [INFO] start -> findProcess -> Entering function. "); }
+ try {
+ if (FULL_LOG === true) { console.log(logDisplace + "Root : [INFO] start -> findProcess -> Entering function. "); }
- botConfig.process = listItem.process;
- botConfig.debug = {};
+ botConfig.process = cloneToExecute.process;
+ botConfig.debug = {};
- /* Loop Counter */
+ /* Loop Counter */
- botConfig.loopCounter = 0;
+ botConfig.loopCounter = 0;
- if (FULL_LOG === true) { console.log(logDisplace + "Root : [INFO] start -> findProcess -> Processing item from executionList -> p = " + p); }
+ /* File Path Root */
- /* File Path Root */
+ botConfig.filePathRoot = botConfig.devTeam + "/" + botConfig.codeName + "." + botConfig.version.major + "." + botConfig.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + botConfig.dataSetVersion;
- botConfig.filePathRoot = botConfig.devTeam + "/" + botConfig.codeName + "." + botConfig.version.major + "." + botConfig.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + botConfig.dataSetVersion;
+ if (FULL_LOG === true) { console.log(logDisplace + "Root : [INFO] start -> findProcess -> cloneToExecute.process = " + cloneToExecute.process); }
- if (FULL_LOG === true) { console.log(logDisplace + "Root : [INFO] start -> findProcess -> listItem.process = " + listItem.process); }
+ /* Now we loop throug all the configured processes at each bots configuration until we find the one we are supposed to run at this Node.js process. */
- /* Now we loop throug all the configured processes at each bots configuration until we find the one we are supposed to run at this Node.js process. */
+ let processFound = false;
- let processFound = false;
+ for (let i = 0; i < botConfig.processes.length; i++) {
- for (let i = 0; i < botConfig.processes.length; i++) {
+ if (botConfig.processes[i].name === cloneToExecute.process) {
- if (botConfig.processes[i].name === listItem.process) {
+ processFound = true;
+ if (FULL_LOG === true) { console.log(logDisplace + "Root : [INFO] start -> findProcess -> Process found at the bot configuration file. -> cloneToExecute.process = " + cloneToExecute.process); }
- processFound = true;
- if (FULL_LOG === true) { console.log(logDisplace + "Root : [INFO] start -> findProcess -> Process found at the bot configuration file. -> listItem.process = " + listItem.process); }
+ let processConfig = botConfig.processes[i];
- let processConfig = botConfig.processes[i];
- processConfig.startMode = global.EXECUTION_CONFIG.startMode // Override file storage configuration
- try {
-
- /*
-
- When running at the browser, the endUser can override the configured setting for the bot. In this scenario we use the commands
- sent from the User Interface.
-
- */
-
- if (UI_COMMANDS.startMode !== undefined) {
-
- switch (UI_COMMANDS.startMode) {
-
- case "Backtest": {
-
- processConfig.startMode.backtest.run = "true";
- processConfig.startMode.live.run = "false";
- processConfig.startMode.competition.run = "false";
-
- break;
- }
-
- case "Live": {
-
- processConfig.startMode.backtest.run = "false";
- processConfig.startMode.live.run = "true";
- processConfig.startMode.competition.run = "false";
-
- break;
- }
-
- case "Competition": {
-
- processConfig.startMode.backtest.run = "false";
- processConfig.startMode.live.run = "false";
- processConfig.startMode.competition.run = "true";
-
- break;
- }
- }
-
- if (FULL_LOG === true) { console.log(logDisplace + "Root : [INFO] start -> findProcess -> Process found at the bot configuration file. -> Start Mode Overwritten. "); }
- if (FULL_LOG === true) { console.log(logDisplace + "Root : [INFO] start -> findProcess -> Process found at the bot configuration file. -> processConfig.startMode = " + processConfig.startMode); }
+ processConfig.startMode = global.EXECUTION_CONFIG.startMode // Override file storage configuration
+ if(global.EXECUTION_CONFIG.timePeriod){
+ processConfig.timePeriod = global.EXECUTION_CONFIG.timePeriod
+ }
+ if (processConfig.framework !== undefined) {
+ if (processConfig.framework.name === "Multi-Period-Daily" || processConfig.framework.name === "Multi-Period-Market") {
+ if (processConfig.startMode.noTime.beginDatetime !== undefined) {
+ processConfig.framework.startDate.fixedDate = processConfig.startMode.noTime.beginDatetime;
}
+ processConfig.framework.startDate.resumeExecution = processConfig.startMode.noTime.resumeExecution;
+ }
+ }
- /* We test each type of start Mode to get what to run and how. */
+ try {
- if (processConfig.startMode.allMonths !== undefined) {
+ /* We test each type of start Mode to get what to run and how. */
- if (processConfig.startMode.allMonths.run === "true") {
+ if (processConfig.startMode.allMonths !== undefined) {
- if (FULL_LOG === true) { console.log(logDisplace + "Root : [INFO] start -> findProcess -> allMonths start mode detected. "); }
+ if (processConfig.startMode.allMonths.run === "true") {
- for (let year = processConfig.startMode.allMonths.maxYear; year >= processConfig.startMode.allMonths.minYear; year--) {
+ if (FULL_LOG === true) { console.log(logDisplace + "Root : [INFO] start -> findProcess -> allMonths start mode detected. "); }
- for (let month = 12; month > 0; month--) {
+ for (let year = processConfig.startMode.allMonths.maxYear; year >= processConfig.startMode.allMonths.minYear; year--) {
- let padMonth = pad(month, 2)
+ for (let month = 12; month > 0; month--) {
- let newInstanceBotConfig = JSON.parse(JSON.stringify(botConfig));
+ let padMonth = pad(month, 2)
- newInstanceBotConfig.debug = {
- month: pad(month, 2),
- year: pad(year, 4)
- };
+ let newInstanceBotConfig = JSON.parse(JSON.stringify(botConfig));
- let timeDelay = Math.random() * 10 * 1000; // We introduce a short delay so as to not overload the machine.
- setTimeout(startProcess, timeDelay);
+ newInstanceBotConfig.debug = {
+ month: pad(month, 2),
+ year: pad(year, 4)
+ };
- function startProcess() {
+ let timeDelay = Math.random() * 10 * 1000; // We introduce a short delay so as to not overload the machine.
+ setTimeout(startProcess, timeDelay);
- if (FULL_LOG === true) { console.log(logDisplace + "Root : [INFO] start -> findProcess -> startProcess -> Ready to start process."); }
+ function startProcess() {
- switch (botConfig.type) {
- case 'Extraction': {
- runExtractionBot(newInstanceBotConfig, processConfig, padMonth, year);
- break;
- }
- case 'Indicator': {
- runIndicatorBot(newInstanceBotConfig, processConfig, padMonth, year);
- break;
- }
- default: {
- console.log(logDisplace + "Root : [ERROR] start -> findProcess -> startProcess -> Unexpected bot type. -> botConfig.type = " + botConfig.type);
- }
+ if (FULL_LOG === true) { console.log(logDisplace + "Root : [INFO] start -> findProcess -> startProcess -> Ready to start process."); }
+
+ switch (botConfig.type) {
+ case 'Sensor': {
+ runSensorBot(newInstanceBotConfig, processConfig, padMonth, year);
+ break;
+ }
+ case 'Indicator': {
+ runIndicatorBot(newInstanceBotConfig, processConfig, padMonth, year);
+ break;
+ }
+ default: {
+ console.log(logDisplace + "Root : [ERROR] start -> findProcess -> startProcess -> Unexpected bot type. -> botConfig.type = " + botConfig.type);
}
}
}
}
}
}
+ }
- if (processConfig.startMode.oneMonth !== undefined) {
+ if (processConfig.startMode.oneMonth !== undefined) {
- if (processConfig.startMode.oneMonth.run === "true") {
+ if (processConfig.startMode.oneMonth.run === "true") {
- if (FULL_LOG === true) { console.log(logDisplace + "Root : [INFO] start -> findProcess -> oneMonth start mode detected. "); }
+ if (FULL_LOG === true) { console.log(logDisplace + "Root : [INFO] start -> findProcess -> oneMonth start mode detected. "); }
- startProcess();
+ startProcess();
- function startProcess() {
+ function startProcess() {
- if (FULL_LOG === true) { console.log(logDisplace + "Root : [INFO] start -> findProcess -> startProcess -> Ready to start process."); }
+ if (FULL_LOG === true) { console.log(logDisplace + "Root : [INFO] start -> findProcess -> startProcess -> Ready to start process."); }
- let month = pad(processConfig.startMode.oneMonth.month, 2);
- let year = processConfig.startMode.oneMonth.year;
+ let month = pad(processConfig.startMode.oneMonth.month, 2);
+ let year = processConfig.startMode.oneMonth.year;
- botConfig.debug = {
- month: pad(month, 2),
- year: pad(year, 4)
- };
-
- switch (botConfig.type) {
- case 'Extraction': {
- runExtractionBot(botConfig, processConfig, month, year);
- break;
- }
- case 'Indicator': {
- runIndicatorBot(botConfig, processConfig, month, year);
- break;
- }
- default: {
- console.log(logDisplace + "Root : [ERROR] start -> findProcess -> startProcess -> Unexpected bot type. -> botConfig.type = " + botConfig.type);
- }
- }
- }
- }
- }
-
- if (processConfig.startMode.noTime !== undefined) {
-
- if (processConfig.startMode.noTime.run === "true") {
-
- let month = pad((new Date()).getUTCMonth() + 1, 2);
- let year = (new Date()).getUTCFullYear();
-
- if (processConfig.startMode.noTime.resumeExecution === "true") {
- botConfig.hasTheBotJustStarted = false;
- } else {
- botConfig.hasTheBotJustStarted = true;
- }
+ botConfig.debug = {
+ month: pad(month, 2),
+ year: pad(year, 4)
+ };
switch (botConfig.type) {
- case 'Extraction': {
- runExtractionBot(botConfig, processConfig, month, year);
+ case 'Sensor': {
+ runSensorBot(botConfig, processConfig, month, year);
break;
}
case 'Indicator': {
@@ -498,464 +376,494 @@ exports.newRoot = function newRoot() {
break;
}
default: {
- console.log(logDisplace + "Root : [ERROR] start -> findProcess -> Unexpected bot type. -> botConfig.type = " + botConfig.type);
+ console.log(logDisplace + "Root : [ERROR] start -> findProcess -> startProcess -> Unexpected bot type. -> botConfig.type = " + botConfig.type);
}
}
}
}
+ }
- if (processConfig.startMode.fixedInterval !== undefined) {
+ if (processConfig.startMode.noTime !== undefined) {
- if (processConfig.startMode.fixedInterval.run === "true") {
+ if (processConfig.startMode.noTime.run === "true") {
- botConfig.runAtFixedInterval = true;
- botConfig.fixedInterval = processConfig.startMode.fixedInterval.interval;
-
- let month = pad((new Date()).getUTCMonth() + 1, 2);
- let year = (new Date()).getUTCFullYear();
-
- switch (botConfig.type) {
- case 'Extraction': {
- runExtractionBot(botConfig, processConfig, month, year);
- break;
- }
- default: {
- console.log(logDisplace + "Root : [ERROR] start -> findProcess -> Unexpected bot type. -> botConfig.type = " + botConfig.type);
- }
- }
- }
- }
-
- if (processConfig.startMode.live !== undefined) {
-
- if (processConfig.startMode.live.run === "true" && global.EXECUTION_CONFIG.startMode.live.run === "true") {
-
- botConfig.startMode = "Live";
- console.log(logDisplace + "Root : [INFO] start -> findProcess -> Process found at the bot configuration file. -> Start Mode = " + botConfig.startMode);
-
- let month = pad((new Date()).getUTCMonth() + 1, 2);
- let year = (new Date()).getUTCFullYear();
-
- if (processConfig.startMode.live.resumeExecution === "true" && global.EXECUTION_CONFIG.startMode.live.resumeExecution === "true") {
- botConfig.hasTheBotJustStarted = false;
- } else {
- botConfig.hasTheBotJustStarted = true;
- }
-
- switch (botConfig.type) {
- case 'Trading': {
- runTradingBot(botConfig, processConfig);
- break;
- }
- default: {
- console.log(logDisplace + "Root : [ERROR] start -> findProcess -> Unexpected bot type. -> botConfig.type = " + botConfig.type);
- }
- }
- }
- }
-
- if (processConfig.startMode.backtest !== undefined) {
-
- if (processConfig.startMode.backtest.run === "true" && global.EXECUTION_CONFIG.startMode.backtest.run === "true") {
-
- botConfig.startMode = "Backtest";
- console.log(logDisplace + "Root : [INFO] start -> findProcess -> Process found at the bot configuration file. -> Start Mode = " + botConfig.startMode);
-
- botConfig.backtest = processConfig.startMode.backtest;
-
- /* We override these waitTimes to the one specified at the backtest configuration. */
-
- processConfig.normalWaitTime = processConfig.startMode.backtest.waitTime;
- processConfig.retryWaitTime = processConfig.startMode.backtest.waitTime;
-
- /* Backtest Mode does not support Resume Execution, so this is the only way. */
+ let month = pad((new Date()).getUTCMonth() + 1, 2);
+ let year = (new Date()).getUTCFullYear();
+ if (processConfig.startMode.noTime.resumeExecution === "true") {
+ botConfig.hasTheBotJustStarted = false;
+ } else {
botConfig.hasTheBotJustStarted = true;
-
- switch (botConfig.type) {
- case 'Trading': {
- runTradingBot(botConfig, processConfig);
- break;
- }
- default: {
- console.log(logDisplace + "Root : [ERROR] start -> findProcess -> Unexpected bot type. -> botConfig.type = " + botConfig.type);
- }
- }
- }
- }
-
- if (processConfig.startMode.competition !== undefined) {
-
- if (processConfig.startMode.competition.run === "true" && global.EXECUTION_CONFIG.startMode.competition.run === "true") {
-
- botConfig.startMode = "Competition";
- console.log(logDisplace + "Root : [INFO] start -> findProcess -> Process found at the bot configuration file. -> Start Mode = " + botConfig.startMode);
-
- botConfig.competition = processConfig.startMode.competition;
-
- if (processConfig.startMode.competition.resumeExecution === "false" && global.EXECUTION_CONFIG.startMode.competition.resumeExecution === "false") {
- botConfig.hasTheBotJustStarted = true;
- } else {
- botConfig.hasTheBotJustStarted = false;
- }
-
- switch (botConfig.type) {
- case 'Trading': {
- runTradingBot(botConfig, processConfig);
- break;
- }
- default: {
- console.log(logDisplace + "Root : [ERROR] start -> findProcess -> Unexpected bot type. -> botConfig.type = " + botConfig.type);
- }
- }
- }
- }
-
- } catch (err) {
- console.log(logDisplace + "Root : [ERROR] start -> findProcess -> Unexpected exception. -> err.message = " + err.message);
- }
- }
- }
-
- if (processFound === false) {
-
- console.log(logDisplace + "Root : [ERROR] start -> findProcess -> Process listed at the configuration file of AACloud not found at the configuration file of the bot.");
- console.log(logDisplace + "Root : [ERROR] start -> findProcess -> listItem.process = " + listItem.process);
-
- }
-
- function runExtractionBot(pBotConfig, pProcessConfig, pMonth, pYear) {
-
- try {
-
- const DEBUG_MODULE = require(ROOT_DIR + 'DebugLog');
- let logger;
-
- logger = DEBUG_MODULE.newDebugLog();
- logger.bot = pBotConfig;
-
- if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> findProcess -> runExtractionBot -> Entering function."); }
- if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> findProcess -> runExtractionBot -> pMonth = " + pMonth); }
- if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> findProcess -> runExtractionBot -> pYear = " + pYear); }
-
- let extractionBotMainLoop = EXTRACTION_BOT_MAIN_LOOP_MODULE.newExtractionBotProcessMainLoop(pBotConfig, logger);
- extractionBotMainLoop.initialize(UI_COMMANDS, pProcessConfig, onInitializeReady);
-
- function onInitializeReady(err) {
-
- if (err.result === global.DEFAULT_OK_RESPONSE.result) {
-
- extractionBotMainLoop.run(pMonth, pYear, whenRunFinishes);
-
- function whenRunFinishes(err) {
-
- pBotConfig.loopCounter = 0;
-
- let botId;
- if (pYear !== undefined) {
- botId = pBotConfig.devTeam + "." + pBotConfig.codeName + "." + pBotConfig.process + "." + pYear + "." + pMonth;
- } else {
- botId = pBotConfig.devTeam + "." + pBotConfig.codeName + "." + pBotConfig.process;
- }
-
- if (err.result === global.DEFAULT_OK_RESPONSE.result) {
-
- logger.write(MODULE_NAME, "[INFO] start -> findProcess -> runExtractionBot -> onInitializeReady -> whenStartFinishes -> Bot execution finished sucessfully.");
- logger.write(MODULE_NAME, "[INFO] start -> findProcess -> runExtractionBot -> onInitializeReady -> whenStartFinishes -> Bot Id = " + botId);
-
- console.log(logDisplace + "Root : [INFO] start -> findProcess -> runExtractionBot -> onInitializeReady -> whenStartFinishes -> botId = " + botId);
- console.log(logDisplace + "Root : [INFO] start -> findProcess -> runExtractionBot -> onInitializeReady -> whenStartFinishes -> Bot execution finished sucessfully.");
-
- logger.persist();
-
- } else {
-
- logger.write(MODULE_NAME, "[ERROR] start -> findProcess -> runExtractionBot -> onInitializeReady -> whenStartFinishes -> err = " + err.message);
- logger.write(MODULE_NAME, "[ERROR] start -> findProcess -> runExtractionBot -> onInitializeReady -> whenStartFinishes -> Execution will be stopped. ");
- logger.write(MODULE_NAME, "[ERROR] start -> findProcess -> runExtractionBot -> onInitializeReady -> whenStartFinishes -> Bye.");
- logger.write(MODULE_NAME, "[ERROR] start -> findProcess -> runExtractionBot -> onInitializeReady -> whenStartFinishes -> Bot Id = " + botId);
-
- console.log(logDisplace + "Root : [ERROR] start -> findProcess -> runExtractionBot -> onInitializeReady -> whenStartFinishes -> botId = " + botId);
- console.log(logDisplace + "Root : [ERROR] start -> findProcess -> runExtractionBot -> onInitializeReady -> whenStartFinishes -> Bot execution was aborted.");
- logger.persist();
- }
}
- } else {
- logger.write(MODULE_NAME, "[ERROR] start -> findProcess -> runExtractionBot -> onInitializeReady -> err = " + err.message);
- logger.write(MODULE_NAME, "[ERROR] start -> findProcess -> runExtractionBot -> onInitializeReady -> Bot will not be started. ");
- console.log(logDisplace + "Root : [ERROR] start -> findProcess -> runExtractionBot -> onInitializeReady -> err = " + err.message);
-
- logger.persist();
+ switch (botConfig.type) {
+ case 'Sensor': {
+ runSensorBot(botConfig, processConfig, month, year);
+ break;
+ }
+ case 'Indicator': {
+ runIndicatorBot(botConfig, processConfig, month, year);
+ break;
+ }
+ default: {
+ console.log(logDisplace + "Root : [ERROR] start -> findProcess -> Unexpected bot type. -> botConfig.type = " + botConfig.type);
+ }
+ }
}
}
- }
- catch (err) {
- console.log(logDisplace + "Root : [ERROR] start -> findProcess -> runExtractionBot -> err = " + err.message);
- }
- }
- function runIndicatorBot(pBotConfig, pProcessConfig, pMonth, pYear) {
+ if (processConfig.startMode.fixedInterval !== undefined) {
- try {
- const DEBUG_MODULE = require(ROOT_DIR + 'DebugLog');
- let logger;
+ if (processConfig.startMode.fixedInterval.run === "true") {
- logger = DEBUG_MODULE.newDebugLog();
- logger.bot = pBotConfig;
+ botConfig.runAtFixedInterval = true;
+ botConfig.fixedInterval = processConfig.startMode.fixedInterval.interval;
- if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> findProcess -> runIndicatorBot -> Entering function."); }
- if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> findProcess -> runIndicatorBot -> pMonth = " + pMonth); }
- if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> findProcess -> runIndicatorBot -> pYear = " + pYear); }
+ let month = pad((new Date()).getUTCMonth() + 1, 2);
+ let year = (new Date()).getUTCFullYear();
- let indicatorBotMainLoop = INDICATOR_BOT_MAIN_LOOP_MODULE.newIndicatorBotProcessMainLoop(pBotConfig, logger);
- indicatorBotMainLoop.initialize(UI_COMMANDS, pProcessConfig, onInitializeReady);
-
- function onInitializeReady(err) {
-
- if (err.result === global.DEFAULT_OK_RESPONSE.result) {
-
- indicatorBotMainLoop.run(pMonth, pYear, whenRunFinishes);
-
- function whenRunFinishes(err) {
-
- pBotConfig.loopCounter = 0;
-
- let botId;
- if (pYear !== undefined) {
- botId = pBotConfig.devTeam + "." + pBotConfig.codeName + "." + pBotConfig.process + "." + pYear + "." + pMonth;
- } else {
- botId = pBotConfig.devTeam + "." + pBotConfig.codeName + "." + pBotConfig.process;
+ switch (botConfig.type) {
+ case 'Sensor': {
+ runSensorBot(botConfig, processConfig, month, year);
+ break;
}
-
- if (err.result === global.DEFAULT_OK_RESPONSE.result) {
-
- logger.write(MODULE_NAME, "[INFO] start -> findProcess -> runIndicatorBot -> onInitializeReady -> whenStartFinishes -> Bot execution finished sucessfully.");
- logger.write(MODULE_NAME, "[INFO] start -> findProcess -> runIndicatorBot -> onInitializeReady -> whenStartFinishes -> Bot Id = " + botId);
-
- console.log(logDisplace + "Root : [INFO] start -> findProcess -> runIndicatorBot -> onInitializeReady -> whenStartFinishes -> botId = " + botId);
- console.log(logDisplace + "Root : [INFO] start -> findProcess -> runIndicatorBot -> onInitializeReady -> whenStartFinishes -> Bot execution finished sucessfully.");
-
- logger.persist();
-
- } else {
-
- logger.write(MODULE_NAME, "[ERROR] start -> findProcess -> runIndicatorBot -> onInitializeReady -> whenStartFinishes -> err = " + err.message);
- logger.write(MODULE_NAME, "[ERROR] start -> findProcess -> runIndicatorBot -> onInitializeReady -> whenStartFinishes -> Execution will be stopped. ");
- logger.write(MODULE_NAME, "[ERROR] start -> findProcess -> runIndicatorBot -> onInitializeReady -> whenStartFinishes -> Bye.");
- logger.write(MODULE_NAME, "[ERROR] start -> findProcess -> runIndicatorBot -> onInitializeReady -> whenStartFinishes -> Bot Id = " + botId);
- console.log(logDisplace + "Root : [ERROR] start -> findProcess -> runIndicatorBot -> onInitializeReady -> whenStartFinishes -> Bot execution finished with errors. Please check the logs.");
- logger.persist();
+ default: {
+ console.log(logDisplace + "Root : [ERROR] start -> findProcess -> Unexpected bot type. -> botConfig.type = " + botConfig.type);
}
}
-
- } else {
- logger.write(MODULE_NAME, "[ERROR] start -> findProcess -> runIndicatorBot -> onInitializeReady -> err = " + err.message);
- logger.write(MODULE_NAME, "[ERROR] start -> findProcess -> runIndicatorBot -> onInitializeReady -> Bot will not be started. ");
- console.log(logDisplace + "Root : [ERROR] start -> findProcess -> runIndicatorBot -> onInitializeReady -> err = " + err.message);
- logger.persist();
}
}
- }
- catch (err) {
- console.log(logDisplace + "Root : [ERROR] start -> findProcess -> runIndicatorBot -> err = " + err.message);
- }
- }
+ if (processConfig.startMode.live !== undefined) {
- function runTradingBot(pBotConfig, pProcessConfig) {
+ if (processConfig.startMode.live.run === "true") {
- try {
+ botConfig.startMode = "Live";
+ console.log(logDisplace + "Root : [INFO] start -> findProcess -> Process found at the bot configuration file. -> Start Mode = " + botConfig.startMode);
- if (FULL_LOG === true) { console.log(logDisplace + "[INFO] start -> findProcess -> runTradingBot -> Entering function."); }
-
- if (pBotConfig.genes !== undefined) {
-
- /* Here, based on the gene we will create one instance for each combination of genes */
-
- let valueMatrix = [];
-
- for (let i = 0; i < pBotConfig.genes.length; i++) {
-
- let gene = pBotConfig.genes[i];
-
- let possibleValues = [];
-
- for (let j = gene.lowerLimit; j <= gene.upperLimit; j++) {
-
- possibleValues.push(j);
+ let month = pad((new Date()).getUTCMonth() + 1, 2);
+ let year = (new Date()).getUTCFullYear();
+ if (processConfig.startMode.live.resumeExecution === "true") {
+ botConfig.hasTheBotJustStarted = false;
+ } else {
+ botConfig.hasTheBotJustStarted = true;
}
- valueMatrix.push(possibleValues);
-
- }
-
- /*
- Now we have all the possible genes values in a multi-dimensional matrix.
- We will go thorugh each of the elements of each dimension and get each combination possible with the other dimmensions.
- */
-
- let combinations = [];
- let combination = [];
- let dimensionIndex = 0;
-
- calculateCombinations(dimensionIndex, combination);
-
- function calculateCombinations(pDimensionIndex, pCombination) {
-
- let dimension = valueMatrix[pDimensionIndex];
-
- for (let j = 0; j < dimension.length; j++) {
-
- let copy = JSON.parse(JSON.stringify(pCombination));
-
- let value = dimension[j];
- copy.push(value);
-
- if (pDimensionIndex < valueMatrix.length - 1) {
-
- calculateCombinations(pDimensionIndex + 1, copy);
-
- } else {
-
- combinations.push(copy);
-
+ switch (botConfig.type) {
+ case 'Trading': {
+ runTradingBot(botConfig, processConfig);
+ break;
+ }
+ default: {
+ console.log(logDisplace + "Root : [ERROR] start -> findProcess -> Unexpected bot type. -> botConfig.type = " + botConfig.type);
}
}
}
-
- /* At this point we have an array with all the possible combinations, we just need to create an instance for each one and set the genes according to that. */
-
- for (let i = 0; i < combinations.length; i++) {
-
- let botConfig = JSON.parse(JSON.stringify(pBotConfig));
- let combination = combinations[i];
- let genes = {};
- let clonKey = "";
-
- for (let j = 0; j < botConfig.genes.length; j++) {
-
- genes[botConfig.genes[j].name] = combination[j];
- clonKey = clonKey + "." + combination[j];
-
- }
-
- let clonName = botConfig.codeName + "-" + "Clon" + clonKey + "-" + process.env.CLONE_ID;
-
- botConfig.filePathRoot = botConfig.devTeam + "/" + clonName + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + botConfig.dataSetVersion;
-
- botConfig.instance = clonName;
- botConfig.instanceIndex = i;
-
- setTimeout(execute, i * Math.random() * 10 * 1000);
-
- function execute() {
-
- createBotInstance(genes, combinations.length, botConfig);
-
- }
- }
- } else {
-
- /* If the bot does not have any genes at all */
-
- let genes = {};
- let clonName = botConfig.codeName + "-" + process.env.CLONE_ID;
-
- botConfig.filePathRoot = botConfig.devTeam + "/" + clonName + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + botConfig.dataSetVersion;
-
- pBotConfig.instance = clonName;
- pBotConfig.instanceIndex = 0;
-
- createBotInstance(genes, 1, pBotConfig);
-
}
+ if (processConfig.startMode.backtest !== undefined) {
- function createBotInstance(pGenes, pTotalInstances, pBotConfig) {
+ if (processConfig.startMode.backtest.run === "true") {
- const DEBUG_MODULE = require(ROOT_DIR + 'DebugLog');
- let logger;
+ botConfig.startMode = "Backtest";
+ console.log(logDisplace + "Root : [INFO] start -> findProcess -> Process found at the bot configuration file. -> Start Mode = " + botConfig.startMode);
- logger = DEBUG_MODULE.newDebugLog();
- logger.bot = pBotConfig;
+ botConfig.backtest = processConfig.startMode.backtest;
- if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> findProcess -> runTradingBot -> createBotInstance -> Entering function."); }
+ /* We override these waitTimes to the one specified at the backtest configuration. */
- let tradingBotMainLoop = TRADING_BOT_MAIN_LOOP_MODULE.newTradingBotProcessMainLoop(pBotConfig, logger);
- tradingBotMainLoop.initialize(UI_COMMANDS, pProcessConfig, onInitializeReady);
+ processConfig.normalWaitTime = processConfig.startMode.backtest.waitTime;
+ processConfig.retryWaitTime = processConfig.startMode.backtest.waitTime;
- function onInitializeReady(err) {
+ /* Backtest Mode does not support Resume Execution, so this is the only way. */
+
+ botConfig.hasTheBotJustStarted = true;
+
+ switch (botConfig.type) {
+ case 'Trading': {
+ runTradingBot(botConfig, processConfig);
+ break;
+ }
+ default: {
+ console.log(logDisplace + "Root : [ERROR] start -> findProcess -> Unexpected bot type. -> botConfig.type = " + botConfig.type);
+ }
+ }
+ }
+ }
+
+ if (processConfig.startMode.competition !== undefined) {
+
+ if (processConfig.startMode.competition.run === "true") {
+
+ botConfig.startMode = "Competition";
+ console.log(logDisplace + "Root : [INFO] start -> findProcess -> Process found at the bot configuration file. -> Start Mode = " + botConfig.startMode);
+
+ botConfig.competition = processConfig.startMode.competition;
+
+ if (processConfig.startMode.competition.resumeExecution === "false") {
+ botConfig.hasTheBotJustStarted = true;
+ } else {
+ botConfig.hasTheBotJustStarted = false;
+ }
+
+ switch (botConfig.type) {
+ case 'Trading': {
+ runTradingBot(botConfig, processConfig);
+ break;
+ }
+ default: {
+ console.log(logDisplace + "Root : [ERROR] start -> findProcess -> Unexpected bot type. -> botConfig.type = " + botConfig.type);
+ }
+ }
+ }
+ }
+
+ } catch (err) {
+ console.log(logDisplace + "Root : [ERROR] start -> findProcess -> Unexpected exception. -> err.message = " + err.message);
+ }
+ }
+ }
+
+ if (processFound === false) {
+
+ console.log(logDisplace + "Root : [ERROR] start -> findProcess -> Process listed at the configuration file of CloneExecutor not found at the configuration file of the bot.");
+ console.log(logDisplace + "Root : [ERROR] start -> findProcess -> cloneToExecute.process = " + cloneToExecute.process);
+
+ }
+
+ function runSensorBot(pBotConfig, pProcessConfig, pMonth, pYear) {
+
+ try {
+
+ const DEBUG_MODULE = require(ROOT_DIR + 'DebugLog');
+ let logger;
+
+ logger = DEBUG_MODULE.newDebugLog();
+ logger.bot = pBotConfig;
+
+ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> findProcess -> runSensorBot -> Entering function."); }
+ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> findProcess -> runSensorBot -> pMonth = " + pMonth); }
+ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> findProcess -> runSensorBot -> pYear = " + pYear); }
+
+ let extractionBotMainLoop = EXTRACTION_BOT_MAIN_LOOP_MODULE.newSensorBotProcessMainLoop(pBotConfig, logger);
+ extractionBotMainLoop.initialize(UI_COMMANDS, pProcessConfig, onInitializeReady);
+
+ function onInitializeReady(err) {
+
+ if (err.result === global.DEFAULT_OK_RESPONSE.result) {
+
+ extractionBotMainLoop.run(pMonth, pYear, whenRunFinishes);
+
+ function whenRunFinishes(err) {
+
+ pBotConfig.loopCounter = 0;
+
+ let botId;
+ if (pYear !== undefined) {
+ botId = pBotConfig.devTeam + "." + pBotConfig.codeName + "." + pBotConfig.process + "." + pYear + "." + pMonth;
+ } else {
+ botId = pBotConfig.devTeam + "." + pBotConfig.codeName + "." + pBotConfig.process;
+ }
if (err.result === global.DEFAULT_OK_RESPONSE.result) {
- tradingBotMainLoop.run(pGenes, pTotalInstances, whenRunFinishes);
+ logger.write(MODULE_NAME, "[INFO] start -> findProcess -> runSensorBot -> onInitializeReady -> whenStartFinishes -> Bot execution finished sucessfully.");
+ logger.write(MODULE_NAME, "[INFO] start -> findProcess -> runSensorBot -> onInitializeReady -> whenStartFinishes -> Bot Id = " + botId);
- function whenRunFinishes(err, context) {
+ console.log(logDisplace + "Root : [INFO] start -> findProcess -> runSensorBot -> onInitializeReady -> whenStartFinishes -> botId = " + botId);
+ console.log(logDisplace + "Root : [INFO] start -> findProcess -> runSensorBot -> onInitializeReady -> whenStartFinishes -> Bot execution finished sucessfully.");
- pBotConfig.loopCounter = 0;
-
- let botId;
-
- botId = pBotConfig.devTeam + "." + pBotConfig.codeName + "." + pBotConfig.instance + "." + pBotConfig.process;
-
- if (err.result === global.DEFAULT_OK_RESPONSE.result) {
-
- logger.write(MODULE_NAME, "[INFO] start -> findProcess -> runTradingBot -> createBotInstance -> onInitializeReady -> whenStartFinishes -> Bot execution finished sucessfully.");
- logger.write(MODULE_NAME, "[INFO] start -> findProcess -> runTradingBot -> createBotInstance -> onInitializeReady -> whenStartFinishes -> Bot Id = " + botId);
-
- console.log(logDisplace + "Root : [INFO] start -> findProcess -> runTradingBot -> createBotInstance -> onInitializeReady -> whenStartFinishes -> botId = " + botId);
- console.log(logDisplace + "Root : [INFO] start -> findProcess -> runTradingBot -> createBotInstance -> onInitializeReady -> whenStartFinishes -> Bot execution finished sucessfully.");
- logger.persist();
-
- } else {
-
- logger.write(MODULE_NAME, "[ERROR] start -> findProcess -> runTradingBot -> createBotInstance -> onInitializeReady -> whenStartFinishes -> err = " + err.message);
- logger.write(MODULE_NAME, "[ERROR] start -> findProcess -> runTradingBot -> createBotInstance -> onInitializeReady -> whenStartFinishes -> Execution will be stopped. ");
- logger.write(MODULE_NAME, "[ERROR] start -> findProcess -> runTradingBot -> createBotInstance -> onInitializeReady -> whenStartFinishes -> Bye.");
- logger.write(MODULE_NAME, "[ERROR] start -> findProcess -> runTradingBot -> createBotInstance -> onInitializeReady -> whenStartFinishes -> Bot Id = " + botId);
- console.log(logDisplace + "Root : [ERROR] start -> findProcess -> runTradingBot -> createBotInstance -> onInitializeReady -> whenStartFinishes -> Bot execution finished with errors. Please check the logs.");
- logger.persist();
- }
-
- // Update operations module with latest context
- if (context !== undefined) {
- let lastExecution = context.executionHistory[context.executionHistory.length - 1]
- let date = lastExecution[0] / 1000 | 0
- let buyAvgRate = lastExecution[1]
- let sellAvgRate = lastExecution[2]
- let marketRate = lastExecution[7]
- let combinedProfitsA = lastExecution[13]
- let combinedProfitsB = lastExecution[14]
-
- operationsIntegration.updateExecutionResults(date, buyAvgRate, sellAvgRate,
- marketRate, combinedProfitsA, combinedProfitsB)
- }
- }
+ logger.persist();
} else {
- logger.write(MODULE_NAME, "[ERROR] start -> findProcess -> runTradingBot -> createBotInstance -> onInitializeReady -> err = " + err.message);
- logger.write(MODULE_NAME, "[ERROR] start -> findProcess -> runTradingBot -> createBotInstance -> onInitializeReady -> Bot will not be started. ");
- console.log(logDisplace + "Root : [ERROR] start -> findProcess -> runTradingBot -> createBotInstance -> onInitializeReady -> err = " + err.message);
+ logger.write(MODULE_NAME, "[ERROR] start -> findProcess -> runSensorBot -> onInitializeReady -> whenStartFinishes -> err = " + err.message);
+ logger.write(MODULE_NAME, "[ERROR] start -> findProcess -> runSensorBot -> onInitializeReady -> whenStartFinishes -> Execution will be stopped. ");
+ logger.write(MODULE_NAME, "[ERROR] start -> findProcess -> runSensorBot -> onInitializeReady -> whenStartFinishes -> Bye.");
+ logger.write(MODULE_NAME, "[ERROR] start -> findProcess -> runSensorBot -> onInitializeReady -> whenStartFinishes -> Bot Id = " + botId);
+
+ console.log(logDisplace + "Root : [ERROR] start -> findProcess -> runSensorBot -> onInitializeReady -> whenStartFinishes -> botId = " + botId);
+ console.log(logDisplace + "Root : [ERROR] start -> findProcess -> runSensorBot -> onInitializeReady -> whenStartFinishes -> Bot execution was aborted.");
logger.persist();
}
}
+
+ } else {
+ logger.write(MODULE_NAME, "[ERROR] start -> findProcess -> runSensorBot -> onInitializeReady -> err = " + err.message);
+ logger.write(MODULE_NAME, "[ERROR] start -> findProcess -> runSensorBot -> onInitializeReady -> Bot will not be started. ");
+ console.log(logDisplace + "Root : [ERROR] start -> findProcess -> runSensorBot -> onInitializeReady -> err = " + err.message);
+
+ logger.persist();
}
}
- catch (err) {
- console.log(logDisplace + "Root : [ERROR] start -> findProcess -> runTradingBot -> err = " + err.message);
+ }
+ catch (err) {
+ console.log(logDisplace + "Root : [ERROR] start -> findProcess -> runSensorBot -> err = " + err.message);
+ }
+ }
+
+ function runIndicatorBot(pBotConfig, pProcessConfig, pMonth, pYear) {
+
+ try {
+ const DEBUG_MODULE = require(ROOT_DIR + 'DebugLog');
+ let logger;
+
+ logger = DEBUG_MODULE.newDebugLog();
+ logger.bot = pBotConfig;
+
+ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> findProcess -> runIndicatorBot -> Entering function."); }
+ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> findProcess -> runIndicatorBot -> pMonth = " + pMonth); }
+ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> findProcess -> runIndicatorBot -> pYear = " + pYear); }
+
+ let indicatorBotMainLoop = INDICATOR_BOT_MAIN_LOOP_MODULE.newIndicatorBotProcessMainLoop(pBotConfig, logger);
+ indicatorBotMainLoop.initialize(UI_COMMANDS, pProcessConfig, onInitializeReady);
+
+ function onInitializeReady(err) {
+
+ if (err.result === global.DEFAULT_OK_RESPONSE.result) {
+
+ indicatorBotMainLoop.run(pMonth, pYear, whenRunFinishes);
+
+ function whenRunFinishes(err) {
+
+ pBotConfig.loopCounter = 0;
+
+ let botId;
+ if (pYear !== undefined) {
+ botId = pBotConfig.devTeam + "." + pBotConfig.codeName + "." + pBotConfig.process + "." + pYear + "." + pMonth;
+ } else {
+ botId = pBotConfig.devTeam + "." + pBotConfig.codeName + "." + pBotConfig.process;
+ }
+
+ if (err.result === global.DEFAULT_OK_RESPONSE.result) {
+
+ logger.write(MODULE_NAME, "[INFO] start -> findProcess -> runIndicatorBot -> onInitializeReady -> whenStartFinishes -> Bot execution finished sucessfully.");
+ logger.write(MODULE_NAME, "[INFO] start -> findProcess -> runIndicatorBot -> onInitializeReady -> whenStartFinishes -> Bot Id = " + botId);
+
+ console.log(logDisplace + "Root : [INFO] start -> findProcess -> runIndicatorBot -> onInitializeReady -> whenStartFinishes -> botId = " + botId);
+ console.log(logDisplace + "Root : [INFO] start -> findProcess -> runIndicatorBot -> onInitializeReady -> whenStartFinishes -> Bot execution finished sucessfully.");
+
+ logger.persist();
+
+ } else {
+
+ logger.write(MODULE_NAME, "[ERROR] start -> findProcess -> runIndicatorBot -> onInitializeReady -> whenStartFinishes -> err = " + err.message);
+ logger.write(MODULE_NAME, "[ERROR] start -> findProcess -> runIndicatorBot -> onInitializeReady -> whenStartFinishes -> Execution will be stopped. ");
+ logger.write(MODULE_NAME, "[ERROR] start -> findProcess -> runIndicatorBot -> onInitializeReady -> whenStartFinishes -> Bye.");
+ logger.write(MODULE_NAME, "[ERROR] start -> findProcess -> runIndicatorBot -> onInitializeReady -> whenStartFinishes -> Bot Id = " + botId);
+ console.log(logDisplace + "Root : [ERROR] start -> findProcess -> runIndicatorBot -> onInitializeReady -> whenStartFinishes -> Bot execution finished with errors. Please check the logs.");
+ logger.persist();
+ }
+ }
+
+ } else {
+ logger.write(MODULE_NAME, "[ERROR] start -> findProcess -> runIndicatorBot -> onInitializeReady -> err = " + err.message);
+ logger.write(MODULE_NAME, "[ERROR] start -> findProcess -> runIndicatorBot -> onInitializeReady -> Failed to initialize the bot. ");
+ console.log(logDisplace + "Root : [ERROR] start -> findProcess -> runIndicatorBot -> onInitializeReady -> err = " + err.message);
+ logger.persist();
+ throw new Error("Root -> start -> findProcess -> runIndicatorBot -> onInitializeReady -> Failed to initialize the bot.")
+ }
}
}
+ catch (err) {
+ console.log(logDisplace + "Root : [ERROR] start -> findProcess -> runIndicatorBot -> err = " + err.message);
+ }
}
- catch (err) {
- console.log(logDisplace + "Root : [ERROR] start -> findProcess -> err.message = " + err.message);
- return;
+
+ function runTradingBot(pBotConfig, pProcessConfig) {
+
+ try {
+
+ if (FULL_LOG === true) { console.log(logDisplace + "[INFO] start -> findProcess -> runTradingBot -> Entering function."); }
+
+ if (pBotConfig.genes !== undefined) {
+
+ /* Here, based on the gene we will create one instance for each combination of genes */
+
+ let valueMatrix = [];
+
+ for (let i = 0; i < pBotConfig.genes.length; i++) {
+
+ let gene = pBotConfig.genes[i];
+
+ let possibleValues = [];
+
+ for (let j = gene.lowerLimit; j <= gene.upperLimit; j++) {
+
+ possibleValues.push(j);
+
+ }
+
+ valueMatrix.push(possibleValues);
+
+ }
+
+ /*
+ Now we have all the possible genes values in a multi-dimensional matrix.
+ We will go thorugh each of the elements of each dimension and get each combination possible with the other dimmensions.
+ */
+
+ let combinations = [];
+ let combination = [];
+ let dimensionIndex = 0;
+
+ calculateCombinations(dimensionIndex, combination);
+
+ function calculateCombinations(pDimensionIndex, pCombination) {
+
+ let dimension = valueMatrix[pDimensionIndex];
+
+ for (let j = 0; j < dimension.length; j++) {
+
+ let copy = JSON.parse(JSON.stringify(pCombination));
+
+ let value = dimension[j];
+ copy.push(value);
+
+ if (pDimensionIndex < valueMatrix.length - 1) {
+
+ calculateCombinations(pDimensionIndex + 1, copy);
+
+ } else {
+
+ combinations.push(copy);
+
+ }
+ }
+ }
+
+ /* At this point we have an array with all the possible combinations, we just need to create an instance for each one and set the genes according to that. */
+
+ for (let i = 0; i < combinations.length; i++) {
+
+ let botConfig = JSON.parse(JSON.stringify(pBotConfig));
+ let combination = combinations[i];
+ let genes = {};
+ let clonKey = "";
+
+ for (let j = 0; j < botConfig.genes.length; j++) {
+
+ genes[botConfig.genes[j].name] = combination[j];
+ clonKey = clonKey + "." + combination[j];
+
+ }
+
+ let clonName = botConfig.codeName + "-" + "Clon" + clonKey;
+ clonName += ".1.0";
+
+ if (global.CURRENT_EXECUTION_AT === "Node") {
+ clonName += "-" + process.env.CLONE_ID;
+ }
+
+ botConfig.filePathRoot = botConfig.devTeam + "/" + clonName + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + botConfig.dataSetVersion;
+
+ botConfig.instance = clonName;
+ botConfig.instanceIndex = i;
+
+ setTimeout(execute, i * Math.random() * 10 * 1000);
+
+ function execute() {
+
+ createBotInstance(genes, combinations.length, botConfig);
+
+ }
+ }
+ } else {
+
+ /* If the bot does not have any genes at all */
+
+ let genes = {};
+ let clonName = botConfig.codeName;
+
+ if (global.CURRENT_EXECUTION_AT === "Node") {
+ clonName += "-" + process.env.CLONE_ID;
+ }
+
+ clonName += ".1.0";
+
+ botConfig.filePathRoot = botConfig.devTeam + "/" + clonName + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + botConfig.dataSetVersion;
+
+ pBotConfig.instance = clonName;
+ pBotConfig.instanceIndex = 0;
+
+ createBotInstance(genes, 1, pBotConfig);
+
+ }
+
+
+ function createBotInstance(pGenes, pTotalInstances, pBotConfig) {
+
+ const DEBUG_MODULE = require(ROOT_DIR + 'DebugLog');
+ let logger;
+
+ logger = DEBUG_MODULE.newDebugLog();
+ logger.bot = pBotConfig;
+ pBotConfig.timePeriodFileStorage = global.EXECUTION_CONFIG.timePeriodFileStorage
+ pBotConfig.dataSet = global.EXECUTION_CONFIG.dataSet
+
+ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> findProcess -> runTradingBot -> createBotInstance -> Entering function."); }
+
+ let tradingBotMainLoop = TRADING_BOT_MAIN_LOOP_MODULE.newTradingBotProcessMainLoop(pBotConfig, logger);
+ tradingBotMainLoop.initialize(UI_COMMANDS, pProcessConfig, onInitializeReady);
+
+ function onInitializeReady(err) {
+
+ if (err.result === global.DEFAULT_OK_RESPONSE.result) {
+
+ tradingBotMainLoop.run(pGenes, pTotalInstances, whenRunFinishes);
+
+ function whenRunFinishes(err) {
+
+ pBotConfig.loopCounter = 0;
+
+ let botId;
+
+ botId = pBotConfig.devTeam + "." + pBotConfig.codeName + "." + pBotConfig.instance + "." + pBotConfig.process;
+
+ if (err.result === global.DEFAULT_OK_RESPONSE.result) {
+
+ logger.write(MODULE_NAME, "[INFO] start -> findProcess -> runTradingBot -> createBotInstance -> onInitializeReady -> whenStartFinishes -> Bot execution finished sucessfully.");
+ logger.write(MODULE_NAME, "[INFO] start -> findProcess -> runTradingBot -> createBotInstance -> onInitializeReady -> whenStartFinishes -> Bot Id = " + botId);
+
+ console.log(logDisplace + "Root : [INFO] start -> findProcess -> runTradingBot -> createBotInstance -> onInitializeReady -> whenStartFinishes -> botId = " + botId);
+ console.log(logDisplace + "Root : [INFO] start -> findProcess -> runTradingBot -> createBotInstance -> onInitializeReady -> whenStartFinishes -> Bot execution finished sucessfully.");
+ logger.persist();
+
+ } else {
+
+ logger.write(MODULE_NAME, "[ERROR] start -> findProcess -> runTradingBot -> createBotInstance -> onInitializeReady -> whenStartFinishes -> err = " + err.message);
+ logger.write(MODULE_NAME, "[ERROR] start -> findProcess -> runTradingBot -> createBotInstance -> onInitializeReady -> whenStartFinishes -> Execution will be stopped. ");
+ logger.write(MODULE_NAME, "[ERROR] start -> findProcess -> runTradingBot -> createBotInstance -> onInitializeReady -> whenStartFinishes -> Bye.");
+ logger.write(MODULE_NAME, "[ERROR] start -> findProcess -> runTradingBot -> createBotInstance -> onInitializeReady -> whenStartFinishes -> Bot Id = " + botId);
+ console.log(logDisplace + "Root : [ERROR] start -> findProcess -> runTradingBot -> createBotInstance -> onInitializeReady -> whenStartFinishes -> Bot execution finished with errors. Please check the logs.");
+ logger.persist();
+ }
+ }
+
+ } else {
+ logger.write(MODULE_NAME, "[ERROR] start -> findProcess -> runTradingBot -> createBotInstance -> onInitializeReady -> err = " + err.message);
+ logger.write(MODULE_NAME, "[ERROR] start -> findProcess -> runTradingBot -> createBotInstance -> onInitializeReady -> Bot will not be started. ");
+ console.log(logDisplace + "Root : [ERROR] start -> findProcess -> runTradingBot -> createBotInstance -> onInitializeReady -> err = " + err.message);
+
+ logger.persist();
+ }
+ }
+ }
+ }
+ catch (err) {
+ console.log(logDisplace + "Root : [ERROR] start -> findProcess -> runTradingBot -> err = " + err.message);
+ }
}
+
+ }
+ catch (err) {
+ console.log(logDisplace + "Root : [ERROR] start -> findProcess -> err.message = " + err.message);
+ return;
}
}
+
}
}
diff --git a/Run.js b/Run.js
index 2abe7cb4c..8231644e9 100644
--- a/Run.js
+++ b/Run.js
@@ -1,13 +1,13 @@
require('dotenv').config()
global.CURRENT_ENVIRONMENT = "Develop";
-global.CURRENT_EXECUTION_AT = "Cloud";
+global.CURRENT_EXECUTION_AT = "Node";
global.SHALL_BOT_STOP = false;
-global.AT_BREAKPOINT = false; // This is used only when running at the browser.
+global.AT_BREAKPOINT = false; // This is used only when running at the browser.
global.RUN_AS_TEAM = false;
/* Default parameters can be changed by the execution configuration */
-global.EXCHANGE_NAME = "Poloniex";
+global.EXCHANGE_NAME = process.env.EXCHANGE_NAME;
global.MARKET = {
assetA: "USDT",
assetB: "BTC"
@@ -16,25 +16,17 @@ global.MARKET = {
process.on('uncaughtException', function (err) {
console.log('[INFO] Run -> uncaughtException -> err.message = ' + err.message);
console.log('[INFO] Run -> uncaughtException -> err.stack = ', err.stack);
- return;
+ process.exit(1)
});
process.on('unhandledRejection', (reason, p) => {
- console.log('[INFO] Run -> unhandledRejection -> reason = ' + reason);
+ console.log('[INFO] Run -> unhandledRejection -> reason = ' + JSON.stringify(reason));
console.log('[INFO] Run -> unhandledRejection -> p = ' + JSON.stringify(p));
- return;
+ process.exit(1)
});
process.on('exit', function (code) {
- try {
- console.log('[INFO] Run -> process.on.exit -> About to exit -> code = ' + code);
- return;
- }
- catch (err) {
- console.log("[ERROR] Run -> process.on.exit -> Error Logging Error Code.");
- console.log("[ERROR] Run -> process.on.exit -> err.message = " + err.message);
- return;
- }
+ console.log('[INFO] Run -> process.on.exit -> About to exit -> code = ' + code);
});
readExecutionConfiguration();
@@ -80,7 +72,7 @@ function readExecutionConfiguration() {
backtest: backtest,
competition: competition
}
- } else if (process.env.TYPE === 'Indicator' || process.env.TYPE === 'Extractor') {
+ } else if (process.env.TYPE === 'Indicator' || process.env.TYPE === 'Sensor') {
let allMonths = {
run: "false",
minYear: process.env.MIN_YEAR,
@@ -92,7 +84,9 @@ function readExecutionConfiguration() {
month: process.env.MONTH
}
let noTime = {
- run: "false"
+ run: "false",
+ beginDatetime: process.env.BEGIN_DATE_TIME,
+ resumeExecution: process.env.RESUME_EXECUTION
}
let fixedInterval = {
run: "false",
@@ -112,17 +106,20 @@ function readExecutionConfiguration() {
startMode[process.env.START_MODE].run = "true"
- let executionList = [{
+ let cloneToExecute = {
enabled: "true",
devTeam: process.env.DEV_TEAM,
bot: process.env.BOT,
process: process.env.PROCESS,
repo: global.CURRENT_BOT_REPO
- }]
+ }
global.EXECUTION_CONFIG = {
- executionList: executionList,
- startMode: startMode
+ cloneToExecute: cloneToExecute,
+ startMode: startMode,
+ timePeriod: getTimePeriod(process.env.TIME_PERIOD),
+ timePeriodFileStorage: process.env.TIME_PERIOD,
+ dataSet: process.env.DATA_SET
};
readStoragePermissions();
@@ -130,13 +127,44 @@ function readExecutionConfiguration() {
catch (err) {
console.log("[ERROR] readExecutionConfiguration -> err = " + err.message);
+ console.log("[ERROR] readExecutionConfiguration -> Please verify that the Start Mode for the type of Bot configured applies to that type.");
console.log("[ERROR] readExecutionConfiguration -> err = " + err.stack);
}
}
-function readStoragePermissions() {
- let filePath;
+function getTimePeriod(timePeriod){
+ if(timePeriod !== undefined){
+ try {
+ let timePeriodMap = new Map()
+ timePeriodMap.set("24-hs", 86400000)
+ timePeriodMap.set("12-hs", 43200000)
+ timePeriodMap.set("08-hs", 28800000)
+ timePeriodMap.set("06-hs", 21600000)
+ timePeriodMap.set("04-hs", 14400000)
+ timePeriodMap.set("03-hs", 10800000)
+ timePeriodMap.set("02-hs", 7200000)
+ timePeriodMap.set("01-hs", 3600000)
+ timePeriodMap.set("45-min", 2700000)
+ timePeriodMap.set("40-min", 2400000)
+ timePeriodMap.set("30-min", 1800000)
+ timePeriodMap.set("20-min", 1200000)
+ timePeriodMap.set("15-min", 900000)
+ timePeriodMap.set("10-min", 600000)
+ timePeriodMap.set("05-min", 300000)
+ timePeriodMap.set("04-min", 240000)
+ timePeriodMap.set("03-min", 180000)
+ timePeriodMap.set("02-min", 120000)
+ timePeriodMap.set("01-min", 60000)
+ return timePeriodMap.get(timePeriod)
+ } catch (error) {
+ console.log( "[WARN] Run -> readExecutionConfiguration -> getTimePeriod -> Error: ", error);
+ }
+ } else {
+ return undefined
+ }
+}
+function readStoragePermissions() {
try {
console.log( "[INFO] Run -> readStoragePermissions -> Entering function. ");
@@ -186,10 +214,8 @@ function readStoragePermissions() {
startRoot();
}
- }
- catch (err) {
+ } catch (err) {
console.log("[ERROR] Run -> readStoragePermissions -> err = " + err.message);
- console.log("[HINT] Run -> readStoragePermissions -> You need to have a file at this path -> " + filePath);
}
}
diff --git a/ExtractionBotProcessMainLoop.js b/SensorBotProcessMainLoop.js
similarity index 89%
rename from ExtractionBotProcessMainLoop.js
rename to SensorBotProcessMainLoop.js
index e3caf7318..87a4ccf86 100644
--- a/ExtractionBotProcessMainLoop.js
+++ b/SensorBotProcessMainLoop.js
@@ -1,8 +1,8 @@
-exports.newExtractionBotProcessMainLoop = function newExtractionBotProcessMainLoop(bot, parentLogger) {
+exports.newSensorBotProcessMainLoop = function newSensorBotProcessMainLoop(bot, parentLogger) {
const ROOT_DIR = './';
- const MODULE_NAME = "Extraction Bot Process Main Loop";
+ const MODULE_NAME = "Sensor Bot Process Main Loop";
const FULL_LOG = true;
let USER_BOT_MODULE;
@@ -13,7 +13,7 @@
const DEBUG_MODULE = require(ROOT_DIR + 'DebugLog');
let logger; // We need this here in order for the loopHealth function to work and be able to rescue the loop when it gets in trouble.
- let nextLoopTimeoutHandle;
+ let nextLoopTimeoutHandle;
let checkLoopHealthHandle;
let thisObject = {
@@ -22,7 +22,7 @@
};
let processConfig;
- let UI_COMMANDS;
+ let UI_COMMANDS;
return thisObject;
@@ -48,24 +48,10 @@
let filePath;
- switch (global.CURRENT_EXECUTION_AT) { // This is what determines if the bot is loaded from the devTeam or an endUser copy.
- case "Cloud": {
- if (global.RUN_AS_TEAM) {
- filePath = global.DEV_TEAM + "/" + "bots" + "/" + bot.repo + "/" + pProcessConfig.name; // DevTeams bots only are run at the cloud.
- } else {
- filePath = global.DEV_TEAM + "/" + "members" + "/" + global.USER_LOGGED_IN + "/" + global.CURRENT_BOT_REPO + "/" + pProcessConfig.name; // DevTeam Members bots only are run at the browser.
- }
- break;
- }
- case "Browser": {
- filePath = global.DEV_TEAM + "/" + "members" + "/" + global.USER_LOGGED_IN + "/" + global.CURRENT_BOT_REPO + "/" + pProcessConfig.name; // DevTeam Members bots only are run at the browser.
- break;
- }
- default: {
- parentLogger.write(MODULE_NAME, "[ERROR] initialize -> onInizialized -> CURRENT_EXECUTION_AT must be either 'Cloud' or 'Browser'.");
- parentLogger.write(MODULE_NAME, "[ERROR] initialize -> onInizialized -> global.CURRENT_EXECUTION_AT = " + global.CURRENT_EXECUTION_AT);
- callBackFunction(global.DEFAULT_FAIL_RESPONSE);
- return; }
+ if (global.RUN_AS_TEAM) {
+ filePath = global.DEV_TEAM + "/" + "bots" + "/" + bot.repo + "/" + pProcessConfig.name; // DevTeams bots only are run at the cloud.
+ } else {
+ filePath = global.DEV_TEAM + "/" + "members" + "/" + global.USER_LOGGED_IN + "/" + global.CURRENT_BOT_REPO + "/" + pProcessConfig.name; // DevTeam Members bots only are run at the browser.
}
const CLOUD_REQUIRE = require(ROOT_DIR + 'CloudRequire');
@@ -84,22 +70,7 @@
USER_BOT_MODULE = pMODULE;
- switch (global.CURRENT_EXECUTION_AT) {
- case "Cloud": {
- filePath = global.DEV_TEAM + "/" + "bots" + "/" + bot.repo;
- break;
- }
- case "Browser": {
- filePath = global.DEV_TEAM + "/" + "members" + "/" + global.USER_LOGGED_IN + "/" + global.CURRENT_BOT_REPO;
- break;
- }
- default: {
- parentLogger.write(MODULE_NAME, "[ERROR] initialize -> onInizialized -> onBotDownloaded -> CURRENT_EXECUTION_AT must be either 'Cloud' or 'Browser'.");
- parentLogger.write(MODULE_NAME, "[ERROR] initialize -> onInizialized -> onBotDownloaded -> global.CURRENT_EXECUTION_AT = " + global.CURRENT_EXECUTION_AT);
- callBackFunction(global.DEFAULT_FAIL_RESPONSE);
- return;
- }
- }
+ filePath = global.DEV_TEAM + "/" + "bots" + "/" + bot.repo;
cloudRequire.downloadCommons(cloudStorage, filePath, onCommonsDownloaded);
@@ -134,7 +105,7 @@
try {
if (FULL_LOG === true) { parentLogger.write(MODULE_NAME, "[INFO] run -> Entering function."); }
- bot.enableCheckLoopHealth = true;
+ bot.enableCheckLoopHealth = true;
let fixedTimeLoopIntervalHandle;
@@ -173,7 +144,7 @@
const UTILITIES = require(ROOT_DIR + 'CloudUtilities');
const STATUS_REPORT = require(ROOT_DIR + 'StatusReport');
- const EXCHANGE_API = require(ROOT_DIR + 'Exchange/ExchangeAPI');
+ const EXCHANGE_API = require('@superalgos/exchangegateway');
const STATUS_DEPENDENCIES = require(ROOT_DIR + 'StatusDependencies');
/* We define the datetime for the process that we are running now. This will be the official processing time for both the infraestructure and the bot. */
@@ -182,8 +153,8 @@
/* High level log entry */
- console.log(bot.processDatetime.toISOString() + " " + pad(bot.codeName, 20) + " " + pad(bot.process, 30) + " " + pad(pMonth, 2) + "/" + pad(pYear, 4)
- + " Entered into Main Loop # " + pad(Number(bot.loopCounter), 8));
+ console.log(new Date().toISOString() + " " + pad(bot.codeName, 20) + " " + pad(bot.process, 30) + " " + pad(pMonth, 2) + "/" + pad(pYear, 4)
+ + " Entered into Main Loop # " + pad(Number(bot.loopCounter), 8) + " bot.processDatetime = " + bot.processDatetime.toISOString());
/* We will prepare first the infraestructure needed for the bot to run. There are 3 modules we need to sucessfullly initialize first. */
@@ -275,7 +246,7 @@
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> initializeExchangeAPI -> Entering function."); }
- exchangeAPI = EXCHANGE_API.newExchangeAPI(bot, logger);
+ exchangeAPI = EXCHANGE_API.newExchangeAPI(logger, global.EXCHANGE_NAME);
exchangeAPI.initialize(onInizialized);
@@ -610,7 +581,7 @@
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> loopControl -> onContinue -> Entering function."); }
- /* Extraction bots are going to be executed after a configured period of time after the last execution ended. This is to avoid overlapping executions. */
+ /* Sensor bots are going to be executed after a configured period of time after the last execution ended. This is to avoid overlapping executions. */
switch (nextWaitTime) {
case 'Normal': {
@@ -620,7 +591,7 @@
logger.persist();
return;
} else {
- if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> loopControl -> Restarting Loop in " + (processConfig.normalWaitTime / 1000) + " seconds."); }
+ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> loopControl -> Restarting Loop in " + (processConfig.normalWaitTime / 1000) + " seconds."); }
checkLoopHealthHandle = setTimeout(checkLoopHealth, processConfig.normalWaitTime * 5, bot.loopCounter);
nextLoopTimeoutHandle = setTimeout(loop, processConfig.normalWaitTime);
logger.persist();
@@ -664,7 +635,7 @@
function checkLoopHealth(pLastLoop) {
- if (global.CURRENT_EXECUTION_AT !== "Cloud") {
+ if (global.CURRENT_EXECUTION_AT !== "Node") {
return;
}
@@ -714,33 +685,7 @@
if (err.result === global.DEFAULT_OK_RESPONSE.result) {
- let filePath;
-
- switch (global.CURRENT_EXECUTION_AT) { // This is what determines if the bot is loaded from the devTeam or an endUser copy.
- case "Cloud": {
- filePath = global.DEV_TEAM + "/" + "AACloud"; // DevTeams bots only are run at the cloud.
- break;
- }
- case "Browser": {
- if (global.SHALL_BOT_STOP === false) {
- continueCallBack();
- } else {
- stopCallBack();
- }
- return;
- }
- default: {
- logger.write(MODULE_NAME, "[ERROR] run -> loop -> shallWeStop -> onInizialized -> CURRENT_EXECUTION_AT must be either 'Cloud' or 'Browser'.");
- logger.write(MODULE_NAME, "[ERROR] run -> loop -> shallWeStop -> onInizialized -> global.CURRENT_EXECUTION_AT = " + global.CURRENT_EXECUTION_AT);
- logger.persist();
- clearInterval(fixedTimeLoopIntervalHandle);
- clearTimeout(nextLoopTimeoutHandle);
- clearTimeout(checkLoopHealthHandle);
- bot.enableCheckLoopHealth = false;
- callBackFunction(global.DEFAULT_FAIL_RESPONSE);
- return;
- }
- }
+ let filePath = global.DEV_TEAM + "/" + "AACloud"; // DevTeams bots only are run at the cloud.
let fileName = "this.config.json";
@@ -750,7 +695,7 @@
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
- /*
+ /*
If for any reason this config file cannot be read, we are not going to abort the loop for that. Instead we are going to assume
that there are no instructions to stop and we will keep the show running.
*/
diff --git a/StatusDependencies.js b/StatusDependencies.js
index 635efdf37..2ce421ef8 100644
--- a/StatusDependencies.js
+++ b/StatusDependencies.js
@@ -6,6 +6,7 @@
const MODULE_NAME = "Status Dependencies";
let thisObject = {
+ config: undefined,
statusReports: new Map(),
initialize: initialize,
keys: []
@@ -22,6 +23,8 @@
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] initialize -> Entering function."); }
+ thisObject.config = pStatusDependenciesConfig;
+
/*
For each dependency declared at the bot config, we will initialize the status report, and load it as part of this initialization process.
diff --git a/TradingBotProcessMainLoop.js b/TradingBotProcessMainLoop.js
index 31e20790b..f217949d9 100644
--- a/TradingBotProcessMainLoop.js
+++ b/TradingBotProcessMainLoop.js
@@ -8,12 +8,13 @@
let USER_BOT_MODULE;
let COMMONS_MODULE;
- const BLOB_STORAGE = require(ROOT_DIR + 'BlobStorage');
+ const operationsIntegration = require('./Integrations/OperationsModuleIntegration')
+ const BLOB_STORAGE = require(ROOT_DIR + 'BlobStorage');
const DEBUG_MODULE = require(ROOT_DIR + 'DebugLog');
let logger; // We need this here in order for the loopHealth function to work and be able to rescue the loop when it gets in trouble.
- let nextLoopTimeoutHandle;
+ let nextLoopTimeoutHandle;
let checkLoopHealthHandle;
let thisObject = {
@@ -24,7 +25,7 @@
bot["botCache"] = new Map();
let processConfig;
let cloudStorage;
- let UI_COMMANDS;
+ let UI_COMMANDS;
return thisObject;
@@ -51,17 +52,13 @@
let filePath;
switch (global.CURRENT_EXECUTION_AT) { // This is what determines if the bot is loaded from the devTeam or an endUser copy.
- case "Cloud": {
+ case "Node": {
if (global.RUN_AS_TEAM) {
filePath = global.DEV_TEAM + "/" + "bots" + "/" + bot.repo + "/" + pProcessConfig.name; // DevTeams bots only are run at the cloud.
} else {
filePath = global.DEV_TEAM + "/" + "members" + "/" + global.USER_LOGGED_IN + "/" + global.CURRENT_BOT_REPO + "/" + pProcessConfig.name; // DevTeam Members bots only are run at the browser.
}
-
- break;
- }
- case "Browser": {
- filePath = global.DEV_TEAM + "/" + "members" + "/" + global.USER_LOGGED_IN + "/" + global.CURRENT_BOT_REPO + "/" + pProcessConfig.name; // DevTeam Members bots only are run at the browser.
+
break;
}
case "IDE": {
@@ -69,7 +66,7 @@
break;
}
default: {
- parentLogger.write(MODULE_NAME, "[ERROR] initialize -> onInizialized -> CURRENT_EXECUTION_AT must be either 'Cloud' or 'Browser'.");
+ parentLogger.write(MODULE_NAME, "[ERROR] initialize -> onInizialized -> CURRENT_EXECUTION_AT must be either 'Node' or 'IDE'.");
parentLogger.write(MODULE_NAME, "[ERROR] initialize -> onInizialized -> global.CURRENT_EXECUTION_AT = " + global.CURRENT_EXECUTION_AT);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
return;
@@ -92,22 +89,7 @@
USER_BOT_MODULE = pMODULE;
- switch (global.CURRENT_EXECUTION_AT) {
- case "Cloud": {
- filePath = global.DEV_TEAM + "/" + "bots" + "/" + bot.repo;
- break;
- }
- case "Browser": {
- filePath = global.DEV_TEAM + "/" + "members" + "/" + global.USER_LOGGED_IN + "/" + global.CURRENT_BOT_REPO;
- break;
- }
- default: {
- parentLogger.write(MODULE_NAME, "[ERROR] initialize -> onInizialized -> onBotDownloaded -> CURRENT_EXECUTION_AT must be either 'Cloud' or 'Browser'.");
- parentLogger.write(MODULE_NAME, "[ERROR] initialize -> onInizialized -> onBotDownloaded -> global.CURRENT_EXECUTION_AT = " + global.CURRENT_EXECUTION_AT);
- callBackFunction(global.DEFAULT_FAIL_RESPONSE);
- return;
- }
- }
+ filePath = global.DEV_TEAM + "/" + "bots" + "/" + bot.repo;
cloudRequire.downloadCommons(cloudStorage, filePath, onCommonsDownloaded);
@@ -144,7 +126,7 @@
try {
if (FULL_LOG === true) { parentLogger.write(MODULE_NAME, "[INFO] run -> Entering function."); }
- bot.enableCheckLoopHealth = true;
+ bot.enableCheckLoopHealth = true;
let fixedTimeLoopIntervalHandle;
@@ -181,7 +163,7 @@
/* We define here all the modules that the rest of the infraestructure, including the bots themselves can consume. */
const UTILITIES = require(ROOT_DIR + 'CloudUtilities');
- const EXCHANGE_API = require(ROOT_DIR + 'Exchange/ExchangeAPI');
+ const EXCHANGE_API = require('@superalgos/exchangegateway');
const CONTEXT = require(ROOT_DIR + 'Context');
const ASSISTANT = require(ROOT_DIR + 'Assistant');
const STATUS_REPORT = require(ROOT_DIR + 'StatusReport');
@@ -247,7 +229,7 @@
} else {
- bot.processDatetime = new Date(bot.backtest.beginDatetime); // Set the starting time as the configured beginDatetime.
+ bot.processDatetime = new Date(bot.backtest.beginDatetime); // Set the starting time as the configured beginDatetime.
}
@@ -262,7 +244,7 @@
} else {
- bot.processDatetime = new Date(bot.processDatetime.valueOf() + timePeriod); // We advance time here.
+ bot.processDatetime = new Date(bot.processDatetime.valueOf() + timePeriod); // We advance time here.
if (UI_COMMANDS.eventHandler !== undefined) {
@@ -275,15 +257,15 @@
if (UI_COMMANDS.endDatetime !== undefined) {
- endDatetime = new Date(UI_COMMANDS.endDatetime.valueOf());
+ endDatetime = new Date(UI_COMMANDS.endDatetime.valueOf());
} else {
- endDatetime = new Date(bot.backtest.endDatetime);
+ endDatetime = new Date(bot.backtest.endDatetime);
}
- if (global.CURRENT_EXECUTION_AT === "Cloud") {
+ if (global.CURRENT_EXECUTION_AT === "Node") {
if (bot.processDatetime.valueOf() > endDatetime.valueOf()) {
@@ -294,7 +276,7 @@
clearTimeout(nextLoopTimeoutHandle);
clearTimeout(checkLoopHealthHandle);
bot.enableCheckLoopHealth = false;
- callBackFunction(global.DEFAULT_OK_RESPONSE, context);
+ callBackFunction(global.DEFAULT_OK_RESPONSE);
return;
}
}
@@ -322,7 +304,7 @@
}
- if (global.CURRENT_EXECUTION_AT === "Cloud") {
+ if (global.CURRENT_EXECUTION_AT === "Node") {
let beginDatetime = new Date(bot.competition.beginDatetime);
@@ -346,7 +328,7 @@
clearTimeout(nextLoopTimeoutHandle);
clearTimeout(checkLoopHealthHandle);
bot.enableCheckLoopHealth = false;
- callBackFunction(global.DEFAULT_OK_RESPONSE, context);
+ callBackFunction(global.DEFAULT_OK_RESPONSE);
return;
}
}
@@ -380,7 +362,7 @@
+ " " + bot.startMode + " Entered into Main Loop # " + pad(Number(bot.loopCounter), 8) + " bot.processDatetime = " + bot.processDatetime.toISOString());
/* We will prepare first the infraestructure needed for the bot to run. There are 3 modules we need to sucessfullly initialize first. */
-
+
let exchangeAPI;
let assistant;
let userBot;
@@ -536,7 +518,7 @@
callBackFunction(err);
}
}
-
+
function initializeContext() {
try {
@@ -616,7 +598,7 @@
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> initializeExchangeAPI -> Entering function."); }
- exchangeAPI = EXCHANGE_API.newExchangeAPI(bot, logger);
+ exchangeAPI = EXCHANGE_API.newExchangeAPI(logger, global.EXCHANGE_NAME);
exchangeAPI.initialize(onInizialized);
@@ -864,7 +846,6 @@
clearTimeout(nextLoopTimeoutHandle);
clearTimeout(checkLoopHealthHandle);
bot.enableCheckLoopHealth = false;
- assistant.sendEmail("FAIL", "Operation Failed. Aborting the process. err = " + err.message, emailList = global.EMAIL_CONFIG.adminList);
callBackFunction(err);
return;
}
@@ -877,7 +858,6 @@
clearTimeout(nextLoopTimeoutHandle);
clearTimeout(checkLoopHealthHandle);
bot.enableCheckLoopHealth = false;
- assistant.sendEmail("FAIL", "Operation Failed. Aborting the process. err = " + err.message, emailList = global.EMAIL_CONFIG.adminList);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
return;
}
@@ -890,7 +870,6 @@
clearTimeout(nextLoopTimeoutHandle);
clearTimeout(checkLoopHealthHandle);
bot.enableCheckLoopHealth = false;
- assistant.sendEmail("FAIL", "Operation Failed. Aborting the process. err = " + err.message, emailList = global.EMAIL_CONFIG.adminList);
callBackFunction(err);
}
}
@@ -902,7 +881,6 @@
clearTimeout(nextLoopTimeoutHandle);
clearTimeout(checkLoopHealthHandle);
bot.enableCheckLoopHealth = false;
- assistant.sendEmail("FAIL", "Operation Failed. Aborting the process. err = " + err.message, emailList = global.EMAIL_CONFIG.adminList);
callBackFunction(err);
}
}
@@ -925,7 +903,7 @@
case global.DEFAULT_OK_RESPONSE.result: {
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> saveContext -> onFinished -> Execution finished well."); }
nextWaitTime = 'Normal';
- loopControl(nextWaitTime);
+ updateClonesModule();
return;
}
case global.DEFAULT_RETRY_RESPONSE.result: { // Something bad happened, but if we retry in a while it might go through the next time.
@@ -984,6 +962,41 @@
}
}
+ async function updateClonesModule() {
+
+ try {
+
+ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> updateClonesModule -> Entering function."); }
+
+ if (global.CURRENT_EXECUTION_AT === "Node") {
+
+ // Update clones module with latest context informations
+
+ let lastExecution = context.newHistoryRecord
+ let date = lastExecution.date / 1000 | 0
+ let buyAvgRate = lastExecution.buyAvgRate
+ let sellAvgRate = lastExecution.sellAvgRate
+ let marketRate = lastExecution.marketRate
+ let combinedProfitsA = lastExecution.combinedProfitsA
+ let combinedProfitsB = lastExecution.combinedProfitsB
+
+ await operationsIntegration.updateExecutionResults(date, buyAvgRate, sellAvgRate,
+ marketRate, combinedProfitsA, combinedProfitsB)
+
+ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> updateClonesModule -> Clones Module Updated."); }
+ }
+
+ nextWaitTime = 'Normal';
+ loopControl(nextWaitTime);
+
+ } catch (err) {
+ logger.write(MODULE_NAME, "[ERROR] run -> loop -> updateClonesModule -> err = " + err.message);
+ logger.write(MODULE_NAME, "[ERROR] run -> loop -> updateClonesModule -> Execution will continue anyways. ");
+ nextWaitTime = 'Normal';
+ loopControl(nextWaitTime);
+ }
+ }
+
function loopControl(nextWaitTime) {
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> loopControl -> Entering function."); }
@@ -1003,7 +1016,7 @@
clearTimeout(nextLoopTimeoutHandle);
clearTimeout(checkLoopHealthHandle);
bot.enableCheckLoopHealth = false;
- callBackFunction(global.DEFAULT_OK_RESPONSE, context);
+ callBackFunction(global.DEFAULT_OK_RESPONSE);
return;
}
@@ -1047,7 +1060,7 @@
function checkLoopHealth(pLastLoop) {
- if (global.CURRENT_EXECUTION_AT !== "Cloud") {
+ if (global.CURRENT_EXECUTION_AT !== "Node") {
return;
}
@@ -1099,33 +1112,7 @@
if (err.result === global.DEFAULT_OK_RESPONSE.result) {
- let filePath;
-
- switch (global.CURRENT_EXECUTION_AT) { // This is what determines if the bot is loaded from the devTeam or an endUser copy.
- case "Cloud": {
- filePath = global.DEV_TEAM + "/" + "AACloud"; // DevTeams bots only are run at the cloud.
- break;
- }
- case "Browser": {
- if (global.SHALL_BOT_STOP === false) {
- continueCallBack();
- } else {
- stopCallBack();
- }
- return;
- }
- default: {
- logger.write(MODULE_NAME, "[ERROR] run -> loop -> shallWeStop -> onInizialized -> CURRENT_EXECUTION_AT must be either 'Cloud' or 'Browser'.");
- logger.write(MODULE_NAME, "[ERROR] run -> loop -> shallWeStop -> onInizialized -> global.CURRENT_EXECUTION_AT = " + global.CURRENT_EXECUTION_AT);
- logger.persist();
- clearInterval(fixedTimeLoopIntervalHandle);
- clearTimeout(nextLoopTimeoutHandle);
- clearTimeout(checkLoopHealthHandle);
- bot.enableCheckLoopHealth = false;
- callBackFunction(global.DEFAULT_FAIL_RESPONSE);
- return;
- }
- }
+ let filePath = global.DEV_TEAM + "/" + "AACloud"; // DevTeams bots only are run at the cloud.
let fileName = "this.config.json";
@@ -1135,7 +1122,7 @@
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
- /*
+ /*
If for any reason this config file cannot be read, we are not going to abort the loop for that. Instead we are going to assume
that there are no instructions to stop and we will keep the show running.
*/
@@ -1185,7 +1172,7 @@
}
} catch (err) {
- parentLogger.write(MODULE_NAME, "[ERROR] run -> loop -> err = " + err.message);
+ parentLogger.write(MODULE_NAME, "[ERROR] run -> loop -> err = " + err.stack);
clearInterval(fixedTimeLoopIntervalHandle);
clearTimeout(nextLoopTimeoutHandle);
clearTimeout(checkLoopHealthHandle);
diff --git a/package-lock.json b/package-lock.json
index fb0afbaa8..6727351a0 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,9 +1,40 @@
{
- "name": "AACloud",
+ "name": "@superalgos/clone-executor",
"version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
+ "@superalgos/exchangegateway": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/@superalgos/exchangegateway/-/exchangegateway-0.0.1.tgz",
+ "integrity": "sha512-x1u+yOwcADT4741Zmm6z3fk580JmP13FlebpUK0uw6fJ5B77DolqwwIi7Tvzk9ipJVB6IVejcqsgndeuumx8Hw==",
+ "requires": {
+ "apollo-boost": "0.1.16",
+ "assert": "1.4.1",
+ "axios": "0.18.0",
+ "azure-storage": "2.10.2",
+ "dotenv": "6.2.0",
+ "graphql": "14.0.2",
+ "jsonwebtoken": "8.4.0",
+ "lodash": "4.17.11",
+ "nodemailer": "4.6.8",
+ "nonce": "1.0.4",
+ "querystring": "0.2.0",
+ "retry": "0.12.0",
+ "superagent": "5.0.2",
+ "underscore": "1.9.1",
+ "winston": "3.1.0"
+ }
+ },
+ "@superalgos/mqservice": {
+ "version": "0.0.12",
+ "resolved": "https://registry.npmjs.org/@superalgos/mqservice/-/mqservice-0.0.12.tgz",
+ "integrity": "sha1-XOfm592AbBFLemFzkO10plDcwos=",
+ "requires": {
+ "chai": "4.2.0",
+ "mocha": "6.0.2"
+ }
+ },
"@types/async": {
"version": "2.0.49",
"resolved": "https://registry.npmjs.org/@types/async/-/async-2.0.49.tgz",
@@ -26,6 +57,24 @@
"json-schema-traverse": "0.3.1"
}
},
+ "ansi-colors": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz",
+ "integrity": "sha1-V9NbhoboUeLMBMQD8cACA5dqGBM="
+ },
+ "ansi-regex": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
+ "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg="
+ },
+ "ansi-styles": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+ "integrity": "sha1-QfuyAkPlCxK+DwS43tvwdSDOhB0=",
+ "requires": {
+ "color-convert": "1.9.3"
+ }
+ },
"apollo-boost": {
"version": "0.1.16",
"resolved": "https://registry.npmjs.org/apollo-boost/-/apollo-boost-0.1.16.tgz",
@@ -134,10 +183,33 @@
"fclone": "1.0.11"
}
},
- "app-root-path": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/app-root-path/-/app-root-path-2.1.0.tgz",
- "integrity": "sha1-mL9lmTJ+zqGZMJhm6BQDaP0uZGo="
+ "argparse": {
+ "version": "1.0.10",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
+ "integrity": "sha1-vNZ5HqWuCXJeF+WtmIE0zUCz2RE=",
+ "requires": {
+ "sprintf-js": "1.0.3"
+ }
+ },
+ "arr-diff": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz",
+ "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA="
+ },
+ "arr-flatten": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz",
+ "integrity": "sha1-NgSLv/TntH4TZkQxbJlmnqWukfE="
+ },
+ "arr-union": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz",
+ "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ="
+ },
+ "array-unique": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz",
+ "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg="
},
"asn1": {
"version": "0.2.4",
@@ -160,6 +232,16 @@
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
},
+ "assertion-error": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz",
+ "integrity": "sha1-5gtrDo8wG9l+U3UhW9pAbIURjAs="
+ },
+ "assign-symbols": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz",
+ "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c="
+ },
"async": {
"version": "2.6.1",
"resolved": "https://registry.npmjs.org/async/-/async-2.6.1.tgz",
@@ -173,6 +255,11 @@
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
},
+ "atob": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz",
+ "integrity": "sha1-bZUX654DDSQ2ZmZR6GvZ9vE1M8k="
+ },
"aws-sign2": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
@@ -217,6 +304,61 @@
}
}
},
+ "balanced-match": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
+ "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
+ },
+ "base": {
+ "version": "0.11.2",
+ "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz",
+ "integrity": "sha1-e95c7RRbbVUakNuH+DxVi060io8=",
+ "requires": {
+ "cache-base": "1.0.1",
+ "class-utils": "0.3.6",
+ "component-emitter": "1.2.1",
+ "define-property": "1.0.0",
+ "isobject": "3.0.1",
+ "mixin-deep": "1.3.1",
+ "pascalcase": "0.1.1"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
+ "requires": {
+ "is-descriptor": "1.0.2"
+ }
+ },
+ "is-accessor-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+ "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=",
+ "requires": {
+ "kind-of": "6.0.2"
+ }
+ },
+ "is-data-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+ "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=",
+ "requires": {
+ "kind-of": "6.0.2"
+ }
+ },
+ "is-descriptor": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+ "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=",
+ "requires": {
+ "is-accessor-descriptor": "1.0.0",
+ "is-data-descriptor": "1.0.0",
+ "kind-of": "6.0.2"
+ }
+ }
+ }
+ },
"bcrypt-pbkdf": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
@@ -226,6 +368,47 @@
"tweetnacl": "0.14.5"
}
},
+ "brace-expansion": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+ "integrity": "sha1-PH/L9SnYcibz0vUrlm/1Jx60Qd0=",
+ "requires": {
+ "balanced-match": "1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "braces": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz",
+ "integrity": "sha1-WXn9PxTNUxVl5fot8av/8d+u5yk=",
+ "requires": {
+ "arr-flatten": "1.1.0",
+ "array-unique": "0.3.2",
+ "extend-shallow": "2.0.1",
+ "fill-range": "4.0.0",
+ "isobject": "3.0.1",
+ "repeat-element": "1.1.3",
+ "snapdragon": "0.8.2",
+ "snapdragon-node": "2.1.1",
+ "split-string": "3.1.0",
+ "to-regex": "3.0.2"
+ },
+ "dependencies": {
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "requires": {
+ "is-extendable": "0.1.1"
+ }
+ }
+ }
+ },
+ "browser-stdout": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz",
+ "integrity": "sha1-uqVZ7hTO1zRSIputcyZGfGH6vWA="
+ },
"browserify-mime": {
"version": "1.2.9",
"resolved": "https://registry.npmjs.org/browserify-mime/-/browserify-mime-1.2.9.tgz",
@@ -236,16 +419,120 @@
"resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
"integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk="
},
+ "cache-base": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz",
+ "integrity": "sha1-Cn9GQWgxyLZi7jb+TnxZ129marI=",
+ "requires": {
+ "collection-visit": "1.0.0",
+ "component-emitter": "1.2.1",
+ "get-value": "2.0.6",
+ "has-value": "1.0.0",
+ "isobject": "3.0.1",
+ "set-value": "2.0.0",
+ "to-object-path": "0.3.0",
+ "union-value": "1.0.0",
+ "unset-value": "1.0.0"
+ }
+ },
+ "camelcase": {
+ "version": "5.3.1",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
+ "integrity": "sha1-48mzFWnhBoEd8kL3FXJaH0xJQyA="
+ },
"caseless": {
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
"integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw="
},
+ "chai": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/chai/-/chai-4.2.0.tgz",
+ "integrity": "sha1-dgqnLPION5XoSxKHfODoNzeqKeU=",
+ "requires": {
+ "assertion-error": "1.1.0",
+ "check-error": "1.0.2",
+ "deep-eql": "3.0.1",
+ "get-func-name": "2.0.0",
+ "pathval": "1.1.0",
+ "type-detect": "4.0.8"
+ }
+ },
+ "chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha1-zUJUFnelQzPPVBpJEIwUMrRMlCQ=",
+ "requires": {
+ "ansi-styles": "3.2.1",
+ "escape-string-regexp": "1.0.5",
+ "supports-color": "5.5.0"
+ },
+ "dependencies": {
+ "supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha1-4uaaRKyHcveKHsCzW2id9lMO/I8=",
+ "requires": {
+ "has-flag": "3.0.0"
+ }
+ }
+ }
+ },
+ "check-error": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz",
+ "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII="
+ },
+ "class-utils": {
+ "version": "0.3.6",
+ "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz",
+ "integrity": "sha1-+TNprouafOAv1B+q0MqDAzGQxGM=",
+ "requires": {
+ "arr-union": "3.1.0",
+ "define-property": "0.2.5",
+ "isobject": "3.0.1",
+ "static-extend": "0.1.2"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+ "requires": {
+ "is-descriptor": "0.1.6"
+ }
+ }
+ }
+ },
+ "cliui": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz",
+ "integrity": "sha1-NIQi2+gtgAswIu709qwQvy5NG0k=",
+ "requires": {
+ "string-width": "2.1.1",
+ "strip-ansi": "4.0.0",
+ "wrap-ansi": "2.1.0"
+ }
+ },
"co": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
"integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ="
},
+ "code-point-at": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
+ "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c="
+ },
+ "collection-visit": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz",
+ "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=",
+ "requires": {
+ "map-visit": "1.0.0",
+ "object-visit": "1.0.1"
+ }
+ },
"color": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/color/-/color-3.0.0.tgz",
@@ -304,11 +591,50 @@
"delayed-stream": "1.0.0"
}
},
+ "component-emitter": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz",
+ "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY="
+ },
+ "concat-map": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
+ },
+ "cookiejar": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.2.tgz",
+ "integrity": "sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA=="
+ },
+ "copy-descriptor": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz",
+ "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40="
+ },
"core-util-is": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
},
+ "cross-spawn": {
+ "version": "6.0.5",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
+ "integrity": "sha1-Sl7Hxk364iw6FBJNus3uhG2Ay8Q=",
+ "requires": {
+ "nice-try": "1.0.5",
+ "path-key": "2.0.1",
+ "semver": "5.7.0",
+ "shebang-command": "1.2.0",
+ "which": "1.3.1"
+ },
+ "dependencies": {
+ "semver": {
+ "version": "5.7.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz",
+ "integrity": "sha1-eQp89v6lRZuslhELKbYEEtyP+Ws="
+ }
+ }
+ },
"dashdash": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
@@ -325,11 +651,79 @@
"ms": "2.0.0"
}
},
+ "decamelize": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
+ "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA="
+ },
+ "decode-uri-component": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
+ "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU="
+ },
+ "deep-eql": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz",
+ "integrity": "sha1-38lARACtHI/gI+faHfHBR8S0RN8=",
+ "requires": {
+ "type-detect": "4.0.8"
+ }
+ },
+ "define-properties": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz",
+ "integrity": "sha1-z4jabL7ib+bbcJT2HYcMvYTO6fE=",
+ "requires": {
+ "object-keys": "1.1.0"
+ }
+ },
+ "define-property": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz",
+ "integrity": "sha1-1Flono1lS6d+AqgX+HENcCyxbp0=",
+ "requires": {
+ "is-descriptor": "1.0.2",
+ "isobject": "3.0.1"
+ },
+ "dependencies": {
+ "is-accessor-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+ "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=",
+ "requires": {
+ "kind-of": "6.0.2"
+ }
+ },
+ "is-data-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+ "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=",
+ "requires": {
+ "kind-of": "6.0.2"
+ }
+ },
+ "is-descriptor": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+ "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=",
+ "requires": {
+ "is-accessor-descriptor": "1.0.0",
+ "is-data-descriptor": "1.0.0",
+ "kind-of": "6.0.2"
+ }
+ }
+ }
+ },
"delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
},
+ "detect-file": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz",
+ "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc="
+ },
"diagnostics": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/diagnostics/-/diagnostics-1.1.1.tgz",
@@ -340,6 +734,11 @@
"kuler": "1.0.1"
}
},
+ "diff": {
+ "version": "3.5.0",
+ "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz",
+ "integrity": "sha1-gAwN0eCov7yVg1wgKtIg/jF+WhI="
+ },
"dotenv": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-6.2.0.tgz",
@@ -371,12 +770,12 @@
"env-variable": "0.0.5"
}
},
- "encoding": {
- "version": "0.1.12",
- "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz",
- "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=",
+ "end-of-stream": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz",
+ "integrity": "sha1-7SljTRm6ukY7bOa4CjchPqtx7EM=",
"requires": {
- "iconv-lite": "0.4.24"
+ "once": "1.4.0"
}
},
"env-variable": {
@@ -384,11 +783,184 @@
"resolved": "https://registry.npmjs.org/env-variable/-/env-variable-0.0.5.tgz",
"integrity": "sha512-zoB603vQReOFvTg5xMl9I1P2PnHsHQQKTEowsKKD7nseUfJq6UWzK+4YtlWUO1nhiQUxe6XMkk+JleSZD1NZFA=="
},
+ "es-abstract": {
+ "version": "1.13.0",
+ "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.13.0.tgz",
+ "integrity": "sha1-rIYUX91QmdjdSVWMy6Lq+biOJOk=",
+ "requires": {
+ "es-to-primitive": "1.2.0",
+ "function-bind": "1.1.1",
+ "has": "1.0.3",
+ "is-callable": "1.1.4",
+ "is-regex": "1.0.4",
+ "object-keys": "1.1.0"
+ }
+ },
+ "es-to-primitive": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz",
+ "integrity": "sha1-7fckeAM0VujdqO8J4ArZZQcH83c=",
+ "requires": {
+ "is-callable": "1.1.4",
+ "is-date-object": "1.0.1",
+ "is-symbol": "1.0.2"
+ }
+ },
+ "escape-string-regexp": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+ "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
+ },
+ "esprima": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
+ "integrity": "sha1-E7BM2z5sXRnfkatph6hpVhmwqnE="
+ },
+ "execa": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz",
+ "integrity": "sha1-xiNqW7TfbW8V6I5/AXeYIWdJ3dg=",
+ "requires": {
+ "cross-spawn": "6.0.5",
+ "get-stream": "4.1.0",
+ "is-stream": "1.1.0",
+ "npm-run-path": "2.0.2",
+ "p-finally": "1.0.0",
+ "signal-exit": "3.0.2",
+ "strip-eof": "1.0.0"
+ }
+ },
+ "expand-brackets": {
+ "version": "2.1.4",
+ "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz",
+ "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=",
+ "requires": {
+ "debug": "2.6.9",
+ "define-property": "0.2.5",
+ "extend-shallow": "2.0.1",
+ "posix-character-classes": "0.1.1",
+ "regex-not": "1.0.2",
+ "snapdragon": "0.8.2",
+ "to-regex": "3.0.2"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=",
+ "requires": {
+ "ms": "2.0.0"
+ }
+ },
+ "define-property": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+ "requires": {
+ "is-descriptor": "0.1.6"
+ }
+ },
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "requires": {
+ "is-extendable": "0.1.1"
+ }
+ }
+ }
+ },
+ "expand-tilde": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz",
+ "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=",
+ "requires": {
+ "homedir-polyfill": "1.0.3"
+ }
+ },
"extend": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
"integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
},
+ "extend-shallow": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz",
+ "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=",
+ "requires": {
+ "assign-symbols": "1.0.0",
+ "is-extendable": "1.0.1"
+ },
+ "dependencies": {
+ "is-extendable": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
+ "integrity": "sha1-p0cPnkJnM9gb2B4RVSZOOjUHyrQ=",
+ "requires": {
+ "is-plain-object": "2.0.4"
+ }
+ }
+ }
+ },
+ "extglob": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz",
+ "integrity": "sha1-rQD+TcYSqSMuhxhxHcXLWrAoVUM=",
+ "requires": {
+ "array-unique": "0.3.2",
+ "define-property": "1.0.0",
+ "expand-brackets": "2.1.4",
+ "extend-shallow": "2.0.1",
+ "fragment-cache": "0.2.1",
+ "regex-not": "1.0.2",
+ "snapdragon": "0.8.2",
+ "to-regex": "3.0.2"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
+ "requires": {
+ "is-descriptor": "1.0.2"
+ }
+ },
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "requires": {
+ "is-extendable": "0.1.1"
+ }
+ },
+ "is-accessor-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+ "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=",
+ "requires": {
+ "kind-of": "6.0.2"
+ }
+ },
+ "is-data-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+ "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=",
+ "requires": {
+ "kind-of": "6.0.2"
+ }
+ },
+ "is-descriptor": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+ "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=",
+ "requires": {
+ "is-accessor-descriptor": "1.0.0",
+ "is-data-descriptor": "1.0.0",
+ "kind-of": "6.0.2"
+ }
+ }
+ }
+ },
"extsprintf": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
@@ -419,6 +991,61 @@
"resolved": "https://registry.npmjs.org/fecha/-/fecha-2.3.3.tgz",
"integrity": "sha512-lUGBnIamTAwk4znq5BcqsDaxSmZ9nDVJaij6NvRt/Tg4R69gERA+otPKbS86ROw9nxVMw2/mp1fnaiWqbs6Sdg=="
},
+ "fill-range": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
+ "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=",
+ "requires": {
+ "extend-shallow": "2.0.1",
+ "is-number": "3.0.0",
+ "repeat-string": "1.6.1",
+ "to-regex-range": "2.1.1"
+ },
+ "dependencies": {
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "requires": {
+ "is-extendable": "0.1.1"
+ }
+ }
+ }
+ },
+ "find-up": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
+ "integrity": "sha1-SRafHXmTQwZG2mHsxa41XCHJe3M=",
+ "requires": {
+ "locate-path": "3.0.0"
+ }
+ },
+ "findup-sync": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-2.0.0.tgz",
+ "integrity": "sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw=",
+ "requires": {
+ "detect-file": "1.0.0",
+ "is-glob": "3.1.0",
+ "micromatch": "3.1.10",
+ "resolve-dir": "1.0.1"
+ }
+ },
+ "flat": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.0.tgz",
+ "integrity": "sha1-CQvsiwXjnLowl0fx1YjwTbr5jbI=",
+ "requires": {
+ "is-buffer": "2.0.3"
+ },
+ "dependencies": {
+ "is-buffer": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.3.tgz",
+ "integrity": "sha1-Ts8/z3ScvR5HJonhCaxmJhol5yU="
+ }
+ }
+ },
"follow-redirects": {
"version": "1.6.1",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.6.1.tgz",
@@ -427,6 +1054,11 @@
"debug": "3.1.0"
}
},
+ "for-in": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
+ "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA="
+ },
"forever-agent": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
@@ -452,6 +1084,52 @@
}
}
},
+ "formidable": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.2.1.tgz",
+ "integrity": "sha512-Fs9VRguL0gqGHkXS5GQiMCr1VhZBxz0JnJs4JmMp/2jL18Fmbzvv7vOFRU+U8TBkHEE/CX1qDXzJplVULgsLeg=="
+ },
+ "fragment-cache": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz",
+ "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=",
+ "requires": {
+ "map-cache": "0.2.2"
+ }
+ },
+ "fs.realpath": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
+ },
+ "function-bind": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
+ "integrity": "sha1-pWiZ0+o8m6uHS7l3O3xe3pL0iV0="
+ },
+ "get-caller-file": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz",
+ "integrity": "sha1-+Xj6TJDR3+f/LWvtoqUV5xO9z0o="
+ },
+ "get-func-name": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz",
+ "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE="
+ },
+ "get-stream": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz",
+ "integrity": "sha1-wbJVV189wh1Zv8ec09K0axw6VLU=",
+ "requires": {
+ "pump": "3.0.0"
+ }
+ },
+ "get-value": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz",
+ "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg="
+ },
"getpass": {
"version": "0.1.7",
"resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
@@ -460,6 +1138,41 @@
"assert-plus": "1.0.0"
}
},
+ "glob": {
+ "version": "7.1.3",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz",
+ "integrity": "sha1-OWCDLT8VdBCDQtr9OmezMsCWnfE=",
+ "requires": {
+ "fs.realpath": "1.0.0",
+ "inflight": "1.0.6",
+ "inherits": "2.0.1",
+ "minimatch": "3.0.4",
+ "once": "1.4.0",
+ "path-is-absolute": "1.0.1"
+ }
+ },
+ "global-modules": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz",
+ "integrity": "sha1-bXcPDrUjrHgWTXK15xqIdyZcw+o=",
+ "requires": {
+ "global-prefix": "1.0.2",
+ "is-windows": "1.0.2",
+ "resolve-dir": "1.0.1"
+ }
+ },
+ "global-prefix": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz",
+ "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=",
+ "requires": {
+ "expand-tilde": "2.0.2",
+ "homedir-polyfill": "1.0.3",
+ "ini": "1.3.5",
+ "is-windows": "1.0.2",
+ "which": "1.3.1"
+ }
+ },
"graphql": {
"version": "14.0.2",
"resolved": "https://registry.npmjs.org/graphql/-/graphql-14.0.2.tgz",
@@ -476,19 +1189,16 @@
"apollo-utilities": "1.0.21"
}
},
- "graphql-client": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/graphql-client/-/graphql-client-2.0.1.tgz",
- "integrity": "sha512-XXdjUD3mwsBDcUB7g+iXQeRt+3gmIbvA/Yx1nE5aq2RQmaJwiH4hEoYw27AW8cDR90pCrPlHJAb1jJq3zUMbZA==",
- "requires": {
- "isomorphic-fetch": "2.2.1"
- }
- },
"graphql-tag": {
"version": "2.10.0",
"resolved": "https://registry.npmjs.org/graphql-tag/-/graphql-tag-2.10.0.tgz",
"integrity": "sha512-9FD6cw976TLLf9WYIUPCaaTpniawIjHWZSwIRZSjrfufJamcXbVVYfN2TWvJYbw0Xf2JjYbl1/f2+wDnBVw3/w=="
},
+ "growl": {
+ "version": "1.10.5",
+ "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz",
+ "integrity": "sha1-8nNdwig2dPpnR4sQGBBZNVw2nl4="
+ },
"har-schema": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
@@ -503,6 +1213,53 @@
"har-schema": "2.0.0"
}
},
+ "has": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
+ "integrity": "sha1-ci18v8H2qoJB8W3YFOAR4fQeh5Y=",
+ "requires": {
+ "function-bind": "1.1.1"
+ }
+ },
+ "has-flag": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+ "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0="
+ },
+ "has-symbols": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz",
+ "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q="
+ },
+ "has-value": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz",
+ "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=",
+ "requires": {
+ "get-value": "2.0.6",
+ "has-values": "1.0.0",
+ "isobject": "3.0.1"
+ }
+ },
+ "has-values": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz",
+ "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=",
+ "requires": {
+ "is-number": "3.0.0",
+ "kind-of": "4.0.0"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz",
+ "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=",
+ "requires": {
+ "is-buffer": "1.1.6"
+ }
+ }
+ }
+ },
"hash-base": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz",
@@ -512,6 +1269,19 @@
"safe-buffer": "5.1.2"
}
},
+ "he": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
+ "integrity": "sha1-hK5l+n6vsWX922FWauFLrwVmTw8="
+ },
+ "homedir-polyfill": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz",
+ "integrity": "sha1-dDKYzvTlrz4ZQWH7rcwhUdOgWOg=",
+ "requires": {
+ "parse-passwd": "1.0.0"
+ }
+ },
"http-signature": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
@@ -522,12 +1292,13 @@
"sshpk": "1.14.2"
}
},
- "iconv-lite": {
- "version": "0.4.24",
- "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
- "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+ "inflight": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+ "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
"requires": {
- "safer-buffer": "2.1.2"
+ "once": "1.4.0",
+ "wrappy": "1.0.2"
}
},
"inherits": {
@@ -535,6 +1306,34 @@
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz",
"integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE="
},
+ "ini": {
+ "version": "1.3.5",
+ "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
+ "integrity": "sha1-7uJfVtscnsYIXgwid4CD9Zar+Sc="
+ },
+ "invert-kv": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz",
+ "integrity": "sha1-c5P1r6Weyf9fZ6J2INEcIm4+7AI="
+ },
+ "is-accessor-descriptor": {
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
+ "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=",
+ "requires": {
+ "kind-of": "3.2.2"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "requires": {
+ "is-buffer": "1.1.6"
+ }
+ }
+ }
+ },
"is-arrayish": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz",
@@ -545,29 +1344,145 @@
"resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
"integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w=="
},
+ "is-callable": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz",
+ "integrity": "sha1-HhrfIZ4e62hNaR+dagX/DTCiTXU="
+ },
+ "is-data-descriptor": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
+ "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=",
+ "requires": {
+ "kind-of": "3.2.2"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "requires": {
+ "is-buffer": "1.1.6"
+ }
+ }
+ }
+ },
+ "is-date-object": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz",
+ "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY="
+ },
+ "is-descriptor": {
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
+ "integrity": "sha1-Nm2CQN3kh8pRgjsaufB6EKeCUco=",
+ "requires": {
+ "is-accessor-descriptor": "0.1.6",
+ "is-data-descriptor": "0.1.4",
+ "kind-of": "5.1.0"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
+ "integrity": "sha1-cpyR4thXt6QZofmqZWhcTDP1hF0="
+ }
+ }
+ },
+ "is-extendable": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
+ "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik="
+ },
+ "is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI="
+ },
+ "is-fullwidth-code-point": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
+ "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8="
+ },
+ "is-glob": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz",
+ "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=",
+ "requires": {
+ "is-extglob": "2.1.1"
+ }
+ },
+ "is-number": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
+ "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
+ "requires": {
+ "kind-of": "3.2.2"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "requires": {
+ "is-buffer": "1.1.6"
+ }
+ }
+ }
+ },
+ "is-plain-object": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
+ "integrity": "sha1-LBY7P6+xtgbZ0Xko8FwqHDjgdnc=",
+ "requires": {
+ "isobject": "3.0.1"
+ }
+ },
+ "is-regex": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz",
+ "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=",
+ "requires": {
+ "has": "1.0.3"
+ }
+ },
"is-stream": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
"integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ="
},
+ "is-symbol": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz",
+ "integrity": "sha1-oFX2rlcZLK7jKeeoYBGLSXqVDzg=",
+ "requires": {
+ "has-symbols": "1.0.0"
+ }
+ },
"is-typedarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
"integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo="
},
+ "is-windows": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz",
+ "integrity": "sha1-0YUOuXkezRjmGCzhKjDzlmNLsZ0="
+ },
"isarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
},
- "isomorphic-fetch": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz",
- "integrity": "sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=",
- "requires": {
- "node-fetch": "1.7.3",
- "whatwg-fetch": "3.0.0"
- }
+ "isexe": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA="
+ },
+ "isobject": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8="
},
"isstream": {
"version": "0.1.2",
@@ -579,6 +1494,15 @@
"resolved": "https://registry.npmjs.org/iterall/-/iterall-1.2.2.tgz",
"integrity": "sha512-yynBb1g+RFUPY64fTrFv7nsjRrENBQJaX2UL+2Szc9REFrSNm1rpSXHGzhmAy7a9uv3vlvgBlXnf9RqmPH1/DA=="
},
+ "js-yaml": {
+ "version": "3.12.0",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz",
+ "integrity": "sha1-6u1lbsg0TxD1J8a/obbiJE3hZ9E=",
+ "requires": {
+ "argparse": "1.0.10",
+ "esprima": "4.0.1"
+ }
+ },
"jsbn": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
@@ -666,6 +1590,11 @@
"safe-buffer": "5.1.2"
}
},
+ "kind-of": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
+ "integrity": "sha1-ARRrNqYhjmTljzqNZt5df8b20FE="
+ },
"kuler": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/kuler/-/kuler-1.0.1.tgz",
@@ -674,6 +1603,23 @@
"colornames": "1.1.1"
}
},
+ "lcid": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz",
+ "integrity": "sha1-bvXS32DlL4LrIopMNz6NHzlyU88=",
+ "requires": {
+ "invert-kv": "2.0.0"
+ }
+ },
+ "locate-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
+ "integrity": "sha1-2+w7OrdZdYBxtY/ln8QYca8hQA4=",
+ "requires": {
+ "p-locate": "3.0.0",
+ "path-exists": "3.0.0"
+ }
+ },
"lodash": {
"version": "4.17.11",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
@@ -714,6 +1660,14 @@
"resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
"integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w="
},
+ "log-symbols": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz",
+ "integrity": "sha1-V0Dhxdbw39pK2TI7UzIQfva0xAo=",
+ "requires": {
+ "chalk": "2.4.2"
+ }
+ },
"logform": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/logform/-/logform-1.10.0.tgz",
@@ -733,6 +1687,27 @@
}
}
},
+ "map-age-cleaner": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz",
+ "integrity": "sha1-fVg6cwZDTAVf5HSw9FB45uG0uSo=",
+ "requires": {
+ "p-defer": "1.0.0"
+ }
+ },
+ "map-cache": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz",
+ "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8="
+ },
+ "map-visit": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz",
+ "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=",
+ "requires": {
+ "object-visit": "1.0.1"
+ }
+ },
"md5.js": {
"version": "1.3.4",
"resolved": "http://registry.npmjs.org/md5.js/-/md5.js-1.3.4.tgz",
@@ -742,6 +1717,46 @@
"inherits": "2.0.1"
}
},
+ "mem": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz",
+ "integrity": "sha1-Rhr0l7xK4JYIzbLmDu+2m/90QXg=",
+ "requires": {
+ "map-age-cleaner": "0.1.3",
+ "mimic-fn": "2.1.0",
+ "p-is-promise": "2.0.0"
+ }
+ },
+ "methods": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
+ "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4="
+ },
+ "micromatch": {
+ "version": "3.1.10",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
+ "integrity": "sha1-cIWbyVyYQJUvNZoGij/En57PrCM=",
+ "requires": {
+ "arr-diff": "4.0.0",
+ "array-unique": "0.3.2",
+ "braces": "2.3.2",
+ "define-property": "2.0.2",
+ "extend-shallow": "3.0.2",
+ "extglob": "2.0.4",
+ "fragment-cache": "0.2.1",
+ "kind-of": "6.0.2",
+ "nanomatch": "1.2.13",
+ "object.pick": "1.3.0",
+ "regex-not": "1.0.2",
+ "snapdragon": "0.8.2",
+ "to-regex": "3.0.2"
+ }
+ },
+ "mime": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.0.tgz",
+ "integrity": "sha512-ikBcWwyqXQSHKtciCcctu9YfPbFYZ4+gbHEmE0Q8jzcTYQg5dHCr3g2wwAZjPoJfQVXZq6KXAjpXOTf5/cjT7w=="
+ },
"mime-db": {
"version": "1.36.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.36.0.tgz",
@@ -755,18 +1770,130 @@
"mime-db": "1.36.0"
}
},
+ "mimic-fn": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
+ "integrity": "sha1-ftLCzMyvhNP/y3pptXcR/CCDQBs="
+ },
+ "minimatch": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
+ "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=",
+ "requires": {
+ "brace-expansion": "1.1.11"
+ }
+ },
+ "minimist": {
+ "version": "0.0.8",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
+ "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
+ },
+ "mixin-deep": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz",
+ "integrity": "sha1-pJ5yaNzhoNlpjkUybFYm3zVD0P4=",
+ "requires": {
+ "for-in": "1.0.2",
+ "is-extendable": "1.0.1"
+ },
+ "dependencies": {
+ "is-extendable": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
+ "integrity": "sha1-p0cPnkJnM9gb2B4RVSZOOjUHyrQ=",
+ "requires": {
+ "is-plain-object": "2.0.4"
+ }
+ }
+ }
+ },
+ "mkdirp": {
+ "version": "0.5.1",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
+ "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
+ "requires": {
+ "minimist": "0.0.8"
+ }
+ },
+ "mocha": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/mocha/-/mocha-6.0.2.tgz",
+ "integrity": "sha1-zcGm/fZkcsB5tWBbrFnSmAdwLSw=",
+ "requires": {
+ "ansi-colors": "3.2.3",
+ "browser-stdout": "1.3.1",
+ "debug": "3.2.6",
+ "diff": "3.5.0",
+ "escape-string-regexp": "1.0.5",
+ "findup-sync": "2.0.0",
+ "glob": "7.1.3",
+ "growl": "1.10.5",
+ "he": "1.2.0",
+ "js-yaml": "3.12.0",
+ "log-symbols": "2.2.0",
+ "minimatch": "3.0.4",
+ "mkdirp": "0.5.1",
+ "ms": "2.1.1",
+ "node-environment-flags": "1.0.4",
+ "object.assign": "4.1.0",
+ "strip-json-comments": "2.0.1",
+ "supports-color": "6.0.0",
+ "which": "1.3.1",
+ "wide-align": "1.1.3",
+ "yargs": "12.0.5",
+ "yargs-parser": "11.1.1",
+ "yargs-unparser": "1.5.0"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "3.2.6",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
+ "integrity": "sha1-6D0X3hbYp++3cX7b5fsQE17uYps=",
+ "requires": {
+ "ms": "2.1.1"
+ }
+ },
+ "ms": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
+ "integrity": "sha1-MKWGTrPrsKZvLr5tcnrwagnYbgo="
+ }
+ }
+ },
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
},
- "node-fetch": {
- "version": "1.7.3",
- "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz",
- "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==",
+ "nanomatch": {
+ "version": "1.2.13",
+ "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz",
+ "integrity": "sha1-uHqKpPwN6P5r6IiVs4mD/yZb0Rk=",
"requires": {
- "encoding": "0.1.12",
- "is-stream": "1.1.0"
+ "arr-diff": "4.0.0",
+ "array-unique": "0.3.2",
+ "define-property": "2.0.2",
+ "extend-shallow": "3.0.2",
+ "fragment-cache": "0.2.1",
+ "is-windows": "1.0.2",
+ "kind-of": "6.0.2",
+ "object.pick": "1.3.0",
+ "regex-not": "1.0.2",
+ "snapdragon": "0.8.2",
+ "to-regex": "3.0.2"
+ }
+ },
+ "nice-try": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
+ "integrity": "sha1-ozeKdpbOfSI+iPybdkvX7xCJ42Y="
+ },
+ "node-environment-flags": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.4.tgz",
+ "integrity": "sha1-C3hKZVFCa/wW07IghCTcvCsv8Dg=",
+ "requires": {
+ "object.getownpropertydescriptors": "2.0.3"
}
},
"nodemailer": {
@@ -779,21 +1906,192 @@
"resolved": "https://registry.npmjs.org/nonce/-/nonce-1.0.4.tgz",
"integrity": "sha1-7nMCrejBvvR28wG4yR9cxRpIdhI="
},
+ "npm-run-path": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz",
+ "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=",
+ "requires": {
+ "path-key": "2.0.1"
+ }
+ },
+ "number-is-nan": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
+ "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0="
+ },
"oauth-sign": {
"version": "0.9.0",
"resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
"integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ=="
},
+ "object-copy": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz",
+ "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=",
+ "requires": {
+ "copy-descriptor": "0.1.1",
+ "define-property": "0.2.5",
+ "kind-of": "3.2.2"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+ "requires": {
+ "is-descriptor": "0.1.6"
+ }
+ },
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "requires": {
+ "is-buffer": "1.1.6"
+ }
+ }
+ }
+ },
+ "object-keys": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.0.tgz",
+ "integrity": "sha1-Eb0iNI3S4JagRasG9shbzDQPoDI="
+ },
+ "object-visit": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz",
+ "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=",
+ "requires": {
+ "isobject": "3.0.1"
+ }
+ },
+ "object.assign": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz",
+ "integrity": "sha1-lovxEA15Vrs8oIbwBvhGs7xACNo=",
+ "requires": {
+ "define-properties": "1.1.3",
+ "function-bind": "1.1.1",
+ "has-symbols": "1.0.0",
+ "object-keys": "1.1.0"
+ }
+ },
+ "object.getownpropertydescriptors": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz",
+ "integrity": "sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY=",
+ "requires": {
+ "define-properties": "1.1.3",
+ "es-abstract": "1.13.0"
+ }
+ },
+ "object.pick": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz",
+ "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=",
+ "requires": {
+ "isobject": "3.0.1"
+ }
+ },
+ "once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
+ "requires": {
+ "wrappy": "1.0.2"
+ }
+ },
"one-time": {
"version": "0.0.4",
"resolved": "https://registry.npmjs.org/one-time/-/one-time-0.0.4.tgz",
"integrity": "sha1-+M33eISCb+Tf+T46nMN7HkSAdC4="
},
+ "os-locale": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz",
+ "integrity": "sha1-qAKm7hfyTBBIOrmTVxnO9O0Wvxo=",
+ "requires": {
+ "execa": "1.0.0",
+ "lcid": "2.0.0",
+ "mem": "4.3.0"
+ }
+ },
+ "p-defer": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz",
+ "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww="
+ },
+ "p-finally": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz",
+ "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4="
+ },
+ "p-is-promise": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.0.0.tgz",
+ "integrity": "sha1-dVTj1XIQmofh8/U/an2F0bGU9MU="
+ },
+ "p-limit": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz",
+ "integrity": "sha1-QXyZQeYCepq8ulCS3SkE4lW1+8I=",
+ "requires": {
+ "p-try": "2.2.0"
+ }
+ },
+ "p-locate": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
+ "integrity": "sha1-Mi1poFwCZLJZl9n0DNiokasAZKQ=",
+ "requires": {
+ "p-limit": "2.2.0"
+ }
+ },
+ "p-try": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
+ "integrity": "sha1-yyhoVA4xPWHeWPr741zpAE1VQOY="
+ },
+ "parse-passwd": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz",
+ "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY="
+ },
+ "pascalcase": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz",
+ "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ="
+ },
+ "path-exists": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
+ "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU="
+ },
+ "path-is-absolute": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+ "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
+ },
+ "path-key": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
+ "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A="
+ },
+ "pathval": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz",
+ "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA="
+ },
"performance-now": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
"integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns="
},
+ "posix-character-classes": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz",
+ "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs="
+ },
"process-nextick-args": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz",
@@ -804,6 +2102,15 @@
"resolved": "https://registry.npmjs.org/psl/-/psl-1.1.29.tgz",
"integrity": "sha512-AeUmQ0oLN02flVHXWh9sSJF7mcdFq0ppid/JkErufc3hGIV/AMa8Fo9VgDo/cT2jFdOWoFvHp90qqBH54W+gjQ=="
},
+ "pump": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
+ "integrity": "sha1-tKIRaBW94vTh6mAjVOjHVWUQemQ=",
+ "requires": {
+ "end-of-stream": "1.4.1",
+ "once": "1.4.0"
+ }
+ },
"punycode": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
@@ -832,6 +2139,25 @@
"util-deprecate": "1.0.2"
}
},
+ "regex-not": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz",
+ "integrity": "sha1-H07OJ+ALC2XgJHpoEOaoXYOldSw=",
+ "requires": {
+ "extend-shallow": "3.0.2",
+ "safe-regex": "1.1.0"
+ }
+ },
+ "repeat-element": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz",
+ "integrity": "sha1-eC4NglwMWjuzlzH4Tv7mt0Lmsc4="
+ },
+ "repeat-string": {
+ "version": "1.6.1",
+ "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz",
+ "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc="
+ },
"request": {
"version": "2.88.0",
"resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz",
@@ -859,6 +2185,35 @@
"uuid": "3.3.2"
}
},
+ "require-directory": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
+ "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I="
+ },
+ "require-main-filename": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz",
+ "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE="
+ },
+ "resolve-dir": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz",
+ "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=",
+ "requires": {
+ "expand-tilde": "2.0.2",
+ "global-modules": "1.0.0"
+ }
+ },
+ "resolve-url": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz",
+ "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo="
+ },
+ "ret": {
+ "version": "0.1.15",
+ "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz",
+ "integrity": "sha1-uKSCXVvbH8P29Twrwz+BOIaBx7w="
+ },
"retry": {
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz",
@@ -869,6 +2224,14 @@
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
},
+ "safe-regex": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz",
+ "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=",
+ "requires": {
+ "ret": "0.1.15"
+ }
+ },
"safer-buffer": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
@@ -879,6 +2242,55 @@
"resolved": "http://registry.npmjs.org/sax/-/sax-0.5.8.tgz",
"integrity": "sha1-1HLbIo6zMcJQaw6MFVJK25OdEsE="
},
+ "semver": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.0.0.tgz",
+ "integrity": "sha512-0UewU+9rFapKFnlbirLi3byoOuhrSsli/z/ihNnvM24vgF+8sNBiI1LZPBSH9wJKUwaUbw+s3hToDLCXkrghrQ=="
+ },
+ "set-blocking": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
+ "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc="
+ },
+ "set-value": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz",
+ "integrity": "sha1-ca5KiPD+77v1LR6mBPP7MV67YnQ=",
+ "requires": {
+ "extend-shallow": "2.0.1",
+ "is-extendable": "0.1.1",
+ "is-plain-object": "2.0.4",
+ "split-string": "3.1.0"
+ },
+ "dependencies": {
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "requires": {
+ "is-extendable": "0.1.1"
+ }
+ }
+ }
+ },
+ "shebang-command": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
+ "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=",
+ "requires": {
+ "shebang-regex": "1.0.0"
+ }
+ },
+ "shebang-regex": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
+ "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM="
+ },
+ "signal-exit": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
+ "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0="
+ },
"simple-swizzle": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
@@ -887,6 +2299,146 @@
"is-arrayish": "0.3.2"
}
},
+ "snapdragon": {
+ "version": "0.8.2",
+ "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz",
+ "integrity": "sha1-ZJIufFZbDhQgS6GqfWlkJ40lGC0=",
+ "requires": {
+ "base": "0.11.2",
+ "debug": "2.6.9",
+ "define-property": "0.2.5",
+ "extend-shallow": "2.0.1",
+ "map-cache": "0.2.2",
+ "source-map": "0.5.7",
+ "source-map-resolve": "0.5.2",
+ "use": "3.1.1"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=",
+ "requires": {
+ "ms": "2.0.0"
+ }
+ },
+ "define-property": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+ "requires": {
+ "is-descriptor": "0.1.6"
+ }
+ },
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "requires": {
+ "is-extendable": "0.1.1"
+ }
+ }
+ }
+ },
+ "snapdragon-node": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz",
+ "integrity": "sha1-bBdfhv8UvbByRWPo88GwIaKGhTs=",
+ "requires": {
+ "define-property": "1.0.0",
+ "isobject": "3.0.1",
+ "snapdragon-util": "3.0.1"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
+ "requires": {
+ "is-descriptor": "1.0.2"
+ }
+ },
+ "is-accessor-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+ "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=",
+ "requires": {
+ "kind-of": "6.0.2"
+ }
+ },
+ "is-data-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+ "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=",
+ "requires": {
+ "kind-of": "6.0.2"
+ }
+ },
+ "is-descriptor": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+ "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=",
+ "requires": {
+ "is-accessor-descriptor": "1.0.0",
+ "is-data-descriptor": "1.0.0",
+ "kind-of": "6.0.2"
+ }
+ }
+ }
+ },
+ "snapdragon-util": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz",
+ "integrity": "sha1-+VZHlIbyrNeXAGk/b3uAXkWrVuI=",
+ "requires": {
+ "kind-of": "3.2.2"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "requires": {
+ "is-buffer": "1.1.6"
+ }
+ }
+ }
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
+ },
+ "source-map-resolve": {
+ "version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz",
+ "integrity": "sha1-cuLMNAlVQ+Q7LGKyxMENSpBU8lk=",
+ "requires": {
+ "atob": "2.1.2",
+ "decode-uri-component": "0.2.0",
+ "resolve-url": "0.2.1",
+ "source-map-url": "0.4.0",
+ "urix": "0.1.0"
+ }
+ },
+ "source-map-url": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz",
+ "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM="
+ },
+ "split-string": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz",
+ "integrity": "sha1-fLCd2jqGWFcFxks5pkZgOGguj+I=",
+ "requires": {
+ "extend-shallow": "3.0.2"
+ }
+ },
+ "sprintf-js": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
+ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw="
+ },
"sshpk": {
"version": "1.14.2",
"resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.14.2.tgz",
@@ -908,11 +2460,135 @@
"resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz",
"integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA="
},
+ "static-extend": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz",
+ "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=",
+ "requires": {
+ "define-property": "0.2.5",
+ "object-copy": "0.1.0"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+ "requires": {
+ "is-descriptor": "0.1.6"
+ }
+ }
+ }
+ },
+ "string-width": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
+ "integrity": "sha1-q5Pyeo3BPSjKyBXEYhQ6bZASrp4=",
+ "requires": {
+ "is-fullwidth-code-point": "2.0.0",
+ "strip-ansi": "4.0.0"
+ }
+ },
"string_decoder": {
"version": "0.10.31",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
"integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ="
},
+ "strip-ansi": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
+ "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
+ "requires": {
+ "ansi-regex": "3.0.0"
+ }
+ },
+ "strip-eof": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz",
+ "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8="
+ },
+ "strip-json-comments": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
+ "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo="
+ },
+ "superagent": {
+ "version": "5.0.2",
+ "resolved": "https://registry.npmjs.org/superagent/-/superagent-5.0.2.tgz",
+ "integrity": "sha512-CqeqvwByDJuLwhcO6NOSuPatyQOIZX/TlvD5GJnXg5tzBTth2xQGZGdAZdo/kX+BtzvwJFX2IGGczTZgEIT7Wg==",
+ "requires": {
+ "component-emitter": "1.2.1",
+ "cookiejar": "2.1.2",
+ "debug": "4.1.1",
+ "form-data": "2.3.3",
+ "formidable": "1.2.1",
+ "methods": "1.1.2",
+ "mime": "2.4.0",
+ "qs": "6.7.0",
+ "readable-stream": "3.2.0",
+ "semver": "6.0.0"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
+ "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
+ "requires": {
+ "ms": "2.1.1"
+ }
+ },
+ "form-data": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
+ "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
+ "requires": {
+ "asynckit": "0.4.0",
+ "combined-stream": "1.0.7",
+ "mime-types": "2.1.20"
+ }
+ },
+ "inherits": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+ "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
+ },
+ "ms": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
+ "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
+ },
+ "qs": {
+ "version": "6.7.0",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
+ "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ=="
+ },
+ "readable-stream": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.2.0.tgz",
+ "integrity": "sha512-RV20kLjdmpZuTF1INEb9IA3L68Nmi+Ri7ppZqo78wj//Pn62fCoJyV9zalccNzDD/OuJpMG4f+pfMl8+L6QdGw==",
+ "requires": {
+ "inherits": "2.0.3",
+ "string_decoder": "1.2.0",
+ "util-deprecate": "1.0.2"
+ }
+ },
+ "string_decoder": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.2.0.tgz",
+ "integrity": "sha512-6YqyX6ZWEYguAxgZzHGL7SsCeGx3V2TtOTqZz1xSTSWnqsbWwbptafNyvf/ACquZUXV3DANr5BDIwNYe1mN42w==",
+ "requires": {
+ "safe-buffer": "5.1.2"
+ }
+ }
+ }
+ },
+ "supports-color": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz",
+ "integrity": "sha1-ds/nQs8fQbubHCmtAwaMBbTA5Ao=",
+ "requires": {
+ "has-flag": "3.0.0"
+ }
+ },
"symbol-observable": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz",
@@ -923,6 +2599,44 @@
"resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz",
"integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg=="
},
+ "to-object-path": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz",
+ "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=",
+ "requires": {
+ "kind-of": "3.2.2"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "requires": {
+ "is-buffer": "1.1.6"
+ }
+ }
+ }
+ },
+ "to-regex": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz",
+ "integrity": "sha1-E8/dmzNlUvMLUfM6iuG0Knp1mc4=",
+ "requires": {
+ "define-property": "2.0.2",
+ "extend-shallow": "3.0.2",
+ "regex-not": "1.0.2",
+ "safe-regex": "1.1.0"
+ }
+ },
+ "to-regex-range": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz",
+ "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=",
+ "requires": {
+ "is-number": "3.0.0",
+ "repeat-string": "1.6.1"
+ }
+ },
"tough-cookie": {
"version": "2.4.3",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz",
@@ -951,11 +2665,94 @@
"integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=",
"optional": true
},
+ "type-detect": {
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz",
+ "integrity": "sha1-dkb7XxiHHPu3dJ5pvTmmOI63RQw="
+ },
"underscore": {
"version": "1.9.1",
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.9.1.tgz",
"integrity": "sha512-5/4etnCkd9c8gwgowi5/om/mYO5ajCaOgdzj/oW+0eQV9WxKBDZw5+ycmKmeaTXjInS/W0BzpGLo2xR2aBwZdg=="
},
+ "union-value": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz",
+ "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=",
+ "requires": {
+ "arr-union": "3.1.0",
+ "get-value": "2.0.6",
+ "is-extendable": "0.1.1",
+ "set-value": "0.4.3"
+ },
+ "dependencies": {
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "requires": {
+ "is-extendable": "0.1.1"
+ }
+ },
+ "set-value": {
+ "version": "0.4.3",
+ "resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz",
+ "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=",
+ "requires": {
+ "extend-shallow": "2.0.1",
+ "is-extendable": "0.1.1",
+ "is-plain-object": "2.0.4",
+ "to-object-path": "0.3.0"
+ }
+ }
+ }
+ },
+ "unset-value": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz",
+ "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=",
+ "requires": {
+ "has-value": "0.3.1",
+ "isobject": "3.0.1"
+ },
+ "dependencies": {
+ "has-value": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz",
+ "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=",
+ "requires": {
+ "get-value": "2.0.6",
+ "has-values": "0.1.4",
+ "isobject": "2.1.0"
+ },
+ "dependencies": {
+ "isobject": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz",
+ "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=",
+ "requires": {
+ "isarray": "1.0.0"
+ }
+ }
+ }
+ },
+ "has-values": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz",
+ "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E="
+ }
+ }
+ },
+ "urix": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz",
+ "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI="
+ },
+ "use": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz",
+ "integrity": "sha1-1QyMrHmhn7wg8pEfVuuXP04QBw8="
+ },
"util": {
"version": "0.10.3",
"resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz",
@@ -989,10 +2786,26 @@
"extsprintf": "1.3.0"
}
},
- "whatwg-fetch": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.0.0.tgz",
- "integrity": "sha512-9GSJUgz1D4MfyKU7KRqwOjXCXTqWdFNvEr7eUBYchQiVc744mqK/MzXPNR2WsPkmkOa4ywfg8C2n8h+13Bey1Q=="
+ "which": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
+ "integrity": "sha1-pFBD1U9YBTFtqNYvn1CRjT2nCwo=",
+ "requires": {
+ "isexe": "2.0.0"
+ }
+ },
+ "which-module": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
+ "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho="
+ },
+ "wide-align": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz",
+ "integrity": "sha1-rgdOa9wMFKQx6ATmJFScYzsABFc=",
+ "requires": {
+ "string-width": "2.1.1"
+ }
},
"winston": {
"version": "3.1.0",
@@ -1087,6 +2900,53 @@
}
}
},
+ "wrap-ansi": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
+ "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=",
+ "requires": {
+ "string-width": "1.0.2",
+ "strip-ansi": "3.0.1"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+ "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
+ },
+ "is-fullwidth-code-point": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
+ "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
+ "requires": {
+ "number-is-nan": "1.0.1"
+ }
+ },
+ "string-width": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
+ "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
+ "requires": {
+ "code-point-at": "1.1.0",
+ "is-fullwidth-code-point": "1.0.0",
+ "strip-ansi": "3.0.1"
+ }
+ },
+ "strip-ansi": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+ "requires": {
+ "ansi-regex": "2.1.1"
+ }
+ }
+ }
+ },
+ "wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
+ },
"xml2js": {
"version": "0.2.8",
"resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.2.8.tgz",
@@ -1100,6 +2960,49 @@
"resolved": "http://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz",
"integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0="
},
+ "y18n": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz",
+ "integrity": "sha1-le+U+F7MgdAHwmThkKEg8KPIVms="
+ },
+ "yargs": {
+ "version": "12.0.5",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz",
+ "integrity": "sha1-BfWZe2CWR7ZPZrgeO0sQo2jnrRM=",
+ "requires": {
+ "cliui": "4.1.0",
+ "decamelize": "1.2.0",
+ "find-up": "3.0.0",
+ "get-caller-file": "1.0.3",
+ "os-locale": "3.1.0",
+ "require-directory": "2.1.1",
+ "require-main-filename": "1.0.1",
+ "set-blocking": "2.0.0",
+ "string-width": "2.1.1",
+ "which-module": "2.0.0",
+ "y18n": "4.0.0",
+ "yargs-parser": "11.1.1"
+ }
+ },
+ "yargs-parser": {
+ "version": "11.1.1",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-11.1.1.tgz",
+ "integrity": "sha1-h5oIZZc7yp9rq1y987HGfsfTvPQ=",
+ "requires": {
+ "camelcase": "5.3.1",
+ "decamelize": "1.2.0"
+ }
+ },
+ "yargs-unparser": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.5.0.tgz",
+ "integrity": "sha1-8rsqfoPLyHu5XI5XKCigbJrdbg0=",
+ "requires": {
+ "flat": "4.1.0",
+ "lodash": "4.17.11",
+ "yargs": "12.0.5"
+ }
+ },
"zen-observable": {
"version": "0.8.9",
"resolved": "https://registry.npmjs.org/zen-observable/-/zen-observable-0.8.9.tgz",
diff --git a/package.json b/package.json
index fa8757b2c..75de40d50 100644
--- a/package.json
+++ b/package.json
@@ -1,5 +1,5 @@
{
- "name": "AACloud",
+ "name": "@superalgos/clone-executor",
"version": "1.0.0",
"description": "",
"main": "Run.js",
@@ -9,20 +9,21 @@
"author": "Luis-Fernando-Molina",
"license": "ISC",
"dependencies": {
+ "@superalgos/exchangegateway": "0.0.1",
+ "@superalgos/mqservice": "0.0.12",
"apollo-boost": "^0.1.16",
- "app-root-path": "^2.1.0",
"assert": "^1.4.1",
"axios": "^0.18.0",
"azure-storage": "^2.8.2",
"dotenv": "^6.0.0",
"graphql": "^14.0.2",
- "graphql-client": "^2.0.1",
"jsonwebtoken": "^8.4.0",
"lodash": "^4.17.11",
"nodemailer": "^4.6.8",
"nonce": "^1.0.4",
"querystring": "^0.2.0",
"retry": "^0.12.0",
+ "superagent": "^5.0.2",
"underscore": "^1.9.1",
"winston": "^3.1.0"
}
diff --git a/this.config.json b/this.config.json
index d4a37b864..fa18a5c76 100644
--- a/this.config.json
+++ b/this.config.json
@@ -1,54 +1,10 @@
{
- "codeName": "AACloud",
+ "codeName": "clone-executor",
"version": {
"major": 1,
"minor": 1,
"patch": 0
},
- "executionList": [
- {
- "enabled": "false",
- "devTeam": "AAMasters",
- "bot": "AAMariam",
- "process": "Trading-Process",
- "repo": "AAMariam-Trading-Bot"
- },
- {
- "enabled": "false",
- "devTeam": "AAMasters",
- "bot": "AACharly",
- "process": "Poloniex-Live-Trades",
- "repo": "AACharly-Extraction-Bot"
- },
- {
- "enabled": "false",
- "devTeam": "AAMasters",
- "bot": "AACharly",
- "process": "Poloniex-Hole-Fixing",
- "repo": "AACharly-Extraction-Bot"
- },
- {
- "enabled": "false",
- "devTeam": "AAMasters",
- "bot": "AABruce",
- "process": "One-Min-Daily-Candles-Volumes",
- "repo": "AABruce-Indicator-Bot"
- },
- {
- "enabled": "false",
- "devTeam": "AAMasters",
- "bot": "AAOlivia",
- "process": "Multi-Period-Daily",
- "repo": "AAOlivia-Indicator-Bot"
- },
- {
- "enabled": "false",
- "devTeam": "AAMasters",
- "bot": "AAOlivia",
- "process": "Multi-Period-Market",
- "repo": "AAOlivia-Indicator-Bot"
- }
- ],
"stopGracefully": false,
"marketRateProvider": {
"devTeam": "AAMasters",
@@ -61,4 +17,4 @@
"dataSet": "One-Min",
"dataSetVersion": "dataSet.V1"
}
-}
\ No newline at end of file
+}
diff --git a/utils/auth.js b/utils/auth.js
index c7f0b8d87..be0145a1f 100644
--- a/utils/auth.js
+++ b/utils/auth.js
@@ -1,12 +1,9 @@
const axios = require('axios')
-const appRoot = require('app-root-path')
-const { logger } = require(`${appRoot}/utils/logger`)
exports.authenticate = async function () {
try {
if (!global.ACCESS_TOKEN) {
- logger.debug('authenticate -> Entering Function.')
const authBody = '{"client_id":"' + process.env.AUTH_CLIENT_ID
+ '","client_secret": "' + process.env.AUTH_CLIENT_SECRET
@@ -33,7 +30,6 @@ exports.authenticate = async function () {
return global.ACCESS_TOKEN
} catch (error) {
- logger.error('authenticate -> Error: ' + error.stack)
throw new Error('There has been an error on the authentication: ' + error)
}
}
\ No newline at end of file
diff --git a/utils/logger.js b/utils/logger.js
index 1cc942d0c..da3df770b 100644
--- a/utils/logger.js
+++ b/utils/logger.js
@@ -1,11 +1,10 @@
const winston = require('winston')
-const appRoot = require('app-root-path')
const util = require('util')
const options = {
file: {
level: 'info',
- filename: `${appRoot}/logs/app.log`,
+ filename: '../logs/app.log',
handleExceptions: true,
json: true,
maxsize: 5242880, // 5MB