diff --git a/.vs/AACloud/v15/.suo b/.vs/AACloud/v15/.suo index e9ba96e1d..3b5b7b810 100644 Binary files a/.vs/AACloud/v15/.suo and b/.vs/AACloud/v15/.suo differ diff --git a/Debug Log.js b/Debug Log.js index 827f6b47b..1f34c0a2e 100644 --- a/Debug Log.js +++ b/Debug Log.js @@ -11,6 +11,7 @@ let messageId = 0; let firstCall = true; let folderPath; + let loopCounter; let thisObject = { bot: undefined, @@ -50,16 +51,30 @@ catch (err) { console.log("Error trying to create the folders needed. Error: " + err.message); } + } + function createLoopFolder() { + try { + + folderPath = '../Logs/' + thisObject.bot.devTeam + "/" + thisObject.bot.type + "/" + thisObject.bot.codeName + "." + thisObject.bot.version.major + "." + thisObject.bot.version.minor + "/" + thisObject.bot.process + "/Loop." + loopCounter; + + createFolderSync(folderPath); + + } + catch (err) { + console.log("Error trying to create the loop folder needed. Error: " + err.message); + } } function write(Message) { - if (firstCall === true) { + if (firstCall === true) { createFolders();} - createFolders(); + if (global.loopCointer !== loopCounter) { + loopCounter = global.loopCointer; + createLoopFolder(); } let filePath = getCurrentLogFile(folderPath + "/" + dateString + "---" + randomId + "---", this.fileName); diff --git a/Dependencies.js b/Dependencies.js new file mode 100644 index 000000000..ae562375e --- /dev/null +++ b/Dependencies.js @@ -0,0 +1,140 @@ +exports.newDependencies = function newDependencies(BOT, DEBUG_MODULE, STATUS_REPORT, FILE_STORAGE, UTILITIES) { + + const FULL_LOG = true; + const LOG_FILE_CONTENT = false; + + const MODULE_NAME = "Dependencies"; + + let thisObject = { + statusReports: new Map(), + initialize: initialize + }; + + /* + + During the process we will create a new History Record. This will go to the Context History file which essentially mantains an + index of all the bots executions. This file will later be plotted by the bot s plotter on the timeline, allowing end users to + know where there is information related to the actions taken by the bot. + + */ + + let bot = BOT; + let ownerBot; // This is the bot owner of the Status Report. Only owners can save the report and override the existing content. + + const logger = DEBUG_MODULE.newDebugLog(); + logger.fileName = MODULE_NAME; + logger.bot = bot; + + return thisObject; + + function initialize(pDependenciesConfig, callBackFunction) { + + try { + + if (FULL_LOG === true) { logger.write("[INFO] initialize -> Entering function."); } + + /* + + For each dependency declared at the bot config, we will initialize the status report, and load it as part of this initialization process. + + */ + let alreadyCalledBack = false; + let loadCount = 0; + + for (let i = 0; i < pDependenciesConfig.length; i++) { + + let statusReportModule = STATUS_REPORT.newStatusReport(BOT, DEBUG_MODULE, FILE_STORAGE, UTILITIES); + + statusReportModule.initialize(pDependenciesConfig[i], onInitilized); + + function onInitilized(err) { + + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { + logger.write("[ERROR] initialize -> onInitilized -> err = " + err.message); + + if (alreadyCalledBack === false) { + callBackFunction(err); + } else { + alreadyCalledBack = true; + } + return; + } + + statusReportModule.load(onLoad); + } + + function onLoad(err) { + + try { + + switch (err.result) { + case global.DEFAULT_OK_RESPONSE.result: { + logger.write("[INFO] initialize -> onLoad -> Execution finished well. :-)"); + + addReport(); + return; + } + case global.CUSTOM_OK_RESPONSE.result: { // We need to see if we can handle this. + logger.write("[ERROR] initialize -> onLoad -> err.message = " + err.message); + + if (err.message === "Status Report was never created.") { + + logger.write("[ERROR] initialize -> onLoad -> err.message = " + err.message); + logger.write("[ERROR] initialize -> onLoad -> pDependenciesConfig[i] = " + JSON.stringify(pDependenciesConfig[i])); + addReport(); + return; + } else { + + logger.write("[WARN] initialize -> onLoad -> Response not understood."); + + if (alreadyCalledBack === false) { + callBackFunction(err); + } else { + alreadyCalledBack = true; + } + return; + } + + } + default: + { + logger.write("[ERROR] initialize -> onLoad -> Operation Failed."); + + if (alreadyCalledBack === false) { + callBackFunction(err); + } else { + alreadyCalledBack = true; + } + return; + } + } + } + catch (err) { + logger.write("[ERROR] initialize -> onLoad -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + function addReport() { + + loadCount++; + + let key = pDependenciesConfig[i].devTeam + "-" + pDependenciesConfig[i].bot + "-" + pDependenciesConfig[i].process + "-" + pDependenciesConfig[i].dataSetVersion; + + thisObject.statusReports.set(key, statusReportModule); + + if (loadCount === pDependenciesConfig.length) { + if (alreadyCalledBack === false) { + callBackFunction(global.DEFAULT_OK_RESPONSE); + } + } + } + } + + } catch (err) { + logger.write("[ERROR] initialize -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + +}; \ No newline at end of file diff --git a/Extraction Bot Main Loop.js b/Extraction Bot Main Loop.js index 6c11cfa21..a449645d9 100644 --- a/Extraction Bot Main Loop.js +++ b/Extraction Bot Main Loop.js @@ -55,6 +55,8 @@ function loop() { try { + global.loopCointer++; + if (FULL_LOG === true) { logger.write("[INFO] run -> loop -> Entering function."); } /* We define here all the modules that the rest of the infraestructure, including the bots themselves can consume. */ @@ -64,6 +66,7 @@ const DEBUG_MODULE = require(ROOT_DIR + 'Debug Log'); const STATUS_REPORT = require(ROOT_DIR + 'Status Report'); const POLONIEX_CLIENT_MODULE = require(ROOT_DIR + 'Poloniex API Client'); + const DEPENDENCIES = require(ROOT_DIR + 'Dependencies'); /* 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. */ @@ -71,11 +74,43 @@ /* We will prepare first the infraestructure needed for the bot to run. There are 3 modules we need to sucessfullly initialize first. */ + let dependencies; let userBot; let nextWaitTime; - initializeUserBot(); + initializeDependencies(); + + function initializeDependencies() { + + if (FULL_LOG === true) { logger.write("[INFO] run -> loop -> initializeDependencies -> Entering function."); } + + dependencies = DEPENDENCIES.newDependencies(bot, DEBUG_MODULE, STATUS_REPORT, FILE_STORAGE, UTILITIES); + + dependencies.initialize(processConfig.dependencies, onInizialized); + + function onInizialized(err) { + + switch (err.result) { + case global.DEFAULT_OK_RESPONSE.result: { + logger.write("[INFO] run -> loop -> initializeDependencies -> onInizialized > Execution finished well. :-)"); + initializeUserBot(); + 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("[ERROR] run -> loop -> initializeDependencies -> 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("[ERROR] run -> loop -> initializeDependencies -> onInizialized > Operation Failed. Aborting the process."); + callBackFunction(err); + return; + } + } + } + } function initializeUserBot() { @@ -83,7 +118,7 @@ usertBot = USER_BOT_MODULE.newUserBot(bot, COMMONS_MODULE, UTILITIES, DEBUG_MODULE, FILE_STORAGE, STATUS_REPORT, POLONIEX_CLIENT_MODULE); - usertBot.initialize(undefined, undefined, onInizialized); + usertBot.initialize(dependencies, onInizialized, undefined, undefined); function onInizialized(err) { @@ -93,20 +128,17 @@ startUserBot(); return; } - break; 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("[ERROR] run -> loop -> initializeUserBot -> onInizialized > Retry Later. Requesting Execution Retry."); nextWaitTime = 'Retry'; loopControl(nextWaitTime); return; } - break; case global.DEFAULT_FAIL_RESPONSE.result: { // This is an unexpected exception that we do not know how to handle. logger.write("[ERROR] run -> loop -> initializeUserBot -> onInizialized > Operation Failed. Aborting the process."); callBackFunction(err); return; } - break; } } } diff --git a/File Storage.js b/File Storage.js index a081f6f40..d35b1ee67 100644 --- a/File Storage.js +++ b/File Storage.js @@ -77,7 +77,7 @@ exports.newFileStorage = function newFileStorage(BOT) { try { let fs = require('fs'); - filePath = '../' + 'Connection-Strings' + '/' + global.RUNNING_MODE + '/' + dataOwner + '.azure.storage.connstring'; + filePath = '../' + 'Connection-Strings' + '/' + global.STORAGE_CONN_STRING_FOLDER + '/' + dataOwner + '.azure.storage.connstring'; let connObj = JSON.parse(fs.readFileSync(filePath, 'utf8')); callBack(global.DEFAULT_OK_RESPONSE, connObj); diff --git a/Indicator Bot Main Loop.js b/Indicator Bot Main Loop.js index a0c4ba208..282d4bdf0 100644 --- a/Indicator Bot Main Loop.js +++ b/Indicator Bot Main Loop.js @@ -55,6 +55,8 @@ function loop() { try { + global.loopCointer++; + if (FULL_LOG === true) { logger.write("[INFO] run -> loop -> Entering function."); } /* We define here all the modules that the rest of the infraestructure, including the bots themselves can consume. */ @@ -63,6 +65,7 @@ const FILE_STORAGE = require(ROOT_DIR + 'File Storage'); const DEBUG_MODULE = require(ROOT_DIR + 'Debug Log'); const STATUS_REPORT = require(ROOT_DIR + 'Status Report'); + const DEPENDENCIES = require(ROOT_DIR + 'Dependencies'); /* 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. */ @@ -74,15 +77,46 @@ let nextWaitTime; - initializeUserBot(); + initializeDependencies(); + + function initializeDependencies() { + + if (FULL_LOG === true) { logger.write("[INFO] run -> loop -> initializeDependencies -> Entering function."); } + + dependencies = DEPENDENCIES.newDependencies(bot, DEBUG_MODULE, STATUS_REPORT, FILE_STORAGE, UTILITIES); + + dependencies.initialize(processConfig.dependencies, onInizialized); + + function onInizialized(err) { + + switch (err.result) { + case global.DEFAULT_OK_RESPONSE.result: { + logger.write("[INFO] run -> loop -> initializeDependencies -> onInizialized > Execution finished well. :-)"); + initializeUserBot(); + 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("[ERROR] run -> loop -> initializeDependencies -> 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("[ERROR] run -> loop -> initializeDependencies -> onInizialized > Operation Failed. Aborting the process."); + callBackFunction(err); + return; + } + } + } + } function initializeUserBot() { if (FULL_LOG === true) { logger.write("[INFO] run -> loop -> initializeUserBot -> Entering function."); } - usertBot = USER_BOT_MODULE.newUserBot(bot, COMMONS_MODULE, UTILITIES, DEBUG_MODULE, FILE_STORAGE, STATUS_REPORT); + usertBot = USER_BOT_MODULE.newUserBot(bot, COMMONS_MODULE, UTILITIES, DEBUG_MODULE, FILE_STORAGE); - usertBot.initialize(undefined, undefined, onInizialized); + usertBot.initialize(dependencies, onInizialized, undefined, undefined); function onInizialized(err) { @@ -92,20 +126,17 @@ startUserBot(); return; } - break; 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("[ERROR] run -> loop -> initializeUserBot -> onInizialized > Retry Later. Requesting Execution Retry."); nextWaitTime = 'Retry'; loopControl(nextWaitTime); return; } - break; case global.DEFAULT_FAIL_RESPONSE.result: { // This is an unexpected exception that we do not know how to handle. logger.write("[ERROR] run -> loop -> initializeUserBot -> onInizialized > Operation Failed. Aborting the process."); callBackFunction(err); return; } - break; } } } @@ -125,20 +156,17 @@ loopControl(nextWaitTime); return; } - break; 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("[ERROR] run -> loop -> startUserBot -> onFinished > Retry Later. Requesting Execution Retry."); nextWaitTime = 'Retry'; loopControl(nextWaitTime); return; } - break; case global.DEFAULT_FAIL_RESPONSE.result: { // This is an unexpected exception that we do not know how to handle. logger.write("[ERROR] run -> loop -> startUserBot -> onFinished > Operation Failed. Aborting the process."); callBackFunction(err); return; } - break; } } } diff --git a/Project.njsproj b/Project.njsproj index 1e4cc3cba..566e4c4e7 100644 --- a/Project.njsproj +++ b/Project.njsproj @@ -13,7 +13,7 @@ 14.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) Project - Poloniex-Live-Trades + Multi-Period-Market C:\Program Files\nodejs\node.exe False @@ -23,6 +23,9 @@ Code + + Code + Code diff --git a/Run.js b/Run.js index 616bd6b7b..210c0fb0d 100644 --- a/Run.js +++ b/Run.js @@ -1,14 +1,6 @@  const FULL_LOG = true; -/* The following global variable tells the system if it is running on test mode or production. */ - -global.RUNNING_MODE = 'Testnet'; // 'Testnet', 'Mixed' or 'Production' - -/* You do not have funds at the exchange and still want run your bot? No problem activate the exchange simulation mode: */ - -global.EXCHANGE_SIMULATION_MODE = false; - /* First thing to do is to read the config and guess which bot we will be running. */ var fs = require('fs'); @@ -25,6 +17,14 @@ catch (err) { return; } +/* You do not have funds at the exchange and still want run your bot? No problem activate the exchange simulation mode: */ + +global.EXCHANGE_SIMULATION_MODE = JSON.parse(global.PLATFORM_CONFIG.exchangeSimulationMode); + +/* The following global variable tells the system if it is running on test mode or production. */ + +global.STORAGE_CONN_STRING_FOLDER = global.PLATFORM_CONFIG.storageConnStringFolder; // 'Testnet', 'Mixed' or 'Production', or whatever folder name the conn strings files are into. + /* Now we will read the config of the bot from the path we obtained on the VM config. */ let botConfig; @@ -144,6 +144,10 @@ global.dailyFilePeriods = JSON.parse(global.dailyFilePeriods); global.FILE_PATH_ROOT = 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; +/* Loop Counter */ + +global.loopCointer = 0; + /* Some LAGACY code starts here. Pending for clean up. */ const INTERVAL_EXECUTOR_MODULE = require('./Interval Executor'); diff --git a/Status Report.js b/Status Report.js index a813d2dc1..7868fe353 100644 --- a/Status Report.js +++ b/Status Report.js @@ -20,16 +20,8 @@ save: save }; - /* - - During the process we will create a new History Record. This will go to the Context History file which essentially mantains an - index of all the bots executions. This file will later be plotted by the bot s plotter on the timeline, allowing end users to - know where there is information related to the actions taken by the bot. - - */ - let bot = BOT; - let ownerBot; // This is the bot owner of the Status Report. Only owners can save the report and override the existing content. + let owner; // This is the bot owner of the Status Report. Only owners can save the report and override the existing content. const logger = DEBUG_MODULE.newDebugLog(); logger.fileName = MODULE_NAME; @@ -45,26 +37,21 @@ return thisObject; - function initialize(pOwnerBot, callBackFunction) { + function initialize(pOwner, callBackFunction) { try { + logger.fileName = MODULE_NAME + "." + pOwner.bot; + if (FULL_LOG === true) { logger.write("[INFO] initialize -> Entering function."); } - /* - - Here we get the positions the bot did and that are recorded at the bot storage account. We will use them through out the rest - of the process. - - */ - - ownerBot = pOwnerBot; + owner = pOwner; initializeStorage(); function initializeStorage() { - cloudStorage.initialize(bot.codeName, onInizialized); + cloudStorage.initialize(owner.bot, onInizialized); function onInizialized(err) { @@ -91,8 +78,9 @@ if (FULL_LOG === true) { logger.write("[INFO] initialize -> load -> Entering function."); } + let rootPath = owner.devTeam + "/" + owner.bot + "." + owner.botVersion.major + "." + owner.botVersion.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + owner.dataSetVersion; let fileName = "Status.Report.json" - let filePath = global.FILE_PATH_ROOT + "/Reports/" + bot.process; + let filePath = rootPath + "/Reports/" + owner.process; if (FULL_LOG === true) { logger.write("[INFO] initialize -> load -> fileName = " + fileName); } if (FULL_LOG === true) { logger.write("[INFO] initialize -> load -> filePath = " + filePath); } @@ -156,8 +144,8 @@ if (FULL_LOG === true) { logger.write("[INFO] save -> Entering function."); } - let ownerId = ownerBot.devTeam + "-" + ownerBot.codeName; - let botId = bot.devTeam + "-" + bot.codeName; + let ownerId = owner.devTeam + "-" + owner.bot + "-" + owner.botVersion.major + "-" + owner.botVersion.minor + "-" + owner.process + "-" + owner.dataSetVersion; + let botId = bot.devTeam + "-" + bot.codeName + "-" + bot.version.major + "-" + bot.version.minor + "-" + bot.process + "-" + bot.dataSetVersion; if (ownerId !== botId) { @@ -165,13 +153,13 @@ result: global.CUSTOM_FAIL_RESPONSE.result, message: "Only bots owners of a Status Report can save them." } - logger.write("[ERROR] save -> customErr = " + err.message); + logger.write("[ERROR] save -> customErr = " + customErr.message); callBackFunction(customErr); return; } let fileName = "Status.Report.json" - let filePath = global.FILE_PATH_ROOT + "/Reports/" + bot.process; + let filePath = global.FILE_PATH_ROOT + "/Reports/" + owner.process; if (FULL_LOG === true) { logger.write("[INFO] save -> fileName = " + fileName); } if (FULL_LOG === true) { logger.write("[INFO] save -> filePath = " + filePath); } diff --git a/Trading Bot Main Loop.js b/Trading Bot Main Loop.js index 92fa0f0e3..f737bc032 100644 --- a/Trading Bot Main Loop.js +++ b/Trading Bot Main Loop.js @@ -55,6 +55,8 @@ function loop() { try { + global.loopCointer++; + if (FULL_LOG === true) { logger.write("[INFO] run -> loop -> Entering function."); } /* We define here all the modules that the rest of the infraestructure, including the bots themselves can consume. */ diff --git a/this.config.json b/this.config.json index 5d0bc2469..2c07461f0 100644 --- a/this.config.json +++ b/this.config.json @@ -6,7 +6,9 @@ "patch": 0 }, "bot": { - "path": "../Bots/AAMasters/AACharly-Extraction-Bot" + "path": "../Bots/AAMasters/AAOlivia-Indicator-Bot" }, - "stopGracefully": "false" + "stopGracefully": "false", + "exchangeSimulationMode": "false", + "storageConnStringFolder": "Mixed" } \ No newline at end of file